Zum Inhalt

Buch-Rezension zu "Working Effectively with Legacy Code"

Legacy Code

Viele Bücher zeigen wie man mittels TDD sauberen Code schreiben kann. Michael Feathers geht in "Working Effectively with Legacy Code" einen anderen Weg. Er zeigt wie man aus Legacy Code Schritt für Schritt und mit viel Arbeit eine saubere Codebasis schaffen kann.

Dieser Weg ist alles andere als leicht, startet dafür aber dort wo wohl die meisten Software-Projekte sind: Bei einer grossen Menge Code mit nur wenigen (oder gar keinen) Tests und der dennoch geschäftskritische Funktionen erfüllt. Wie erhält man dessen Funktionalität und schafft es gleichzeitig flexibel auf neue Anforderungen zu reagieren?

Schritt für Schritt

Wichtig ist das man nicht gleich zu Beginn alles hinwirft. Nur weil der Code noch über keinen einzigen Test verfügt bedeutet dies nicht dass dies so bleiben muss. Im Buch findet man für sehr viele Situationen Tipps und Tricks um mit dem Testen zu beginnen.

Allerdings kann man nicht von einem Extrem in andere springen. Wo noch keine Tests vorhanden sind gleich mit TDD alles machen zu wollen wird sehr schnell scheitern. Besser ist es mit wohlüberlegten und gezielten Tests zu beginnen. Vor der geplanten Änderung erst einmal den Code anschauen und mit Tests auf einer höheren Ebene (wie Integrations- oder Akzeptanztests) beginnen. Oft braucht es auch Mut erst einmal ein Loch aufzureissen um überhaupt einen Test scheiben zu können. Denn wenn man vor dem ändern von Code erst einen Test haben will und für diesen Test erst eine Anpassung am Code braucht steht man vor einem Henne-Ei Problem.

Soll sich die Situation verbessern muss man bereit seit für eine gewisse Zeit mit Code zu leben der nicht allen OO-Regeln folgt. Zusätzliche Konstruktoren nur um Abhängigkeiten zu übergeben sind oft nötig bis dies „korrekt“ gelöst werden kann. Bleibt man dran und geht konsequent den eingeschlagenen Weg kann man auch das grösste Gestrüpp entwirren – dies geschieht aber nicht über Nacht.

Einstellung ändern

Aber was ist eigentlich Legacy Code genau und warum ist dies etwas Schlechtes? Feathers hat in seinem Buch zwei Definitionen, von denen man in der Regel nur die weniger freundlich formulierte in Erinnerung behält:

Legacy Code is Code Without Tests

In dem Sinne liegt es bei jedem einzelnen Entwickler aufzuhören vorneweg Legacy Code zu schreiben und sich über die Qualität und Testbarkeit seines Codes Gedanken zu machen. Andernfalls sind all die im Buch aufgezeigten Ansätze für nichts und man ist in kurzer Zeit wieder da wo man begonnen hat.

Was Michael Feathers in seinem Buch leider nicht anspricht ist wie man sein Team von der Notwendigkeit von wartbarem Code überzeugen kann. Genau dies aber dürfte in vielen Projekten wohl das grösste Hindernis sein.

Characterization Tests

Von all den verschiedenen Ansätzen die in diesem Buch vorgestellt werden fand ich die Characterization Tests am hilfreichsten. Bei diesen Tests fängt man nicht wie bei TDD mit dem gewünschten Verhalten an und folgt dem Red-Green-Refactor Mantra. Stattdessen beginnt man den Test in dem man beim Assert-Aufruf das Resultat der Methode mit dem Default-Wert des entsprechenden Datentyps vergleicht. Der Test wird in den meisten Fällen fehlschlagen und die Fehlermeldung liefert einem den korrekten Wert. Dieser setzt man dann im Assert-Aufruf ein und hat so einen erfolgreich bestandenen Test.

Ohne den Code anzupassen kann man so recht schnell die einzelnen Eigenschaften einer Methode oder einer ganzen Klasse durch Tests fixieren. Dieses Korsett an Tests dient einem nach dem Refactoring zu verifizieren das die Verbesserungen das Verhalten des Codes nicht verändert haben.

Um Legacy Code mit Tests zu versehen macht man also genau das was bei TDD verpönt ist: Den Test so zu schreiben das der aktuelle Code diesen besteht ohne sich Gedanken über die wirklichen Anforderungen zu machen. Aber genau dies macht diese Art von Tests für mich so praxisrelevant. Hat man Legacy Code muss man auf diesen eingehen und eine Lösung finden die den aktuellen Code beschreibt. Hat man einmal so viele Tests dass man wirklich weiss was der Code macht gilt es wieder den Schalter umzulegen und zu prüfen ob dies auch wirklich korrekt ist. Bis es so weit ist muss man die liebgewordenen Regeln aber auch einmal zurückstellen können.

Weiterführende Bücher

Nach dem der Code mit Tests versehen ist geht es ans Aufräumen. Dazu verweist Feathers oft auf Martin Fowlers "Refactoring". Das Standardwerk zu diesem Thema sollte man kennen, da man ansonsten den Ausführungen kaum folgen kann.

Wer mittels Refactoring grössere Ziele verfolgt sollte auch einen Blick auf "Refactoring to Patterns" von Joshua Kerievsky werfen. Dies baut ebenfalls auf Fowlers Buch auf und erklärt wie man mit einer Kombination von Refactorings grössere Strukturverbesserungen erreichen kann.

Fazit

Michael Feathers zeigt einem in diesem Buch wie man von einer durchschnittlichen Codebasis zu einer kommt die dank Tests auf geänderte Anforderungen reagieren kann. Der Weg dorthin ist aber nicht zu unterschätzen und man muss auch einmal bereit sein eine gewisse Unordnung zu akzeptieren. Will man sich darauf einlassen liefert einem dieses Buch viele wertvolle Tipps.

Zum Buch

"Working Effectively with Legacy Code" von Michael Feathers, 2004 Prentice Hall, ISBN: 978-0-1311-7705-5, 434 Seiten, Englisch