Conways Law Revisited

Wenn man in einer Woche zweimal in unterschiedlichen Kontexten mit einer Sache
konfrontiert wird, ist das ein Zeichen. Wofür auch immer. So ist es mir in der
letzten Wochen mit Conways Law ergangen. Bisher kannte ich Conways Law als
das Gesetz, das besagt, dass sich über kurz oder lang die Strukturen eines
sozialen Systems in einem technischen System wiederfinden werden. Wenn ich ein
Programm schreibe, mit dem später zwei Fachabteilungen arbeiten werden, wird
sich diese Trennung auch im technischen System – dem Programm – ausdrücken.

Die Wikipedia zitiert das Gesetz von Conway so: “Organizations which design
systems [...] are constrained to produce designs which are copies of the
communication structures of these organizations”. Die Strukturen richten sich
demnach vor allem an den Kommunikationsstrukturen aus. (Ich glaube ohne eine
Quelle zur Hand zu haben, dass es im Original vor allem um Compiler ging, die
von Komitees entwickelt wurden. Conway hatte festgestellt, dass die
Modulstruktur der fertigen Compiler den Arbeitsgruppen der Komitees
entsprach.)

Das Gesetz begegnete mir zunächst in einem Artikel von Brandon Byars. Dieser
publiziert gerade auf der Webseite von Martin Fowler einen Artikel über
Enterprise Integration using REST. Im Abschnitt Do not let systems
monopolize resources
 
diskutiert er die Frage, wie man größere Systeme schneiden soll. Soll man bspw. an einer Stelle das Wissen über ein Produkt zentralisieren? Man hätte
dann ein System, das eine Ressource monopolisierte. Und das verstoße gegen das
Gesetz von Conway, das da besage, dass die Architektur des Systems die
Struktur des sozialen Systems spiegeln solle. Im Konkreten würde das heißen,
dass es mehrere Produktbegriffe in mehreren Systeme gäbe und jedes Softwaresystem um ein soziales System, das durch einen einheitlichen semantisches Kontext (Bounded Context) gekennzeichnet ist, zu errichten wäre. Doch das ist eine andere Geschichte.

Für mich war an dieser Lesart des Gesetzes neu, dass es präskriptiv,
vorschreibend, und nicht deskriptiv, beschreiben, gelesen wurde. Bisher fand ich es immer interessant, an den entstandenen Systemen zu rekonstruieren, wie sich hier die
faktischen Kommunikationsstrukturen ausgedrückt haben. Das es praktisch der gleiche
Gedanke ist, vorher nach dem sozialen Systemen und den Kommunikationsstrukturen zu fragen und die Systeme so zu modellieren, dass sie sie abbilden, kam mir dabei
nicht in den Sinn. Bis zu dieser Woche, bis zu Brandon Byars.

Die andere Begegnung war folgende. Ich lass über das Wasserfallmodell, über all die Phasen und all die Artefakte, die jede Phase erzeugte. Das Modell beschreibt auch ein System. Es ist kein strukturelles, es ist ein temporales. Die Phase folgen einander.
Aber das Gesetz von Conway lässt sich ebenfalls anwenden. Das soziale System,
das bei der Softwareerstellung involviert ist, reflektiert sich im Phasenmodell. Jede Abteilung hat ihre Phase und ihre Dokumente. Die grundsätzlichen Anforderungen werden vom oberen Management festgelegt. Die Fachabteilungen erzeugen den Inhalt der Spezifikationen. Die Architekten schaffen den Systementwurf. Die Programmierer den Code. Die Tester den Testplan. Die Betreiber das Betriebskonzept. Die Stabilität des Modells besteht darin, dass jede Gruppe ihre Phase und ihre Artefakte hat. Jede Gruppe kann sich vergegenständlichen. Es gibt kein einheitliches Wasserfallmodell (es
gibt die unterschiedlichsten Ausführungen mit zwischen 6 und 18 Phasen), weil das
zugrundeliegende soziale System immer anders aussieht. Jedes soziale System
schafft sich seine Phase und sein Artefakt. Je stärker die Abteilung um so
ausgeprägter die Phase und wichtiger das Dokument.

Das Problem des Wasserfallmodells lässt sich aus dieser Perspektive folgendermaßen
charakterisieren. Es gibt N Systeme, N Phasen und N Dokumente (Artefakte). Im
Kontext des Systems I ist das Dokument I aussagekräftig. Die Welt des Systems
I verleiht dem Dokument I seine Bedeutung. Für alle anderen Systeme ist das
Dokument marginal, randständig, unscharf, weil alle anderen Systeme anderen
Sprachspielen und Kontexten gehorchen. Im Wasserfallmodell ist dieses
Übersetzungproblem nicht adressiert. Im Gegenteil, man könnte sagen, es ist
zementiert.

Zwei Anwendungen von Conways Law, die für mich neu waren. Im Kern geht es bei
beiden um das Verhältnis von sozialen und technischen Systemen. Einmal in
struktureller Hinsicht (Design von Subsystemen), einmal in temporaler
(Phasen). Ich vermute, das wird nicht das letzte Mal sein, dass ich auf dieses
Gesetz gestoßen bin.

Composed Method Revisited

Ich habe das erste Mal von Composed Method in dem Buch Smalltalk – Best Practice Patterns von Kent Beck (1996) gelesen. Das Buch ist eine Sammlung von Mustern für das Programmieren im Kleinen. Das Problem, das Composed Method adressiert, ist:

“Wie zerlegt man ein Programm in Methoden?”

Es handelt sich um ein zentrales Muster für die Programmierung. Die Frage nach der Zerlegung eines Programmes in Methoden, ist eine der wichtigsten Fragen. Was ist die Antwort auf das Problem, die Kent Beck gibt?

“Zerlege dein Programm in Methoden, die jeweils genau eine erkennbare Aufgabe ausführen. Sorge dafür, dass alle Operationen in einer Methode auf dem selben Niveau der Abstraktion liegen. Dieses Vorgehen wird ganz natürlich zu Programmen mit vielen kleinen Methoden führen, die alle nur ein paar Zeilen lang sind.”

Soweit Composed Method. Drei Jahre später bringt Jeff Langr ein Buch heraus: Essential Java Style. Das Buch ist die Übersetzung der Smalltalk-Pattern in die Sprache Java.

Im Jahre 2002 veröffentlicht Langr einen Artikel: Enlightened Java Style. Er hat sich in 3 Jahren vom ‘Wesentlichen’ zum ‘Erleuchteten’ Java-Style vorgearbeitet. Er empfiehlt sich die 30 Dollar für sein Buch zu sparen und eine CD oder ein Geschenk für einen Freund zu kaufen. Man hätte dann etwas handfestes. Was ist es, was seinen erleuchteten Stil prägt? Er schreibt er könne sich sowieso nur eine handvoll Muster merken und deshalb hätte er die vielen Muster seines Buches zu dreien reduziert: “Composed Method, Intention-Revealing Name and Comment” – wieder Composed Method als zentrales Muster.

Langr erklärt Composed Method so:

“Composed Method sagt aus, dass eine Methode Dinge auf genau einem Niveau der Abstraktion tun soll. Sie soll extrem kohäsiv (bindig, zusammenhaltend) sein. Sie soll eine Sache tun und die soll sie gut tun.” Und zusammenfassend: “Das schnelle Verstehen ist hier das Wichtigste. Es darf mich nicht mehr als eine Minute oder zwei kosten, um zu verstehen, was ein Entwickler mit dieser Methode bewirken wollte.”

Mit diesem Wissen im Hinterkopf war ich gespannt, wie Meister der Programmierung selbst ihre Pattern anwenden. Vor einem Monat haben wir auf der Arbeit einen Innovationstag durchgeführt. Allen stand frei sich einen Tag mit einem Projekt zu beschäftigen, Vorträge zu halten, Vorträge zu hören oder anderweitig ihre Erfahrungen auszutauschen. Ich habe diesen Tag genutzt, um mir den Code der ersten überlieferten Junit-Version anzuschauen. Junit lebt auf github unter: https://github.com/KentBeck/junit.git. Der erste Commit ist die Version 3.4 vom 3. Dezember 2000. Der Commit ist von Erich Gamma. Junit sei auf einem transatlantischen Flug von Kent Beck und Erich Gamma entstanden. Kent Beck hatte das erste Unit-Testframework geschrieben (Sunit in Smalltalk) und wollte Java lernen, Erich Gamma war bereits Java-Fuchs (im eclipse-Projekt aktiv) und wollte Unittesting kennernlernen. Daraus entstanden ist Junit – ein Projekt, das sie zusammen weiterentwickelt haben. Die Versionen vor dem ersten github-Commit gingen verloren: “the earliest versions are lost in the mists of time” (Kent Beck).

Um zu sehen, wie die beiden programmieren, habe ich mir den Code von Junit 3.4 angeschaut. Ich kann es jedem empfehlen an Stelle eines Buches mal einen alten Quellcode zur Hand zu nehmen und ihn zu lesen. Junit ist ein dankbares Exemplar, weil man weiß, wie man es anwendet, und weil es überschaubar ist. Man findet viele kleine Methoden, genau wie Kent Beck es oben als Auswirkung von Composed Method beschreibt. Aber – und das ist der eigentlich Aufhänger dieses Artikels – es findet sich eine Variante des Pattern, die in den Aufsätzen über das Pattern nicht beschrieben ist. Es handelt sich dabei vielleicht nur um eine Spezifik der Anwendung Junit, aber es ist ein Aspekt, der mir vorher nicht klar war, eine Dimension des Musters, die ich bisher nicht wahrgenommen hatte.

In den Projekten, in denen ich arbeite findet sich das Muster oft als Ergebnis eines Refactorings. Eine Methode erledigt viel zu viele konkrete Aufgaben, so dass es unmöglich ist, sie zu überblicken oder nur einfach zu lesen. Man muss sich eine viertel bis halbe Stunde in den Code vertiefen und dann hat man eine Vorstellung von dem, was sie tut. Diese Methode wird dann in einem Refactoring in Blöcke zerlegt, so dass sie am Ende nur noch delegiert. Sehr schematisch: Vorher hatte sie 30 Zeilen, jetzt hat sie nur noch drei und ruft drei Methoden auf, die jeweils 10 Zeilen der alten Methode beinhalten. Die Methode wurde von einer ‘Ich mach lieber alles selbst’ zu einer ‘Ich delegiere alles’-Methode. Wenn man den Kontrollfluss verfolgt, steckt hinter jeder Untermethode gleich viel Betriebsamkeit.

In Junit 3.4 ist das anders. Jede Methode – egal ob Main, Toplevel oder ganz unten in der Hierarchie – erledigt eine konkrete Aufgabe und delegiert anderes. Die Mainmethode erzeugt den Testrunner, startet ihn (Delegation) und kümmert sich um den Exitcode (konkret). Der Start des Testrunners parsed die Kommandozeilenargumente (konkret) und startet die TestSuite (Delegation). Das starten der Testsuite kümmert sich um die Zeitmessung der Tests (konkret) und startet die eigentliche Suite (Delegation). Uns so weiter und so weiter. Diese Variante von Composed Method würde ich so beschreiben, dass jede Methode eine konkrete Aufgabe auf ihrer Ebene ausführt und dann – und das ist für das Lesen des Codes extrem wichtig – genau an einer Stelle auf eine andere Ebene delegiert. Alle Methoden benutzen kleine Hilfsmethoden, aber der Hauptkontrollfluss geht in jeder Methode nur an einer Stelle in die Tiefe. Sehr angenehm!

Was ich mitgenommen habe? Wenn ich in Zukunft Methoden zerlege, versuche ich mir zwei Fragen zu stellen. Erstens: Gibt es eine konkrete Aufgabe, die diese Methode hier erledigen kann? Zweitens: Wie kann ich den Kontrollfluss durch die Methode möglichst einfach gestalten? Wie schaffe ich es, dass man beim Lesen nur an einer Stelle in die komplexe Struktur des Programms absteigen muss?