Den Teilnehmern des dotnetpro.powerdays C# für Profis wurde im Anschluss an die eigentliche Veranstaltung die Teilnahme an einem .NET Coding Dojo angeboten, das von Ilker Cetinkaya durchgeführt wurde.
Im Rahmen dieses Dojos wurde die Frage diskutiert, wie der übliche TDD-Cycle Red – Green – Refactor auszulegen sei. Stein des Anstoßes war, dass einige Teilnehmer den Schritt Refactor als optional angesehen haben und ihn daher im konkreten Fall außen vor lassen wollten – was bei anderen Teilnehmern wiederum für Unmut sorgte.
Ich selbst habe die Meinung vertreten, dass der Schritt Refactoring keineswegs optional sei, denn stellt man diesen in Frage, öffnet man seinem gänzlichen Ausschluss Tür und Tor – dem verführerischen Weg zur Brownfield-Anwendung wird damit Vortrieb geleistet.
Einige Teilnehmer des Dojos – allen voran Stefan Lieser – haben argumentiert, dass ein Refactoring am Ende des TDD-Cycles keinen Sinn machen würde – sondern dass es vielmehr an den Beginn dieses Zyklusses verschoben werden sollte, schließlich sei Refactoring auf ein Ziel und somit auf einen Plan angewiesen – sonst wisse man nicht, in welche Richtung das Refactoring zu treiben sei.
Stefan hat dies in seinen Blogeinträgen Refaktorisieren im TDD Prozess und TDD 2.0 dargelegt – allerdings bin ich davon nicht überzeugt. Ein Refactoring zu Beginn des TDD-Cycles macht keinen Sinn: Erstens aus dem bereits genannten Grund, der Verschmutzung von Code Vortrieb zu leisten, zweitens weil ich direkt zu Beginn eines Projektes kein Refactoring betreiben kann.
Auch wenn es sich hierbei nur um eine einzige Ausnahme handelt, in der die von ihm vorgeschlagene Regel nicht greift – es ist eine Ausnahme, was ich persönlich nicht schön finde.
Für mein Empfinden gibt es zwei Arten von Refactorings: Einerseits kleine, kosmetische Korrekturen, andererseits grundlegende, Architektur-betreffende Änderungen. Stefan beschreibt diese Aufteilung ebenfalls – zieht für mein Empfinden aber die falschen Schlüsse.
Natürlich ist es – wenn überhaupt möglich – schwierig, grundlegende, Architektur-betreffende Änderungen durchzuführen, wenn man noch nicht weiß, in welche Richtung die Software weiterentwickelt werden soll.
Diese Art von Änderungen ist jedoch gar nicht das, was in der Regel von Refactoring betroffen ist: Ob ich Code in eine private Methode auslagere, um DRY umzusetzen, ist unabhängig von der Architektur. Ebenso, ob ich ein Literal in eine Konstante auslagere oder nicht.
Diese Art von Refactorings macht den bedeutend größeren Anteil aus – es wäre auch tragisch, wenn Entwickler und Architekten nach jedem Test beständig damit beschäftigt wären, die Architektur grundlegend anzupassen.
Es liegt auf der Hand, dass diese Art von kosmetischen Korrekturen direkt nach dem Schritt Green ausgeführt werden sollten – ganz so, wie TDD es in seiner Urform vorschreibt: Red – Green – Refactor.
Die Architektur-bezogenen Änderungen werden in diesem Schema aus drei Schritten also gar nicht berücksichtigt: Die logische Konsequenz daraus ist die Einführung eines vierten Schrittes, der getrennt von Refactor stattfinden kann.
Da dieser vierte Schritt wesentliche Änderungen behandelt, die das architektonische Grundgerüst des Codes betreffen, nenne ich diesen Schritt Rearrange – schließlich werden die einzelnen Komponenten und deren Verdrahtung zueinander in diesem Schritt neu arrangiert und komponiert.
Dieser vierte Schritt ist – naturgegeben – erst dann sinnvoll, wenn bekannt ist, in welche Richtung die Entwicklung laufen soll. Ihn aber direkt in den TDD-Cycle aufzunehmen, halte ich für unglücklich – schließlich wird er nicht nach jedem Durchlauf angewendet. Daher plädiere ich für zwei Zyklen, die einander enthalten:
TDD = Red – Green – Refactor
als klassischer TDD-Cycle für kosmetische Korrekturen und
TDD erweitert = TDD – TDD – … – TDD – Rearrange
als erweiterter TDD-Cycle für architektur-bezogene Anpassungen, Änderungen und Erweiterungen.
Den Schritt Rearrange habe ich bewusst am Ende des erweiterten TDD-Cycles untergebracht, denn vor der ersten Ausführung von TDD ergibt die Durchführung von Rearrange keinen Sinn – und da eine Software nie “fertig” ist und es daher stets einen weiteren TDD-Cycle geben wird, habe ich keinerlei Bedenken, Rearrange an die letzte Position zu schieben.
Der erweiterte TDD-Cycle hat in diesem Sinne nämlich keinen Anfang und kein Ende mehr, sondern stellt eher einen Fluss dar – welche Vorbedingungen für den jeweils nächsten Schritt erfüllt sein müssen, darüber wird keine explizite Aussage gemacht. Implizit jedoch erfordert Rearrange Planung, womit auch Stefans Wunsch nach mehr Planung berücksichtigt wäre.