Wenn man als Entwickler in ein neues Projekt kommt, dann fällt es einem fast immer schwer sich im bestehenden Code zu orientieren. Entweder es gibt zu wenig Struktur, d.h. alle Dateien liegen in wenigen oder keinen Projekten/Ordnern, oder zu viel, d.h. alle Dateien verstecken sich hinter einer tiefen Struktur an Ordnern mit mehr oder weniger sinngebenden Namen. Deshalb die Frage: wie müssen wir Code strukturieren, dass sich neue Teammitglieder schnell und problemlos in der Struktur zurecht finden?
Es geht mir an der Stelle jetzt erst mal gar nicht um die Aufteilung in eigene Komponenten. Dies alleine kann ganze Büche füllen. Dabei sei an dieser Stelle nur auf folgende Prinzipien verwiesen:
- The Reuse/Release Equivalence Principle (REP)
- The Common Reuse Principle (CRP)
- The Common Closure Principle (CCP)
Ich will mich jetzt nur darauf konzentrieren, wie viel “Struktur” innerhalb eines Projektes vorhanden sein sollte. Außerdem ist es noch wichtig wann und wie diese entstehen.
Zu Begin eines Projektes legt man eine Architektur fest. Diese Beinhaltet in der Regel eine Aufteilung in Schichten oder Belange (Siehe Seperation of Concerns – SoC). Diese Entscheidungen werden i.d.R. in UML-Diagrammen festgehalten. Je nach Granularität kann so etwas so aussehen:
oder so:
In jedem sollte für jede Schicht – oder jeden Belang – aus der Architektur ein getrennter Bereich existieren. Ist die Trennung nicht schon durch separate Komponenten gegeben, dann sollte sie auf jeden Fall durch Ordner entstehen.
Im Umkehrschluss heißt das aber für mich, dass es zu Projektstart auch nicht mehr Ordner geben sollte, als in der Architektur zu finden sind. Besonders die Ordnertiefe sollte nie tiefer als maximal 2 oder 3 sein. Vermeiden sollte man auch Unterordner mit generischen Namen wie “Controls” oder “Interfaces”. Mit hoher Wahrscheinlichkeit werden sich diese Ordner sonst an vielen Stellen “wiederholen”.
Namespaces
Für eine gute Übersicht sollte die Ordnerstruktur der Struktur des Namensräume entsprechen. Viele Ordner heißt in diesem Fall viele Namespaces; und dies führt dazu, dass viele Using-Statements zu andren Bereichen in der eigenen Anwendung nötig sind. Das erschwert die Wartung und das Refactoring. Deshalb gibt es bei der statischen Codeanalyse auch eine Regel, dass man Namensräume mit wenigen Typen vermeiden soll (CA1020: Avoid namespaces with few types). Diese Regel mach zu Begin eines Projektes natürlich nur bedingt sind und kann getrost unterdrückt werden. Für laufende Projekte ist sie aber durchaus sinnvoll. Wenn ich sehr viele Namensräume mit weniger als 5 Klassen habe, ist das ein Indiz für eine unnötig komplexe Struktur.
Gewachsene Strukturen
Insgesamt ist es aus meiner Ansicht besser mit wenigen Ordern/Namespaces zu starten. Sind in einem Ordner/Namespace dann mal wirklich zu viele Typen (und mit viele meine ich VIELE), dann kann man sinnvolle Cluster bilden und Teile in andere Bereiche verschieben das ist in der Regel viel besser als vorher versuchen die Struktur krampfhaft festzulegen.
Wie viele Typen dürfen in einem Namensraum sein?
Hier ist es schwer eine Aussage zu treffen. Harte Beschränkungen gibt es nicht. Am Besten schaut mal mal, wie andere das machen. Mit folgendem Code-Snippet können wir die Anzahl der Klassen je Namenraum in der Assembly mscorelib bestimmen:
var types = typeof(string).Assembly.GetExportedTypes(); var result = from x in types group x by x.Namespace into y group y by y.Count() into z orderby z.Key select z; Debug.WriteLine("Min {0}", result.Min(x => x.Key)); Debug.WriteLine("Avg {0}", (int)result.Average(x => x.Key)); Debug.WriteLine("Max {0}", result.Max(x => x.Key));
Das Ergebnis ist folgendes:
Min 1
Avg 38
Max 217
Ich denke man sieht an dem Ergebnis, dass 40 oder 60 Klassen noch kein Problem darstellen. Für die Übersichtlichkeit kann man auch nur sehr schwer generelle Aussagen treffen. Es kommt ja stark darauf an, wie viele logische Cluster es von den Namen gibt. Generell gilt: es ist einfacher einen Typ in einer langen Liste zu finden, als sich auf der Suche durch eine Hierarchie zu kämpfen, die man nicht versteht.
Fazit
Zu Begin jeden Softwareprojektes muss man sich eine Architektur überlegen und die Software in Bereiche/Belange Aufteilen. Diese Bereiche sollten durch eigene Komponenten oder Ordner separiert werden. Darüberhinaus sollte man mit so wenig “Struktur” wie Möglich beginnen. Es ist einfach lange Listen sinnvoll zu Cluster. Es ist aber sehr schwierig in komplexen Strukturen den richtigen Platz für neue Typen zu finden – besonders, wenn man neu in einem Projekt ist.