In the Code: Refactoring - Chance oder Schrecken?

Der CTO von Ergon schreibt in seinem Gastbeitrag über die Schwierigkeiten beim Refactoring und Redesign.
 
Als Softwaredienstleister lieben wir erfolgreiche Projekte. Der Kunde hat die Software erfolgreich live geschaltet, der Prosecco der Releaseparty ist ausgetrunken und die Entwickler freuen sich auf eine etwas ruhigere Zeit.
 
Bei vielen Projekten bleibt es hoffentlich nicht bei dem einen Release. Vielleicht stehen neue Features an, die aus Zeitgründen keinen Platz im letzten gefunden haben. Vielleicht sind einige Komponenten so gut gelungen, dass wir sie in einem ähnlichen Projekt erneut verwenden und erweitern können. Und vielleicht ist die Lösung sogar so gut, dass wir sie zu einem Produkt ausbauen und entsprechend vermarkten wollen. Auf den ersten Blick sollte das kein Problem sein. Die Software wurde schliesslich mit hohen Qualitätsansprüchen gebaut, hat keine bekannten Fehler und läuft robust und ausreichend schnell.
 
Stinkender Code
Die Erfahrung zeigt leider, dass auch eine nach allen gängigen Kriterien erfolgreiche Softwarelösung nicht automatisch für einen neuen Kontext geeignet ist. Eine solche Wiederverwendung wird praktisch nie im Voraus geplant - und selbst wenn eine entsprechende Vision einmal vorhanden war, wurde sie vermutlich aus pragmatischen Gründen zurückgestellt. Meist suchen die Entwickler darum nach einer Lösung, die möglichst bald zu sichtbaren Resultaten führt. Tatsächlich unterstützen viele moderne Frameworks genau einen solchen Ansatz, bei dem sich mit wenig Aufwand eine vollständige Applikation bauen lässt, allerdings auf Kosten von Flexibilität und Erweiterbarkeit. Eine ambitioniertere Architektur mit langfristigem Fokus hätten weder der Kunde noch das eigene Management finanzieren wollen - aus gutem Grund, denn die meisten angeblich zukunftsträchtigen Lösungen stellen sich allen Bemühungen zum Trotz beim zweiten Einsatz als weniger brauchbar als erhofft heraus.
 
Normalerweise klappt es trotzdem, die Software mehrfach zu verwenden. Wir nehmen einfach in Kauf, dass gewisse Dinge im Design mit der Zeit nicht mehr ganz passen. Mit fortschreitender Anzahl Änderungen wird der Code weniger schlüssig und konsistent. Im Englischen gibt es dafür den schönen Begriff des "bit rot", also der Vorstellung, dass die Bits und Bytes des Codes vor sich hin gammeln und verfaulen. Der erfahrene Entwickler benutzt seine virtuelle Nase oder ein geeignetes Analysewerkzeug, um den üblen Gerüchen ("code smells") nachzugehen und die faulen Stellen herauszuschneiden, ohne dabei die Funktionalität zu verändern. Martin Fowler hat diesen Prozess in seinem Klassiker "Refactoring" detailliert und humorvoll beschrieben.
 
Das klassische Refactoring gehört zur alltäglichen Arbeit am Code. Entwickler unterstützen es massgeblich durch selbst erstellte, automatisierte Tests. Die heutigen Entwicklungsumgebungen bieten ebenfalls Unterstützung für alle kleineren Korrekturen (z.B. Klassen und Methoden umbenennen, Basisklassen extrahieren, Methoden verschieben etc.). Allerdings verlangt es ein hohes Mass an Entwicklungsdisziplin, das Refactoring auch konsequent durchzuführen, weil es schwierig ist, die Notwendigkeit und den Effekt dieser Arbeit sichtbar zu machen. Fehler im Programm oder lange Antwortzeiten werden in der Regel schnell bemerkt, Probleme im Code-Design hingegen oft erst im Verlauf von Monaten. Vor die Wahl gestellt, ein paar Ungereimtheiten im Design zu beseitigen oder den nächsten Task in Angriff zu nehmen, wird sich mancher Entwickler für letzteres entscheiden, zumal man ihn dann vermutlich für seine sichtbar höhere Produktivität loben wird (und er für einen Effort im Refactoring im besten Fall einen Kommentar der Art "ja, ja, aber war das jetzt wirklich so wichtig?" erwarten kann). Gutes Management heisst in diesem Fall, den Entwicklern Raum für Korrekturen am Design zu lassen und eine Kultur der kontinuierlichen Verbesserung konkret zu fördern.
 
Aus der Sicht der Business-Vertreter
Selbst in einer gut gepflegten Codebasis kommt aber früher oder später der Zeitpunkt, an dem sich die Entwickler sträuben, mit dem bestehenden Design weiter zu arbeiten, weil es die Entwicklung behindert und verteuert. Gegenüber den Business-Vertretern wird von "legacy code", von "technischer Verschuldung" und ? auch hier ? von "Refactoring" gesprochen, obwohl der Begriff in diesem Fall nicht mehr viel mit routinemässigem Refactoring zu tun hat.
 
Für das Business wird der eigentliche positive Begriff des Refactoring dann zum Schreckgespenst. Nun wollen die Entwickler riskante und kostspielige Umbauten an der Software vornehmen, anstatt neue Funktionalität mit Geschäftsnutzen einzubauen! Die Entwickler haben aber bis dahin hauptsächlich die Anforderungen des Business nach neuer Funktionalität immer möglichst rasch erfüllt, und ihr Anliegen, die Codebasis geschmeidig zu behalten, zurückgestellt. Es ist darum aus ihrer Sicht durchaus legitim und auch wichtig, nun den Code besser zu strukturieren und dadurch neue Anforderungen flexibler und effizienter umsetzen zu können.
 
Hätten es die Entwickler denn nicht von Anfang an richtig machen und genau die Software bauen können, die es braucht? ? Nur in einer perfekten Welt sind alle Anforderungen von Anfang an bekannt, ändern sich nie und lassen sich mit einem schon bekannten Lösungsansatz erfüllen. In der realen Welt bauen wir Software für Probleme, die noch nie jemand in dieser Umgebung gelöst hat. Jedes Projekt hat Aspekte, die es einmalig machen. Softwareentwicklung wird dadurch zu einem Prozess, bei dem im ganzen Projektverlauf Wissen aufgebaut wird. Am klügsten sind wir dann, wenn das Projekt zu Ende ist. Viele Entscheide mussten wir aber schon zu Beginn des Projekts fällen. Darum sollte eine langfristig konzipierte Software, von der wir uns einen anhaltenden Geschäftsnutzen versprechen, die Möglichkeit beinhalten, frühere Entscheide zu korrigieren.
 
Welcher Weg?
Die Kosten-Nutzen-Analyse von grossen Umbauten (wobei wir ehrlicherweise von Redesign statt von Refactoring sprechen) ist schwierig. Während sich die Kosten noch halbwegs schätzen lassen, ist eine Beurteilung, wie stark die Produktivität ohne den Umbau gebremst wird, meistens mit viel Unsicherheit und Bauchgefühl verbunden. Die nötigen Anpassungen zu finden, in verdaubare Brocken zu stückeln und in den Entwicklungsprozess einfliessen zu lassen, ist eine Knochenarbeit, für die es kaum Alternativen gibt. Häufig ist die Versuchung da, die alte Software alte Software sein zu lassen und komplett neu zu schreiben, aber dieser Weg ist noch riskanter und kostspieliger als ein schrittweiser Umbau. Gar nichts zu tun, ist langfristig ebenfalls keine Option, weil sich die negativen Effekte mit der Zeit noch verstärken.
 
Jede langlebige Software führt also zu einem kontinuierlichen Dilemma. Investieren wir zu wenig in die Pflege der existierenden Lösung, riskieren wir, dass wir irgendwann nicht mehr schnell und flexibel auf neue Opportunitäten reagieren können, weil unsere Software zu viele Altlasten mit sich trägt. Investieren wir zu wenig in neue Fähigkeiten und Marktopportunitäten, sinkt die Rentabilität und stellt den ökonomischen Nutzen in Frage. Es ist eine komplexe Aufgabe, zu jedem Zeitpunkt im Lebenszyklus der Software die richtige Balance zu bestimmen und entsprechend zu handeln. Sowohl Entwickler als auch Auftraggeber haben dabei eine wichtige Stimme.
 
Solange es um Funktionalität geht, ist allen klar, dass die Kommunikation vom Business zu den Entwicklern erfolgen muss. Bei Refactoring und Redesign verläuft die Kommunikation in umgekehrter Richtung: die Entwickler als Experten sind gefordert, dem Business den aktuellen Zustand verständlich zu erklären und die Konsequenzen verschiedener Vorgehensweisen zu erläutern. Können die Entwickler wiederholt an konkreten Beispielen aufzeigen, welche negativen Konsequenzen die bestehende Architektur auf neue Entwicklungsarbeiten hat, lässt sich der Kunde auch überzeugen, in Umbauvorhaben zu investieren. Eine erfolgreiche und plangemässe Umsetzung hilft zudem, Vertrauen aufzubauen und Diskussionen über ähnliche Vorhaben zu vereinfachen. Schaffen es Auftraggeber und Entwickler, sich gemeinsam auf die nötigen Anpassungen zu einigen und diese erfolgreich umzusetzen, dürfen sie sich bereits auf die nächste Releaseparty freuen. (Erich Oswald)

Über den Autor
Erich Oswald ist Chief Technology Officer beim Zürcher Softwarehersteller Ergon. Zu seinen Aufgaben gehören neben der alltäglichen Entwicklung seit über zehn Jahren die Pflege des Technologieportfolios im Bereich von Java SE und Java EE sowie die Beratung von Kunden und Teams beim Einsatz von Technologie, Softwarearchitektur und agilen Entwicklungsmethoden. Erich Oswald hat seine Studien an der ETH Zürich mit einem Diplom in Informatik und einem Doktor der technischen Wissenschaften abgeschlossen.
 
(Interessenbindung: Ergon ist Technologie-Partner unseres Verlags.)