Zum Thema Legacy Code gibt es schon wirklich sehr viele Artikel und Bücher und dennoch ist es immer wieder ein großes Thema, wie damit umgegangen werden soll. Auch ich habe mich im Beitrag Wie gehe ich mit Legacy Code um mit diesem Thema beschäftigt. Es gibt neben dem technischen, aber auch noch einen menschlichen Aspekt. Diesen möchte ich in diesem Artikel beleuchten.

Technisch gesehen ist das Thema Legacy Code im Grunde recht einfach. Es gilt Zyklen zu finden und diese aufzulösen. Klare Schnittstellen wollen geschaffen werden, vor allem auch, nicht nur um zu entkoppeln, sondern auch automatisiert testen zu können. Mit kleinen Änderungen soll begonnen werden, aber irgendwann dann ist alles gut.

Große Projekte – lange Historie

Wer einmal an richtig großen, über viele Jahre gewachsenen, Projekten mitgearbeitet hat, der weiß, was da alles dahintersteckt. Da geht es nicht nur um Sourcecode, Architektur und Patterns. Es geht um Menschen, deren Geschichten, Sympathie oder Antipathie, Teamgeist oder aber auch Egoismus. Wer sich durchsetzt, prägt das Projekt. Auf Seiten der Entwicklung können mindestens folgende Typen identifiziert werden:

Der Nerd

Er sucht nach neuen Libraries, Tools und Frameworks und integriert dies in kürzester Zeit ins Projekt. Damit werden in bestimmten Bereichen zwar schnelle Fortschritte erzielt (mit denen er im Management punktet), die Fertigstellung muss allerdings durch andere passieren, da bereits das nächste neue “Thing” wartet.

Der Enterprise-Architekt

Jeder mögliche Fall wird durch den Enterprise-Architekten entlarvt und in ein Software-Design gepresst. Nichts wird dem Zufall überlassen. Das Projekt wird dadurch komplex, dafür ist für alle Eventualitäten vorgesorgt. Wird etwas doch nicht gebraucht, dann hat man es zumindest doch berücksichtigt, denn irgendwann, ja irgendwann, braucht es bestimmt jemand. Ganz sicher.

Der Dampfplauderer

Ideen gibt es viele und auch vieles davon ist bereits in Umsetzung und was nicht gerade in Umsetzung ist, wird gerade geplant und auf Papier gebracht. Doch nichts davon wird jemals konkret definiert sein und dem Projekt weiterhelfen. Es dreht sich alles um den positiven Schein der eigenen Person. Die Entwickler sind sich selbst überlassen.

Keiner der angesprochenen Typen bleibt ewig. Sie widmen sich entweder neuen Themen, oder verlassen das Unternehmen um neue Chancen wahr zu nehmen. Übrig bleiben diejenigen, die mit den angehäuften “Schulden” umgehen müssen.

Aufarbeitung der Schulden

Anleitungen zur Aufarbeitung der Schulden gibt es viele. In der Regel beschreiben sie jedoch nur die ideale Herangehensweise. In der Praxis ist das allerdings weit komplizierter. Warum?

Projektdruck

Besonders negativ wird sich Projektstress auf die Entwicklung aus, vor allem, wenn es schon eine Menge technischer Schulden gibt und das Entwicklungsteam dadurch bereits mit besonderen Herausforderungen zu kämpfen hat. Dabei ist es in der Regel irrelevant, wodurch dieser Stress/Druck entsteht (Planung, mangelndes Anforderungsmanagement, übertriebene Architekturen/Umsetzungen in der Entwicklung). Je höher der Produktcharakter des “Projektes” umso mehr (unterschiedliche) Kundenanforderungen beeinflussen die Umsetzung. Wenn diesbezüglich keine klaren Vorgaben bestehen (und von Beginn an umgesetzt wurden), entsteht schnell ein Wildwuchs an Umsetzungsvarianten, der eine Pflege und Erweiterung immer aufwändiger gestaltet.

Frust

Im Laufe der Jahre wird Software (wenn nicht permanent entgegengesteuert wird) immer komplexer und die Wartung sowie Integration neuer Features immer langwieriger. Ich definiere Legacy Code als Code, der nicht durch automatisierte Tests abgesichert ist. Änderungen und Erweiterungen bringen somit unerkannt Probleme an zuvor funktionierenden Stellen mit sich. Durch das Fehlen von Tests fällt das natürlich nicht sofort auf. Je nach Größe und Komplexität der Software fällt ein etwaiges Problem erst beim Kunden auf und muss dann unter Zeitdruck behoben werden. Das artet in Stress und über einen längeren Zeitraum in Frust aus. Frust motiviert bekanntlich nicht und schon befindet man sich in einer Teufelsspirale, aus der es kaum ein Entrinnen gibt.

Oftmals müssen sich Entwickler auch mit Problemen herumschlagen, für die sie sich nicht verantwortlich fühlen, weil sie frühere Entscheidungen nicht mitgetragen haben weil sie noch nicht teil des Entwicklungsteams waren oder aber überstimmt wurden.

Dem Frust folgt langsam aber sicher Resignation und die oft zitierte innere Kündigung. Gerne auch von der tatsächlichen Kündigung gefolgt. Das Projekt beginnt unter einer hohen Fluktuation an Entwicklern zu leiden.

Schwindendes Know-how

Eine hohe Fluktuation bedeutet zwangsweise auch einen hohen Schwund an Know-how. Wenn wir von ausgeprägtem Legacy Code sprechen, dann finden wir in der Regel auch ganz selten eine wirklich gute technische Dokumentation. Ich kenne Projekte, die mit einer ordentlich beschriebenen Architektur gestartet sind, aber getroffene Entscheidungen wurden nicht mehr ausreichend dokumentiert und konnten daher zu einem späteren Zeitpunkt durch die anwesenden Entwickler nicht mehr nachvollzogen werden. Das ist ein großes Problem, gerade wenn das vorgefundene Design merkwürdig erscheint und die Funktionsweise nicht eindeutig nachvollzogen werden kann.

Ängstlichkeit

Bei großen und komplexen Systemen können Änderungen sehr schnell negative Auswirkungen an zuvor funktionierenden Stellen haben. Mangels automatisierter Tests kann dies nur mit aufwändigen manuellen Tests festgestellt werden. Auf der Strecke bleiben mangels zeitlichem Aufwand Spezialfälle und selten benutzte Funktionalitäten. Probleme tauchen daher erst beim Kunden auf und hinterlassen dort den Eindruck einer instabilen bzw. unprofessionell entwickelten Software. Zudem müssen etwaige Probleme schnell behoben werden und wieder zum Kunden gelangen (der Testaufwand bezieht sich hier dann gerne auf den durchgeführten Fix – aus Zeitmangel – verständlich). Dies führt zur Angst vor Veränderung/Modernisierung und blockiert daher. Es manifestiert sich ein defensives Verhalten. Das ist absolut nachvollziehbar, man will ja nicht noch tiefer in den Sumpf, verhindert aber das beherzte Angreifen und aktive Verändern. Und nur Veränderung kann auch Verbesserung bringen.

Menschliche Herausforderung

Der Umgang mit Legacy Code ist also nicht bloß eine technische Herausforderung, sondern auch eine menschliche. Neben einer hohen Motivation und Frustresistenz muss selbst in stressigen Zeiten Ruhe bewahrt werden. Das höchste Ziel muss es sein, die Situation nicht noch zusätzlich verschlechtern, selbst wenn ein weiterer Workaround eigentlich gar nicht mehr ins Gewicht fallen würde.

Zusätzlich braucht es jede Menge Mut zur Veränderung. Kleine Rückschläge dürfen nicht für Verunsicherung sorgen. Das sagt sich leichter als es umgesetzt werden kann und genau hierbei sehe ich das wahre Problem an Legacy Code.

Der ständige Spagat zwischen “Das alles muss bis xx.xx fertig sein” und “Wenn wir hier nicht eine Änderung herbeiführen, dann wird es niemals besser” ist nicht einfach zu bewerkstelligen.

Deine Erfahrung?

Für mich ist es essentiell, alle Beteiligten immer wieder zu motivieren und anzuhalten, im schlimmsten Fall die “technischen Schulden” stabil zu halten, also zumindest keine Verschlechterung zuzulassen. Ein Allheilmittel hätte ich allerdings noch nicht gefunden, denn Frust oder eine zeitweise Aussichtslosigkeit (gerade wenn mehrere Probleme auftreten, oder Projektstress herrscht) kann schnell zuschlagen und nicht alle können (auf Dauer) damit gut umgehen.

Wie ist deine Erfahrung mit diesem Thema? Wie gehst du mit den menschlichen Herausforderungen zum Thema Legacy Code um? Welche Wege hast du, andere zu motivieren? Habt ihr Mechanismen etabliert, um auch in Extremsituationen die technischen Schulden nicht noch weiter zu erhöhen?

Wenn du dazu eine Meinung oder Erfahrungen hast, bitte ich dich um ein paar Minuten deiner Zeit für einen Kommentar.

Updates
23.02.2017: “Ängstlichkeit” hinzugefügt

Veröffentlicht von Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.

Beteilige dich an der Unterhaltung

4 Kommentare

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

  1. Ein guter Blogpost, der die menschliche Seite auf den Punkt bringt!

    Um damit umzugehen, fallen mir drei Sachen ein (aus eigener, bitterer Erfahrung):
    1. Die effektivste Methode, um sich im Legacy Code zurechtzufinden, ist die zu fragen, und sich neben diejenigen zu sitzen, die ihn gemacht haben. Es wäre zwar schöner, wenn etwas dokumentiert wäre, aber mündlich kommt man zehnmal schneller voran als alleine. Das hat außerdem den Vorteil, dass der “alte Entwickler” einen akzeptieren Status von dem “neuen Entwickler” bekommt, womit mehr Frieden im Team herrscht.

    2. Wenn im Team so viele Charaktere vorhanden sind, die alle in andere Richtungen ziehen, dann hängt es gar nicht so stark an den Problemen des Legacy Codes, sondern daran, dass sie sich gegenseitig noch nicht anerkannt haben, und noch nicht als Team funktionieren. Wenn sie sich nie einig werden, dann verlassen einige im Extremfall das Team, und danach geht es besser.

    3. Es sollten gar nicht so viele Personen an einem Legacy Projekt arbeiten, vor allem, wenn sie sich uneinig sind. Viele Köche verderben den Brei noch mehr. In dem Fall ist weniger mehr.

  2. Wenn der gefürchtete Legacy Code sich dadurch definiert, dass kein automatisiertes Testing dafür existiert, dann kann man die Tests auch im Rahmen der Erweiterung nachschreiben. Das Änderungen und Ergänzungen so länger dauern und teurer werden kann man den altvorderen Verantwortlichen dann auch bitteschön mit dem beharren auf dem Erbe verkaufen. Wenn es nicht möglich ist, das Testing nachträglich einzubauen, ist der Code ohnehin eine Zeitbombe.

    Ich hatte schon Projekte, wo ich in einer ähnlichen Situation mit dem Kopf durch die Wand ein Refactoring durchgesetzt habe (und das in der gefährlichen Position als Freiberufler). Das hat einen ganzen Rattenschwanz an Verzögerungen in einem Migrationsprozess nach sich gezogen, aber letztlich hat es denselben insgesamt immens beschleunigt.

    1. Schuldzuweisungen sind wenig hilfreich und sorgen zudem auch noch für schlechte Stimmung. Die eine Seite ist die technische Umsetzung (Schreiben von Tests, Refactorings, Anpassungen an der Architektur) und die zweite Seite – und das versuchte ich in diesem Beitrag hervorzuheben – ist der Mensch und sämtliche Contraints, die auf ihn einprasseln, während er aufgelaufene Probleme lösen soll.

      Mit dem Kopf durch die Wand ist nicht immer möglich (Projekttermine, Pönalen etc.), allerdings besteht eine Erwartungshaltung, die so aber nicht erfüllt werden kann. Das wirkt sich schon massiv auf die Betroffenen aus. Ergo ist nicht nur der ungetestete Legacy Code eine Zeitbombe …

  3. Als Techniker tut man gut daran etwaige Verschnaufpausen zwischen Projektterminen konsequent für die Erweiterung von automatisierten Tests und den gelegentlichen Angriff auf besonders “schmerzhafte Stellen” im Code zu nutzen. Schön ist es, wenn diese Einstellung vom gesamten Developer Team vertreten wird :)

Cookie-Einstellungen
Auf dieser Website werden Cookie verwendet. Diese werden für den Betrieb der Website benötigt oder helfen uns dabei, die Website zu verbessern.
Alle Cookies zulassen
Auswahl speichern
Individuelle Einstellungen
Individuelle Einstellungen
Dies ist eine Übersicht aller Cookies, die auf der Website verwendet werden. Sie haben die Möglichkeit, individuelle Cookie-Einstellungen vorzunehmen. Geben Sie einzelnen Cookies oder ganzen Gruppen Ihre Einwilligung. Essentielle Cookies lassen sich nicht deaktivieren.
Speichern
Abbrechen
Essenziell (1)
Essenzielle Cookies werden für die grundlegende Funktionalität der Website benötigt.
Cookies anzeigen