Komplexe Refactorings an Legacy Code durchführen – Teil 2

Dies ist der 2. Teil des Artikels über die Mikado Methode. Lesen Sie ggf. zunächst den 1. Teil.

Umsetzung des Refactorings mit der Mikado Methode

Im ersten Schritt ist durch eine experimentelle Vorgehensweise ein Mikado Graph entstanden. Es wurde jeweils naiv versucht, die erforderlichen Änderungen am Code durchzuführen. Alle Probleme, die sich bei diesen Experimenten gezeigt haben, sind als Vorbedingungen für das Mikado Ziel in den Mikado Graph übernommen worden. Da die einzelnen Vorbedingungen aufeinander aufbauen, sich also in Abhängigkeiten befinden, enthält der Mikado Graph nicht nur die Vorbedingungen, sondern stellt auch die Abhängigkeiten dar.

Mikado GraphDer Mikado Graph ist also ein gerichteter Graph. An der Wurzel steht das Mikado Ziel, das durch die einzelnen Refactoring Maßnahmen erreicht werden soll. Das Mikado Ziel kann so etwas sein wie „Speichern der Daten in der Cloud statt lokal“ oder „Fehler bei der Neuanlage eines Produkts beheben“.

Nachdem der Mikado Graph erstellt ist, werden die einzelnen Herausforderungen angegangen. Die Umsetzung der Refactorings erfolgt in der Gegenrichtung der Abhängigkeiten, von den Blättern zur Wurzel. Wir arbeiten uns nun in der Gegenrichtung, im Bild von außen nach innen, vor. Die einzelnen Herausforderungen werden gelöst und jeweils in die Versionskontrolle übertragen. Beachten Sie, dass diese Änderungen auf dem Trunk durchgeführt werden, da sie von kurzer Dauer sind. Ein Branch ist nicht erforderlich, weil die Änderungen nicht lange dauern und das Ergebnis potentiell auslieferbar sein soll. Automatisierte Tests sollten entweder schon vorhanden sein oder im Zuge des Refactorings ergänzt werden. Vor dem Commit in die Versionskontrolle muss schließlich sicher gestellt sein, dass die Änderung zu keinen Defekten geführt hat.

Die Mikado Methode

Die folgende Abbildung zeigt den Ablauf der Mikado Methode.

Die Mikado MethodeDas Mikado Ziel notieren

Zu Beginn wird das Ziel der Änderung notiert. Dieses Ziel ist getrieben von einer Anforderung des Kunden. Ein neues Feature oder die Änderung eines bestehenden Features sowie Bugfixes sind potentielle Ziele einer Änderung.

Das Ziel bzw. die aktuelle Vorbedingung naiv implementieren

Nun wird versucht, das Ziel auf naive Weise zu erreichen. Implementieren Sie munter drauf los. Wichtig ist jetzt herauszufinden, was der Umsetzung im Weg steht. Es geht in diesem Schritt nicht darum die endgültige Implementation vorzunehmen, sondern Erkenntnisse zu gewinnen. Daher ist es in Ordnung, das ein oder andere Clean Code Developer Prinzip zu verletzen, da der Code ohnehin zunächst wieder weggeworfen wird. Allerdings dürfen Sie in diesem Schritt nicht über die Stränge schlagen. Halten Sie immer wieder inne und prüfen Sie, ob Sie an einem Punkt angekommen sind, an dem es darum gehen könnte, einen Erkenntnisgewinn im Mikado Graph zu notieren. Wenn Ihr System sich plötzlich nicht mehr wie gewünscht verhält oder die Änderung viele Compilerfehler an allen möglichen Stellen verursacht, haben Sie einen solchen Punkt erreicht.

Gibt es ein Problem?

Wenn Sie eine Änderung durchgeführt haben, müssen Sie herausfinden, ob es ein Problem gibt. Es könnte sein, dass das Programm nicht mehr tut was es soll. Dann liegt definitiv ein Fehler vor. Wenn Sie automatisierte Tests haben, sind Sie fein raus, denn dann schlägt womöglich einer fehl. Ohne Tests bleibt Ihnen nur das manuelle Testen. Im Zweifel gehen Sie an dieser Stelle davon aus, dass etwas kaputt gegangen ist.

Zum zweiten können Sie auf Probleme in Ihrer Codebasis stoßen. Wenn Sie bei der naiven Umsetzung auf eine Herausforderung stoßen, sollten Sie an dieser Stelle ebenfalls anhalten. Typische Herausforderungen sind Abhängigkeiten. Sie stellen plötzlich fest, dass Sie eine Abhängigkeit übersehen haben und die Änderung erst abschließen können, wenn Sie die Abhängigkeit eliminiert oder verändert haben. Eine weitere typische Herausforderung ist das Vermischen von Aspekten. Sie stellen fest, dass eine Methode oder Klasse nicht nur für einen Aspekt zuständig ist, sondern ein Durcheinander von Aspekten vorliegt. Um in guter Weise weiterzukommen, müssen Sie erst die Aspekte trennen. Notieren Sie die Herausforderung als Vorbedingung im Mikado Graph und betrachten Sie das Ergebnis der Änderung als ein Problem.

Ergibt die Änderung Sinn?

Wenn es keinen Fehler gab, müssen Sie herausfinden, ob die Änderung Sinn ergibt. Hier geht es darum, Änderungen nur dann in die Versionskontrolle zu übertragen, wenn diese zusammenhängend einen Sinn ergeben. Das bedeutet, Sie sollten nun keine Ergebnisse einchecken, die einen unfertigen Zwischenschritt darstellen.

Typischerweise kommen Sie hier erst zu einer positiven Entscheidung, wenn Sie begonnen haben, die Erkenntnisse des Mikado Graphs Blatt für Blatt umzusetzen. Sie haben also nicht mit dem Ziel des Mikado Graph begonnen, sondern haben sich ein Blatt des Graphen ausgesucht und begonnen, diese Voraussetzung für das Oberziel zu implementieren. Hierbei sollten Sie natürlich irgendwann zu der Entscheidung kommen können, dass die Änderung Sinn ergibt. Sie befinden sich jetzt nicht mehr in der Experimentierphase sondern sind dabei, die gewonnenen Erkenntnisse Blatt für Blatt umzusetzen.

Sie sollten die Änderung durch automatisierte Tests absichern. Auf diese Weise ist es leichter herauszufinden, ob die Änderung Sinn ergibt.

Commit der Änderungen in die Versionskontrolle

Sofern die Änderungen einen Sinn ergeben, übertragen Sie diese in die Versionskontrolle. Im Mikado Graph machen Sie einen Haken an die Vorbedingung, denn sie ist nun umgesetzt. Dadurch ergeben sich neue Blätter, die das Ziel der nächsten Änderung sein können.

Ist das Mikado Ziel erreicht?

Nach dem Commit müssen Sie entscheiden, ob das Mikado Ziel bereits erreicht ist. Wenn ja, sind Sie fertig.

Nach Lösungen suchen

Wenn es Fehler gab, müssen Sie nun nach einer Lösung suchen. Fehler können auf der Ebene des Programmcode auftreten. Ein Beispiel könnte sein, dass Sie feststellen, dass Sie das Programm beim Entfernen einer Abhängigkeit nicht mehr übersetzen können. Ferner können Fehler bei der Ausführung des Programms auftreten. Ihre Änderung hat das Programm „kaputt gemacht“. In beiden Fällen müssen Sie nach Lösungsideen suchen.

Die Lösungen als Vorbedingungen im Mikado Graph notieren

Haben Sie eine Lösungsidee für das Problem gefunden, notieren Sie diese im Mikado Graph. Achten Sie darauf, dass die im Graph notierte Vorbedingung nicht zu umfangreich ist. Teilen Sie umfangreiche Aufgaben besser in mehrere Schritte auf. Achten Sie dabei darauf, die Abhängigkeiten der einzelnen Schritte korrekt darzustellen.

Verwerfen aller Änderungen mit Hilfe der Versionskontrolle

Dieser Schritt der Mikado Methode ist sehr wichtig: verwerfen Sie nun alle Änderungen! Nur so ist sichergestellt, dass Sie die nächsten Schritte wieder auf einem bekannten Zustand auszuführen. Wenn Sie auf dem „kaputten Code“ weiterarbeiten, würden Sie sehr schnell den Überblick verlieren und sich im Chaos verstricken. Durch die Visualisierung im Mikado Graph soll genau das verhindert werden. Dazu muss jeder einzelne Schritt auf einer Codebasis durchgeführt werden, von der Sie wissen, in welchem Zustand sie ist. Andernfalls schichten Sie einen großen Stapel Probleme auf. Schauen Sie sich dazu noch mal die Bildfolge im ersten Teil des Artikels an. Nachdem Sie ein Pflaster draufgelegt haben, erscheinen sofort weitere Probleme. Da verlieren Sie schnell den Überblick. Sie befinden sich dann typischerweise in einer der beiden folgenden Situationen:

  • Sie wissen nicht, ob Ihr System noch korrekt funktioniert. Ihre Änderungen werden zwar übersetzt, aber mangels ausreichender automatisierter Tests wissen Sie nicht, in welchem Zustand sich Ihr System befindet.
  • Sie wissen, dass etwas kaputt gegangen ist, wissen allerdings nicht, welche Änderung dafür verantwortlich ist. Somit bleibt Ihnen nichts anderes übrig, als alle Änderungen rückgängig zu machen.

Da Sie ohnehin eine naive Implementation vorgenommen haben mit dem Ziel, Erkenntnisse zu gewinnen, ist es nicht weiter tragisch, nun alle Änderungen zu verwerfen. Trennen Sie sich leichten Herzens von den Codeänderungen und feiern Sie den Erkenntnisgewinn.

Nächste Vorbedingung auswählen, um damit zu arbeiten

Nun schauen Sie sich im Mikado Graph um und suchen eine Vorbedingung, mit der Sie im nächsten Schritt weiterarbeiten. Sie werden erneut versuchen, diese Vorbedingung naiv umzusetzen. Sie nehmen sich natürlich nur Blätter vor, weil diese nicht von anderen Vorbedingungen abhängen. Es steht Ihnen frei, welches Blatt Sie auswählen.

Fazit

Mit der Mikado Methode steht eine einfache und gleichzeitig leistungsfähige Methode für komplexe Refactorings zur Verfügung. Die Herausforderung besteht weniger darin, die Methode zu verstehen, sondern sie konsequent anzuwenden. Die größte Schwierigkeit dürfte sein, beim naiven Ändern rechtzeitig anzuhalten, die Erkenntnis als Vorbedingung im Mikado Graph zu notieren und dann konsequent ein Revert in der Versionskontrolle vorzunehmen. Das braucht Übung. Das Internet ist voll von Übungsmaterial. Schauen Sie sich ein Open Source Projekt an, das Sie einsetzen. Vielleicht haben Sie eine Idee für ein zusätzliches Feature oder entdecken einen Fehler. Dies ist eine wunderbare Gelegenheit, die Mikado Methode zu üben.

3 Gedanken zu „Komplexe Refactorings an Legacy Code durchführen – Teil 2“

Schreibe einen Kommentar