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?