Michael Feathers: Effektives Arbeiten mit Legacy Code

Michael Feathers: Effektives Arbeiten mit Legacy Code

Michael C. Feathers
Übersetzung Reinhard Engel
Effektives Arbeiten mit Legacy Code: Refactoring und Testen bestehender Software

1. Auflage
2011, 429 Seiten, Broschur
mitp-Verlag
ISBN: 978-3-8266-9021-1

Informationen zum Buch im Katalog der Deutschen Nationalbibliothek.



Jeder Entwickler dürfte den Begriff Legacy Code kennen und jeder Entwickler hat früher oder später mit dem, was er bezeichnet, zu tun. Entsprechend wichtig ist das Thema und entsprechend hilfreich kann ein gutes Buch darüber sein.
Effektives Arbeiten mit Legacy Code ist ein praxisnahes Buch, das dicht gepacktes, hilfreiches und verständlich vermitteltes Wissen enthält und das von einem sehr erfahrenen Entwickler geschrieben wurde. Mein Fazit: Empfehlenswerte Lektüre für jeden Entwickler.


Struktur

Jeder Entwickler dürfte den Begriff Legacy Code kennen. Doch dieser wird oft mit verschiedenen Bedeutungen verwendet. Deswegen versucht Michael Feathers Legacy Code im Geleitwort zu umreißen und beginnt mit dem, was er „die strenge Definition“ nennt: „Legacy Code ist Code, den wir von jemand anderem übernommen haben“ (S. 16 – kursive Hervorhebung im Original), um Schritt für Schritt zu einer eigenen (und vielleicht auch etwas eigenwilligen) Definition zu gelangen: „Für mich [Feathers – Anm. des Rezensenten] ist Legacy Code ganz einfach Code ohne Tests“ (S. 16 – kursive Hervorhebung im Original). Der Autor begründet seine Definition durch die Wichtigkeit Code einfach, schnell und sicher ändern zu können, wofür Tests einfach die wichtigste Voraussetzung sind. Entsprechend oft werden im Buch Effektives Arbeiten mit Legacy Code die Themen Testen und testfördernde Änderungen aufgegriffen.

Feathers Buch ist dreigeteilt:

  • Teil I: Wie Wandel funktioniert ist als theoretische Einleitung zum Thema zu verstehen.
  • Teil II: Software ändern stellt eine umfangreiche Sammlung konkreter Probleme, welche Legacy Code aufwirft, zusammen mit deren Lösungen, dar. Der zweite Teil hat das Format einer FAQ-Liste (Frequently Asked Questions) und soll dem Leser (bzw. dem ein konkretes Problem habender Programmierer) eine schnelle Lösung auf sein akutes Problem bieten.
  • Teil III: Techniken zur Aufhebung von Dependencies stellt einen Katalog von Refactorings dar, deren Ziel es ist, „sichere“ Änderungen (also solche, welche auch ohne verfügbaren Tests höchstwahrscheinlich den Code nicht „kaputt machen“) mit dem Ziel einfacher Tests zu schreiben, den „Legacy Code zu zähmen“ (S. 23).

Ein sehr kurzer Anhang schließt das Buch ab. Dieser beinhaltet das von Martin Fowler beschriebene Refactoring Extract Method und ein Glossar.

Inhalt

Teil I: Wie Wandel funktioniert

Der erste Teil des Buches ist kurz gehalten und bildet die theoretische Grundlage für die anderen beiden Teile.

Feathers identifiziert im ersten Kapitel Software ändern vier Hauptgründe, welche zu Änderungen in einer Codebasis führen (vgl. S. 27):

  • funktionale Erweiterungen,
  • die Notwendigkeit des Behebens von Bugs,
  • Optimierung von Design und
  • Optimierung von Ressourcen und

betrachtet deren Implikationen auf Struktur, Funktionalität und Ressourcenverbrauch.

Da Änderungen dauernd durchgeführt werden, stellt sich die Frage, wie diese risikoarm und leicht stattfinden können – ein Thema, dem im zweiten Kapitel Mit Feedback arbeiten nachgegangen wird. Tests, die „wie eine Zwinge [agieren], in die unser Code eingespannt ist“ (S. 34) sind die Antwort im Falle der Risikoarmut. Tests müssen schnell sein und genügend große Teile des Codebasis abdecken, um sinnvolles Feedback liefern zu können. Einfache(re) Änderungen können durch Aufheben von Dependencies durchgeführt werden – „Dependency ist eines der gravierendsten Probleme bei der Software-Entwicklung“ (S. 40) stellt Feathers fest.

Unterkapitel 2.4 beschreibt die notwendigen Schritte zur Änderung von Legacy Code in Form eines Algorithmus (vgl. S. 42):

  1. Änderungspunkte identifizieren
  2. Testpunkte identifizieren
  3. Dependencies aufheben
  4. Tests schreiben
  5. Änderung durchführen.

Letztendlich könnte das ganze Buch mittels dieser Begriffe zusammengefasst werden: Identifikation von Änderungspunkten, Dependencies aufheben, Tests schreiben und Refaktorisieren.

Im dritten Kapitel Überwachung und Trennung geht Feathers auf die zwei von ihm identifizierten Gründe beim Schreiben von Tests Dependencies aufzuheben ein (vgl. S. 45):

  • zum Zwecke der Überwachung, weil sich die vom Code berechneten Werte nicht abrufen lassen und
  • zum Zwecke der Trennung, weil der zu testende Code sich nicht in einem Test-Harnisch ausführen lässt.

Die Beschreibung von Fake- und Mock-Objekte runden das Kapitel ab. Es stellt sich nun natürlich die Frage, wie Test-Objekte verwendet werden können. Feathers führt dafür das Konzept der Seams ein (zu Deutsch Naht oder Nahtstelle). Seams sind Stellen, über die Verhaltensänderungen durchgeführt werden können, ohne den Code selbst zu ändern (vgl. Definition auf S. 55). Es gibt drei Arten von Seams:

  • Präprozessor-Seams – eine Eingriffsmöglichkeit die natürlich nur bei Sprachen gegeben ist, die über einen Präprozessor verfügen;
  • Link-Seams – Eingriffe finden über das Linken statt (ebenfalls in Sprachen, wo es diesen Bearbeitungsschritt gibt);
  • Objekt-Seams – macht sich die Möglichkeiten des dynamischen Bindens zu Nutze.

Im letzten Kapitel des ersten Teils werden hilfreiche Tools kurz beschrieben: Refactoring-Werkzeuge, die xUnit-Bibliotheken (JUnit, CppUnitLite, NUnit) und Ward Cunninghams Framework Fit und dessen Weiterentwicklung Fitnesse.

Teil II: Software ändern

Die zweihundertfünfzig Seiten des zweiten Teils sind – etwas vereinfacht betrachtet – eine Sammlung von Coding- und Design-Prinzipien, Programmiermuster und sonstiger Techniken, die bei der Lösung der neunzehn konkreten, beschriebenen Herausforderungen behilflich sein sollen. Die Prinzipien, Mustern und Techniken bilden zusammen mit Feathers‘ Erfahrungen, die er an vielen Stellen anbringt, und den vielen veranschaulichenden Code-Schnipseln, ein Ganzes.

Weder soll hier auf die besprochenen, konkreten Herausforderungen eingegangen werden, die im Allgemeinen in der Tradition von FAQ-Listen als Fragen formuliert werden, noch sollen alle Prinzipien und Muster hier Erwähnung finden. Beispielhaft werden einige der Herausforderungen und der Lösungen aufgelistet.

Unter den Herausforderungen sind folgende Themen zu finden (jeweils Kapitelnamen):

  • Ich habe nicht viel Zeit und ich muss den Code ändern
  • Ich muss eine Änderung vornehmen. Welche Methode sollte ich testen?
  • Dependencies von Bibliotheken bringen mich um
  • Mein Projekt ist nicht objektorientiert. Wie kann ich es sicher ändern?
  • Wie erkenne ich, dass ich nichts kaputtmache?
  • etc.

Zu den beschriebenen Mustern, Techniken und Prinzipien gehören: das Decorator Pattern, das Dependency Inversion Principle, das Test Driven Development, das Liskovsche Substitutionsprinzip, das Null Object Pattern, die Command-Query Separation, das Single-Repsonsibility Principle, das Interface Segregation Principle, das Open-Close Principle und das Pair Programming. Ein aufmerksamer Leser wird nun vielleicht die Prinzipien objektorientierten Designs, die sich hinter dem Akronym SOLID verstecken, in dieser Auflistung entdeckt haben. Und das kommt nicht von ungefähr, denn wie der Code aufgebaut ist, ist genauso wichtig wie ein schneller und robuster Build-Prozess und eine gute Testabdeckung und all das korreliert mit der Schnelligkeit und Sicherheit mit den Änderungen an Codebasen durchgeführt werden können.

Teil III: Techniken zur Aufhebung von Dependencies

Der dritte und letzte Teil enthält lediglich das lange fünfundzwanzigste Kapitel: Techniken zur Aufhebung von Dependencies. Speziell geht es um Refactoring-Techniken, die ohne verfügbare Tests risikoarm durchgeführt werden können (um im Nachhinein einfacher Tests schreiben zu können). Es werden insgesamt vierundzwanzig Refactorings präsentiert, manche davon Martin Fowlers‘ Refactoring-Katalog entnommen.

Diskussion

Martin Fowler schreibt bezüglich Legacy Code in der zweiten Auflage seines Klassikers Refactoring: Wie Sie das Design bestehender Software verbessern:

Der beste Rat, den ich geben kann, ist Michael Feathers Effektives Arbeiten mit Legacy Code […] zu lesen und den dortigen Anleitungen zu folgen. Wundern Sie sich nicht über das Alter des Buchs – die Ratschläge sind auch fast ein Jahrzehnt nach seinem Erscheinen noch gültig.

Martin Fowler. Refactoring: Wie Sie das Design bestehender Software verbessern. mitp-Verlag. 2020. – S. 95

Tatsächlich sind es eher fünfzehn Jahre seit der ersten Auflage der englischen Ausgabe von Working Effectively with Legacy Code (die deutsche Übersetzung von Refactoring nimmt Bezug auf die deutsche Übersetzung von Feathers‘ Buch, also auf den hier besprochenen Text), was allerdings nichts an der prinzipiellen Gültigkeit von Fowlers‘ Aussage ändert. Mittlerweile haben wir weitaus mehr Software und implizit mehr Legacy Code. Ein sinnvoller Umgang mit diesem ist heute entsprechend genauso wichtig wie im Jahre 2005.

Einiges hat sich jedoch geändert:

  • Die meisten Code-Beispiele des Buches sind in Java, C, C++ und in einem geringen Umfang in C# geschrieben. Alle vier Sprachen sind weiterhin relevant, auch wenn die Relevanz von C++ oder Java gegenüber 2005 gesunken ist und die von C# gestiegen ist[i]. Weitere Sprachen sind mittlerweile aber ebenfalls wichtig (oder wichtiger als noch vor fünfzehn Jahren), wie z.B. JavaScript oder Python.
  • Die Wichtigkeit von Unit-Tests dürfte heutzutage nur noch eine kleine Minderheit infrage stellen. Der Grad der Automatisierung ist ebenfalls stark gestiegen.

Michael Feathers‘ Buch dreht sich um wenige Themen: Refactoring, Aufheben von Dependencies, Schreiben von Tests, Coding-Prinzipien – doch damit trifft der Autor die Essenz von Legacy Code: Legacy Code ist unverständlicher, ungetesteter, fragiler Code, der schwer zu ändern ist und mit dem es keinen Spaß macht zu arbeiten. Doch gelingt es Feathers immer wieder überzeugend aufzuzeigen, wie sich der Code durch das Anwenden der von ihm beschriebenen Schritte „zähmen“ lässt und weswegen es sinnvoll ist ihn zu „zähmen.“

Effektives Arbeiten mit Legacy Code ist ein praxisnahes Buch, das dicht gepacktes, hilfreiches und verständlich vermitteltes Wissen enthält und das von einem sehr erfahrenen Entwickler geschrieben wurde. Mein Fazit: Empfehlenswerte Lektüre für jeden Entwickler.


[i] Für historische Werte zur Popularität von Programmiersprachen ist der TIOBE-Index eine hilfreiche Ressource.
[ii] Informationen über den Autor sind seiner Unternehmensseite entnommen.


Zum Autor

Michael Feathers hat langjährige Erfahrung als Software-Entwickler und Berater. Dabei war er für die Firmen Obtiva und Object Mentor International tätig. Aktuell ist er für sein eigenes Unternehmen R7K Research & Conveyance als Berater und Redner unterwegs[ii].

Working Effectively with Legacy Code ist sein bisher einziges Buch.


Folgende Bücher könnten Sie ebenfalls interessieren:

Petre Sora

Petre Soras Interessen sind vielfältig und befinden sich an der Schnittstelle zwischen Mensch und Informationstechnologie. Als studierter Psychologe und Software Engineer war er knappe sechs Jahre als Java-Entwickler in mehreren Unternehmen tätig. Mit der Gründung der Rezensionsplattform nososo hat er sich entschieden eigene Wege zu gehen. Petre ist als Rezensent und Verfasser von Artikeln für nososo tätig.

Schreibe einen Kommentar