- Posted by admin on September 29, 2007
"I didn't have time to write you a short letter, so I wrote you a long one" - Mark Twain
- Posted by admin on September 28, 2007
Zurzeit entwickeln wir eine Ausschreibungsplattform ähnlich zu MyHammer, für die Vermittlung von Druckaufträgen. Eine Ausschreibung nennen wir ein wenig unpräzise Auktion. Die derzeitige Herausforderung ist das Abbilden und der Test verschiedener Zustände sowohl für die UnitTests als auch für das Frontend. Hier ein (vereinfachtes) Zustandsdiagramm, das die Situation ein wenig verdeutlicht:
Wir haben also 5 Zustände und 8 Übergange (Transitions). Es fehlen noch einige Bedingungen (Guards) und in Real sind noch ein par mehr Übergänge möglich. Da die Anforderungen sich während der Entwicklung mit sehr hoher Wahrscheinlichkeit ändern werden, ist das Diagramm für also absolut ausreichend. Nun die Fragen:
- Wie lässt sich das schnell und einfach implementieren?
- Wie lässt sich das Ergebnis schnellst möglich im User Frontend testen, um eine Gefühl dafür zu bekommen was sinnvoll ist und was nicht.
Der erste Schrit ist die Implementierung, hier ein erster Ansatz:
Ganz klassisch bekommt jeder Zustand eine Klasse. Die Möglichen Übergänge werden dessen Methoden.
Fangen wir jedoch erstmal klein an bauen ein Enum für jeden Zustand.
public enum RequestState
{
Active,
ExpiredWithBids,
ExpiredNoBids,
Awarded,
ClosedSuccessful,
ClosedUnsuccessful
}
Es steht in Frage ob das Enum bis zum Ende der Implementierung überleben wird, aber wir gesagt, wir fangen klein an.
Im Nächsten Schritt möchten wir gerne Wissen, in welchem Zustand sich eine Auktion (im Quellcode und weiter Anfrage genannt) gerade befindet. Noch weiß die Anfrage nichts von Zuständen, also müssen wir von Aussen etnscheiden. Zunächst verantwortlich für den aktuellen Zustand wird die Klasse "RequestStateService":
public class RequestStateService
{
private Request _request;
public RequestStateService(Request request)
{
_request = request;
}
public RequestState GetState()
{
if (Active())
return RequestState.Active;
else if (ClosedUnseccessful())
return RequestState.ClosedUnsuccessful;
else if (ClosedSuccessful())
return RequestState.ClosedSuccessful;
else if (Awarded())
return RequestState.Awarded;
else if (ExpiredHavingBids())
return RequestState.ExpiredWithBids;
else if (ExpiredNoBids())
return RequestState.ExpiredNoBids;
throw new Exception("unknown state" + _request.Id);
}
...
Eine "RequestStateService" Instanz ist also immer zuständig für einen "Request".
Noch sind Methoden Stubs, die sich dank Resharper von selbst (ALT Enter) generiert haben.
...
private bool Active()
{
throw new NotImplementedException();
}
private bool ExpiredHavingBids()
{
throw new NotImplementedException();
}
private bool Awarded()
{
throw new NotImplementedException();
}
private bool ClosedSuccessful()
{
throw new NotImplementedException();
}
private bool ClosedUnseccessful()
{
throw new NotImplementedException();
}
private bool ExpiredNoBids()
{
throw new NotImplementedException();
}
}
Im nächsten Schritt müssen wir herausbekommen wie jeder Zustand definiert ist. Die Idee ist es den Zustand über die Eigenschaften eines "Request" Objekts in Erfahrung zu bringen. Der Einfachheit halber nähern wir uns dem Problem mit Kommentaren.
private bool Active()
{
//Not Closed
//Auction End Before Now
}
private bool ExpiredNoBids()
{
//Not Closed
//Auction End After Now
}
private bool ExpiredHavingBids()
{
//Not Closed
//Auction End After Now
//Has Bids
}
private bool Awarded()
{
//Not Closed
//Auction End After Now
//Has Award
}
private bool ClosedSuccessful()
{
//Is Closed
//Has Award
//May be better: Request knows his own state?
}
private bool ClosedUnseccessful()
{
//Is Closed
//Has No Award
//May be better: Request knows his own state?
}
Um das ganze übersichtlicher zu machen und ein wenig mehr Einblick in die Situation zu bekommen hier ein Klassendiagram eines Requests:
Ein Request enthält also mehrere Bids (Gebote). Ein Gebot ist aus dieser Sicht Teil eines Requests und ist daher aggregiert. Prinzipiell könnte man auch argumentieren, das ein Gebot auch für selbst existieren kann aber die Notation für Aggregation ist in UML (1.0;) irgendwie immer ein bisschen Geschmackssache, eine Assoziation wäre sicherlich auch Okay. Wobei die MDA Verfechter und Verwender sicherlich über die Art der Verknüpfung eine Aussage über die Implementierung treffen würden. Aber dieses Diagramm soll nur einen Überblick geben, also ist das was ein CodeGenerator aus dem Diagramm machen würde egal. Dazu kommt das Diagramm Tool Gliffy nicht ganz UML konform ist, aber einfach und schnell zu bedienen. U.a fehlen zum Beispiel Quantifier.
Hier nochmal ein alternatives Diagramm für das gleiche Thema.
Besser herausgestellt ist, dass ein Request (Anfrage) keinen oder einen Award (Zuschlag) hat.
Während Request und Bid ziemlich vollständig implementiert sind und es auch schon eine ziemlich umfangreiche Oberfläche dafür gibt, fehlt das Verteilen von Zuschlägen noch komplett. Hierfür müssen erstmal die Anforderungen erarbeitet werden, dazu noch das User Interface. Wenn das geschehen ist, geht es in ein, zwei Tagen weiter mit dieser Miniserie.
Abschliessend wie nach jedem Arbeitsschritt:
Alles Tests laufen lassen und erst dann weitermachen, wenn alles grün ist :-)
- Posted by admin on September 27, 2007
Ich habe vorhin eine neue Firmware Version unserer Fritz!Box eingespielt. Die neue Version hat eine überarbeitete Obefläche und ist jetzt noch übersichtlicher. Dazu gibt es einige neue Features wie zum Beispiel Schnellwahl, Sichern der Einstellungen und eine Anrufsperre zu Nachzeit, Wecker und mehr.
![CropperCapture[21]](http://speak-friend.com/images/speak-friend_com/andrej/WindowsLiveWriter/FritzBoxKundenbindung_4987/CropperCapture%5B21%5D_thumb.jpg)
Was sehr beeindruckt ist das AVM Software für ein Produkt (FRITZ!Box Fon WLAN 7050) aktualisiert, das es so nicht mehr zu kaufen ist. Viele der Verbesserungen sind auch nicht Lösungen für bestehende Probleme, sondern Erweiterungen für Funktionalität die weit über das Hinaus geht was ich von einem DSL, Router Modem erwarten würde. (Zum Beispiel als WLAN Repeater konfigurierbar.)
Ich verwende AVM Produkte nun schon seit 7 Jahren, angefangen mit einer ISDN Karte und war schon immer zufrieden, aber jetzt bin ich mir sicher das die nächste Erweiterung der Telefon und DSL Analge ein AVM Produkt werden soll.
![CropperCapture[23]](http://speak-friend.com/images/speak-friend_com/andrej/WindowsLiveWriter/FritzBoxKundenbindung_4987/CropperCapture%5B23%5D_thumb.jpg)
![CropperCapture[22]](http://speak-friend.com/images/speak-friend_com/andrej/WindowsLiveWriter/FritzBoxKundenbindung_4987/CropperCapture%5B22%5D_thumb.jpg)
Es ist wohl Psychologie 101 das ich begeistert bin von den Möglichkeiten, aber mir absolut klar ist, das wir keine der neuen (und die meistern der alten) Möglichkeiten nicht nutzen werden :-)
- Posted by admin on September 25, 2007
public RequestVisitedList GetBy(int userId, List<int> requestIds)
{
Disjunction disjunctionRequests = new Disjunction();
foreach (int requestId in requestIds)
disjunctionRequests.Add(
Expression.Eq("RequestId", requestId));
return new RequestVisitedList(
_session.CreateCriteria(typeof(RequestVisited))
.Add(Expression.Eq("UserId", userId))
.Add(disjunctionRequests)
.List<RequestVisited>()
);
}
Der Code oben gibt eine Liste von allen Aufrufen einer Anfrage für eine bestimmten Benutzer zurück, eigentlich nichts Besonderes. Das großartige ist, das das Ganze in 3 min geschrieben war. Keine Stored Procedures, keine Strings zusammen bauen, einfach nur mit IntelliSense bewaffnet einen Abfrage Wunsch beschreiben und fertig ist das Ganze.
Ein hübscher Nebeneffekt, der Code ist Datenbank unabhängig.
Noch schöner wäre das Ganze wenn es für NHibernate schon einen LINQ Provider gäbe, denn soweit ich das Überblicke ist nur MS-SQL zurzeit voll unterstützt, alle anderen LINQ Provider stecken wohl noch in den Kinderschuhen.
- Posted by admin on September 24, 2007
"If you want a girlfriend, avoid working in the computer games industry like the plague. If you work seven days a week, 15 hours a day for almost two years, with barely enough time for a pint, you have no time whatsoever for relationships. Plus computer-games makers are regarded as being about as hip and cool as abattoir workers."
Toby Gard, creator of Lara Croft.
"As we said in the preface to the first edition, C "wears well as one's experience with it grows." With a decade more experience, we still feel that way."
Brian Kernighan and Dennis Ritchie
- Posted by admin on September 14, 2007
Ein neues Video mit Peter Hallam. Er redet über „Automatic Properties“ in C#, wie sie entstanden, wie man sie einsetzen kann. Er erzählt auch die Geschichte von Properties und wie sich C# als Programmiersprache entwickelt hat. Peter Hallam ist Mitglied des C# Language Teams.
- Posted by admin on September 12, 2007
Wo der der Unterschied zwischen "Method Chaining" und einem "Fluent Interface" liegt, ist sicher eine Ermessensfrage. Hier ein Beispiel für Method Chaining:
1 StringBuilder stringBuilder = new StringBuilder();
2 stringBuilder
3 .Append("Method Chaining -")
4 .Append("die wohl älteste Methode")
5 .AppendLine("der Welt")
6 .AppendLine(":-)");
Ein Fluent Interface liefert hingegen Kontext, nehmen wir diesen Code:
1 PlaceOrder
2 .CreateNew(PremiumOrder.With(22).Items)
3 .For.User("MR-T")
4 .InCase(
5 User.IsFriendlyLevel == AboveAverage &&
6 User.Age > 18
7 ).Commit()
Die Implementierung für obigen Code ist deutlich interessanter aufwändiger. Wenn bis zum Ende durch exerziert, ist nach jedem Methodenauswahl nur eine sinnvolle Menge von Methoden, also Kontext Abhängiges Interface nach außen gelegt.
1 public class PlaceOrder
2 {
3 public static IOrderPrepared CreateNew(OrderDescriber orderDesc){
4 return GetPreparedOrderBy(orderDesc);
5 }
6
7 public static Order GetPreparedOrderBy(OrderDescriber orderDesc){
8 Order order = new Order(orderDesc.itemCount);
9 return order.ServiceLevel = orderDesc.ServiceLevel;
10 }
11
12 }
13
14 public class OrderDescriber
15 {
16 public OrderDescriber Items{
17 get{
18 AmountType = OrderAmountType.Items;
19 return this;
20 }
21 }
22
23 public OrderAmountType AmountType = OrderAmountType.Boxes;
24
25 public OrderDescriber(int itemCount){...}
26
27 public static OrderDescriber With(itemCount){
28 return new OrderDescriber(itemCount)
29 }
30 }
31
32 public interface IOrderPrepared{...}
33 ...
Der Obige (Pseudo) Code erstellt eine Schnittstelle, die sich per IntelliSense bedienen lässt.
Es lohnt sich wohl nur soviel Arbeit zu investieren, wenn der Kontext schwierig ist und sich so Fehler vermeiden lassen. Interessant es auch die Zeit zu investieren, wenn vorrausichtlich viele Entwickler den Code verwenden werden. Alternativ kann man vereinfachen und den Kontext weitestgehend weglassen, also ein Arsenal möglicher Methoden nach außen legen.
Ein Fluent Interface ist aus meiner Perspektive auch "Domain Specific Language" für die gilt: je einfacher die nach Außen gelegte Schnittstelle, desto zeitraubender ist die Implementierung.
Wobei die Schnittstelle, das Fluent Interface nur eine Facade für die eigentlichen Domain Objekte sein sollte und nicht die Business Logik komplizierter machen sollte.
- Posted by admin on September 10, 2007
David Laribee veröffentlicht eine kurze knackige Zusammenfassung des Agile Manifests als PDF. Spannend finde ich, dass sich das agile Manifesto problemlos auf andere Arbeitsfelder übertragen lässt. Das Cheat Sheet ist hier zu finden: Agile Manifesto PDF.
- Posted by admin on September 8, 2007
Da arbeitet man Tag ein Tag aus mit Visual Studio 2005 und trotzdem lässt sich hier und da noch etwas Neues entdecken. Heute ist mir das "Code Definition Window" über den Weg gelaufen. Steht der Cursor für kurze Zeit über einem Typ, zeigt das Fenster den dazugehörigen Quelltext.

Im "Code Definition Window" ist das Schreiben von Code nicht möglich. Steht der Quelltext nicht zur Verfügung, wird die öffentlich Schnittstelle mit Kommentaren angezeigt. Das Bild unten zeigt "Object". Jetzt weiß ich endlich wofür ich den dritten Monitor brauche :-)
Ob das beim Arbeiten einen wirklichen Mehrwert hat? Schließlich stehen mit CTRL+SPACE, also der IntelliSense alle nötigen Information über einen Typen zur Verfügung. Und in Resharper genügt CTRL B und man springt zur Klassen, Property oder Funktions Definition.
- Posted by admin on September 7, 2007
ASP.NET Webforms sind nicht jedermanns Liebling. Sie sind Komplex, haben ein monströsen Lifecycle und die Lernkurve für Webentwickler aus der PHP, Ruby on Rails oder Perl Welt ist hoch. Eine Alternative ist MonoRail. Ken Egozi hat die Slides seiner MonoRail Präsentation hier zum Download bereit gestellt.
(Aus den Slides von Ken Egozi)