Antipatterns

Thomas Mentzel hat in seiner “Pattern of the week” Reihe einen guten Artikel über Antipatterns geschrieben.

Dem möchte ich ein paar weitere Dinge hinzufügen.

1. Methoden mit vielen Parametern sind zu vermeiden. Microsoft hat dieses Antipattern leider im .Net Framework einige male benutzt und so ist man schnell geneigt, diese Unsitte nachzumachen. Laut dem Buch "Clean Code" ( zum Beispiel bei Thalia erhältlich ) sollte die Parameteranzahl 3 nicht übersteigen. Was aber wenn man mehr braucht? Ein einfaches POCO ist hier die Lösung:

public class PutDescriptiveNameForParameterContainerHere
{
   public string SomeString { get; set; }
   publid double SomeAmount { get; set; }
   public DateTime SomeDate  { get; set; }
   public Func<Entity, bool> SomeFilter  { get; set; }
}
//...
void MyMethod(PutDescriptiveNameForParameterContainerHere descriptiveName)
{
   //...
}

2. Kryptisch abgekürzte Variablen. Die Zeiten in denen Computer nur ein paar Kilobyte RAM hatten, sind lange vorbei! Man sollte vielmehr aussagekräftige Namen benutzen. Die Kollegen im Team werden es danken und auch man selber findet sich nach längerer Zeit noch im eigenen Code zurecht.

3. Überflüssige Kommentare vermeiden

// Addiert zwei Zahlen
public double AddNumbers(double numberOne, double numberTwo)
{
   return numberOne + numberTwo;
}

4. Wenn Kommentare nötig sind, damit man den Code versteht, stimmt etwas nicht! Ausnahme sind Notizen zum Debugging, für die ToDo-Liste. Code sollte möglichst selbsterklärend sein (siehe Punkt2).

DotNetKicks-DE Image
Published Mittwoch, 29. Dezember 2010 00:13 von Rainer Hilmer

Kommentare

# re: Antipatterns

Mittwoch, 29. Dezember 2010 08:23 von Jan Welker

Hallo Rainer,

ich finde Kommentare wie "Addiert zwei Zahlen" auf überflüssig. Kommentare finde ich dann sinnvoll wenn erklärt warum etwas gemacht wird.

Viele Grüße,

Jan

# Antipatterns

Mittwoch, 29. Dezember 2010 08:24 von dotnet-kicks.de

Sie wurden gekickt (eine gute Sache) - Trackback von dotnet-kicks.de

# re: Antipatterns

Mittwoch, 29. Dezember 2010 20:22 von JakeJBlues

Hallo Rainer,

kann nur zustimmen :-D

Code never lies !!!

und -> Kommentare verwischen nur die freie Sicht auf den Code :-D

Gruß JJR

P.S.: Zu 1) Bin mir nicht im Klaren, warum man bei "Parameter Objekten" Properties verwenden soll :-(

# re: Antipatterns

Mittwoch, 29. Dezember 2010 22:12 von Rainer Hilmer

@JJR: Deine These zu Punkt 1? Geht es etwa um das alte Thema "Properties vs public fields"?

# re: Antipatterns

Freitag, 31. Dezember 2010 16:33 von JakeJBlues

@Rainer -> Yup....

Bin evtl. ein Verfechter der "public fields"....

Aber nachdem ich ein wenig "nachgedacht" habe, wenn man es so nennen kann :-( Bin ich mir nicht sicher, ob 1) tatsächlich ein Anti-Pattern ist. Denn wenn ich ein POCO benutze für die Parameterübergabe nutze, müßte ich ja eigentlich sicherstellen, dass der "Inhalt" des POCO's konsistent ist. Mir fiele hierzu dann ein, den Konstruktor zu nutzen, was ja wiederum zu "langen Parameterlisten" führt. Hast Du hierfür eine Lösung?

Gruß JJR und einen Guten Rutsch!

# re: Antipatterns

Freitag, 31. Dezember 2010 22:26 von Rainer Hilmer

Hallo JJR,

du musst die an eine Methode übergebenen Parameter auch auf Konsistenz prüfen. Wo also ist der Unterschied?

Ich kann mir diverse Vorgehensweisen dafür vorstellen. Es hängt auch davon ab, wie die Reaktion aussehen soll. Eine Exception, null , oder ein NullObject (siehe NullObject Pattern) als Rückgabe bei Inkonsistenz, sind nur ein paar Dinge die mir gerade spontan einfallen.

Ich kann mir sogar vorstellen, zumindest einen Teil der Konsistenzprüfung direkt im POCO vorzunehmen. Statt Autoproperties würden dann die alten Varianten mit Backing field benutzt. Im Setter-Block könnte man die Prüfung vornehmen und bei Inkonsistenz eine Exception werfen lassen. Der haken an der Sache ist nur, dass es dort keiner erwartet. Zumindest ich hab das noch nicht gesehen.

Eine weitere Möglichkeit wären Microsofts CodeContracts:

research.microsoft.com/.../contracts

msdn.microsoft.com/.../dd491992.aspx

social.msdn.microsoft.com/.../en-US

# re: Antipatterns

Freitag, 31. Dezember 2010 22:28 von Rainer Hilmer

Ach ja, und ein gutes neues Jahr wünsche ich auch. :-)

# re: Antipatterns

Freitag, 31. Dezember 2010 23:22 von Rainer Hilmer

Ich möchte noch etwas zu Punkt 1 los werden. In meinem Blog Post habe ich, ausser der Empfehlung aus dem Clean Code Buch, nichts über das "warum" gesagt.

Ob man es nun POCO, business object, value object oder Parameter container nennt, kann ich selber nicht mit hundertprozentiger Sicherheit sagen.

Warum also Container statt einer Methode mit n > 3 Parametern oder params object[]?

Der Grund ist die Lesbarkeit. Ist das so wichtig? Ich und alle anderen CCD-Jünger denken, ja. Denn Code der besser lesbar ist, kann leichter verstanden werden. Bei einer Methode mit vielen Parametern muss man nicht selten zwischendurch in die Parameterinfo von Intellisense schauen, um zu erfahren wo denn nun was eingetragen werden soll. Auch danach kratzt man sich doch verständnislos am Kopf wenn man so etwas sieht:

var result = GetFamiliesBy("Musterstadt", new DateTime(2000,5,20), 2, true);

Was bedeutet die 2 und was true?

Viel leichter wird es dagegen wenn man ein Poco benutzt:

var filter = new FamilyFilter

{

  Wohnort = "Musterstadt",

  Geburtsdatum = new DateTime(2000,5,20),

  AnzahlKinder = 2,

  Verheiratet = true

}

var result = GetFamiliesBy(filter);

Klar, in der Praxis würde man keine statischen Werte einsetzen. Sie kämen wohl viel eher von einem UI.

var result = getFamiliesBy(WohnortTextBox.Text, GeburtsdatumCalendar.SelectedDate, int.Parse(AnzahlKinderTextBox.Text), VerheiratetCheckBox.Checked);

Muss ich das noch kommentieren? :-)

Wenn das Thema auf APIs kommt, gibt es noch eine schöne Alternative zu Parameter Containern: Fluent Interfaces.

# re: Antipatterns

Samstag, 1. Januar 2011 12:08 von JakeJBlues

Hallo Rainer,

Dir natürlich auch ein frohes neues Jahr ;-)

Bzgl. Deines Beispieles WohnortTextBox.Text usw.... hier würde ich evtl. empfehlen ein MVP - Patterns oder ähnliches einzusetzen.

Aber nun zu den Parametern-Objekten oder wie immer Sie heißen mögen :-)

Wenn ich ein Paramter-Objekt FamilyFilter habe mit Konsitenz-Prüfungen o.ä., dann kann leider keinen einen leidenschaftlichen Entwickler hindern, davon eine Ableitung zu machen und die "implementierten" Konsistenz-Prüfungen zu umgehen, denke bei Code-Contracts ist es ähnlich.

Bei der Lesbarkeit im "Aufruf" gebe ich Dir aber nur insofern recht, wenn das Parameter-Objekt direkt vor der Nutzung befüllt wird, weil es ansonsten "schwierig" werden könnte herauszufinden, welche Daten aktuell im "Parameter-Objekt" enthalten sind.

Fluent-Interface könnte eine Alternative sein, da gebe ich Dir recht, obwohl ein

GetFamiliesBy( FamilyFilter.CreateInstance().SetWohnort("A").SetGeburtsDatum(Date.Now).SetAnzahlKinder(2).SetVerheiratet(true))

für manche wohl auch "unlesbar" aussieht ;-)

Gruß JJR

# re: Antipatterns

Freitag, 7. Januar 2011 23:06 von Rainer Hilmer

Hallo Ilker,

danke für deinen Kommentar. Ich gebe dir natürlich Recht wenn du sagst dass wichtige Stellen des Codes dokumentiert werden sollten. Ich habe es bisher nur so gehalten dass ich eine begleitende Dokumentation zum Projekt schreibe. Das fängt mit einer Einleitung über den Sinn der Applikation an, geht dann über eine Abhandlung der Architektur und, wo es nötig ist, bis zu Details im Code. Ich sehe den Vorteil darin, dass ich einerseits eine Art "all in one" Doku habe und andererseits meinen Code sauber halte (XML-Kommentare sind sowieso drin). Was meinst du dazu?

# re: Antipatterns

Samstag, 23. April 2011 20:23 von Rainer Hilmer

@JakeJBlues:

1. Wenn ein anderer Entwickler partout ein System aushebeln will, ist das nicht zu verhindern. Wir reden hier aber doch nicht von irgendwelchen Hacker-Attacken!

2. Dein Beispiel eines fluent Interfaces ist nur zur Hälfte eines. Den wichtigsten Apsekt hast du aussen vorgelassen. Fluent Interfaces sollen die Lesbarkeit vebessern, aber dein Beispiel ist eigentlich das Gegenteil davon. Mit einem richtigen Fluent Interface würde die Syntax so aussehen:

GetFamilies()

.WhereResidenceIs("Posemuckel")

.And

.WhereBirthdayIs(new DateTime(2000,6,15))

.And

.WhereNumberOfChildrenIs(2)

.And

.MarriedIs(true)

.BuildFilter();

Kommentar abgeben

(verpflichtend) 
(verpflichtend) 
(optional)
(verpflichtend)