Technische Schulden und Refactoring: sichtbar machen, dann tilgen
Technische Schulden und Refactoring: sichtbar machen, dann tilgen
Artikel-Übersicht
„Der Code ist schlecht" ist keine Aussage, mit der man Budget bekommt. „Diese Änderung kostet drei Tage statt einem, seit achtzehn Monaten, bei zwölf Änderungen im Jahr" schon. Dieser Artikel behandelt technische Schulden als das, was die Metapher verspricht: eine Größe mit Betrag, Zins und Tilgungsentscheidung. Er erklärt zuerst die Metapher und ihre vier Ausprägungen, zeigt dann vier messbare Größen, mit denen sich Schulden tatsächlich sichtbar machen lassen — und eine Methode, die aus Änderungshäufigkeit und Komplexität die teuersten Stellen findet. Es folgt eine Beispielrechnung fürs Managementgespräch. Der zweite Teil behandelt Refactoring als Tilgung: die Definition, an der die meisten Artikel unscharf werden, Tests als Voraussetzung, drei Wege der Einplanung und die Entscheidungsregel zwischen Refactoring und Neuschreiben.
Was sind technische Schulden?
Technische Schulden sind der zukünftige Mehraufwand, den eine heute gewählte Abkürzung erzeugt.
Die Metapher stammt von Ward Cunningham, der sie 1992 formulierte — nicht von Martin Fowler, dem sie regelmäßig zugeschrieben wird. Cunninghams ursprüngliche Idee war dabei subtiler, als sie meist wiedergegeben wird: Er meinte nicht schlechten Code, sondern Code, der ein noch unvollständiges Verständnis der Fachlichkeit widerspiegelt. Man liefert früh und zahlt später den Aufschlag, weil man beim Bauen dazugelernt hat.
Wer die Metapher ernst nimmt, muss sie zu Ende denken:
| Finanzbegriff | Entsprechung in der Software |
|---|---|
| Betrag | Aufwand, um die Abkürzung zu beseitigen |
| Zins | Mehraufwand bei jeder Änderung, solange sie besteht |
| Tilgung | Refactoring |
| Bonität | wie gut das Team überhaupt in der Lage ist zu tilgen |
Der Zins ist der entscheidende Begriff. Eine Schuld in einem Bereich, den niemand mehr anfasst, kostet nichts — sie ist zinsfrei. Dieselbe Schuld in einem Bereich, der wöchentlich geändert wird, kostet jede Woche. Deshalb ist nicht der schlechteste Code das Problem, sondern der schlechteste Code an der meistgeänderten Stelle.
Die vier Arten
Martin Fowler hat die Schulden in einem Quadranten geordnet, der bis heute die brauchbarste Einteilung ist:
| Umsichtig | Leichtsinnig | |
|---|---|---|
| Bewusst | „Wir liefern jetzt und räumen im nächsten Quartal auf." | „Für Entwurf haben wir keine Zeit." |
| Unbewusst | „Jetzt wissen wir, wie es hätte aussehen müssen." | „Was ist Schichtentrennung?" |
Die wichtigste Erkenntnis daraus: Bewusst-umsichtige Schulden sind eine legitime Projektentscheidung. Wer weiß, dass er eine Abkürzung nimmt, warum er sie nimmt und was sie später kostet, handelt vernünftig. Das Feld links oben ist kein Versagen.
Das Feld rechts unten ist ein Kompetenzproblem und nicht durch Refactoring zu lösen. Das Feld links unten ist der Normalfall in jedem lernenden Projekt.
Sichtbar machen
Hier trennt sich Klage von Argument. Vier Größen, die tatsächlich messbar sind:
Änderungsaufwand je Bereich. Aus der Versionshistorie ablesbar: Welche Dateien werden bei einer typischen Anforderung angefasst? Wenn eine einfache fachliche Änderung regelmäßig zwölf Dateien berührt, ist das eine Zahl, die niemand bestreiten kann.
Fehlerdichte je Modul. Fehler aus dem Ticketsystem den Bereichen zuordnen. Bereiche, die überproportional viele Fehler erzeugen, sind Schuldenschwerpunkte.
Dauer bis zum grünen Testlauf. Wie lange dauert es vom Commit bis zur Rückmeldung? Diese Zahl steigt schleichend und ist einer der zuverlässigsten Indikatoren für strukturelle Probleme.
Anzahl der Stellen, die eine typische Änderung berührt. Verwandt mit der ersten Größe, aber pro Anforderung statt pro Datei — und damit die Zahl, die dem Management etwas sagt.
Was nicht taugt: reine Metrikwerte ohne Bezug zur Änderungslast. Eine hohe zyklomatische Komplexität in einer Datei, die seit vier Jahren niemand angefasst hat, ist kein Problem. Werkzeuge, die eine Gesamtnote für die Codebasis ausgeben, verleiten genau zu diesem Fehler.
Die Methode: Änderungshäufigkeit gegen Komplexität
Die wirksamste Auswertung braucht nichts als die Versionshistorie:
# Wie oft wurde jede Datei im letzten Jahr geändert?
git log --since="1 year ago" --name-only --pretty=format: \
| grep -v '^$' | sort | uniq -c | sort -rn | head -30Diese Liste stellt man der Komplexität oder schlicht der Dateigröße gegenüber. Es entsteht ein Streudiagramm mit vier Feldern:
- Selten geändert, einfach — uninteressant.
- Selten geändert, komplex — zinsfreie Schuld. Nicht anfassen.
- Oft geändert, einfach — gesund, so soll es sein.
- Oft geändert, komplex — hier liegt das Geld.
Das letzte Feld enthält meist zwei bis fünf Dateien. Genau die sind die Antwort auf die Frage „wo fangen wir an".
Dem Management erklären
Der Fehler in diesem Gespräch ist fast immer die Sprache. „Der Code ist unwartbar" ist eine Meinung. Eine Rechnung ist ein Argument:
Das Modul Rechnungsprüfung wurde in den letzten zwölf Monaten 47-mal geändert. Eine durchschnittliche Änderung kostet dort 2,5 Tage; in vergleichbaren Modulen sind es 0,8 Tage. Der Mehraufwand beträgt damit rund 80 Personentage im Jahr. Die geschätzte Bereinigung kostet 25 Personentage. Sie amortisiert sich nach etwa vier Monaten.
Diese Rechnung hat vier Eigenschaften, die sie tragfähig machen: Sie nennt einen Bereich statt „den Code", sie vergleicht mit einem Referenzwert, sie beziffert den laufenden Verlust, und sie nennt einen Amortisationszeitpunkt.
Sie ist außerdem angreifbar — die Schätzungen sind Schätzungen. Das ist kein Nachteil: Ein angreifbares Argument ist eines, über das man reden kann.
Refactoring: die Tilgung
Refactoring ist die Änderung der inneren Struktur eines Systems, ohne sein äußeres Verhalten zu ändern.
An dieser Definition werden die meisten Artikel unscharf, und der Unterschied ist praktisch relevant: Wer Verhalten ändert, refaktoriert nicht — er baut um. Beides ist legitim, aber nur das erste ist durch Tests absicherbar, und nur das erste darf ohne fachliche Abstimmung passieren.
Zur häufig gestellten Übersetzungsfrage: Eine gute deutsche Entsprechung gibt es nicht. „Umstrukturierung" trifft es halb, verliert aber die Zusicherung der Verhaltensgleichheit. In der Praxis sagt jeder Refactoring.
Tests sind die Voraussetzung
Ohne Testabdeckung ist Refactoring Raten. Man ändert die Struktur und hofft, dass sich das Verhalten nicht geändert hat.
Für Systeme ohne Tests gibt es einen etablierten Ausweg: Charakterisierungstests. Sie beschreiben nicht, was der Code tun soll, sondern was er tatsächlich tut — einschließlich der Merkwürdigkeiten. Man ruft die Funktion mit repräsentativen Eingaben auf, schreibt das Ergebnis als erwarteten Wert fest und hat damit ein Netz, das Änderungen im Verhalten sichtbar macht.
Der Begriff stammt von Michael Feathers, und die Vorgehensweise fühlt sich zunächst falsch an, weil man auch fehlerhaftes Verhalten festschreibt. Genau das ist aber der Punkt: Man will beim Refactoring nichts ändern, auch keine Fehler. Deren Korrektur ist ein eigener, separater Schritt.
Wie man es einplant
Drei Wege, alle im Einsatz:
Fester Anteil je Iteration. Zum Beispiel zwanzig Prozent der Kapazität. Vorteil: verlässlich. Nachteil: wird als Erstes gestrichen, wenn es eng wird — und es wird immer eng.
Eigene Aufgaben im Rückstand. Refactoring als sichtbarer Posten neben Funktionen. Vorteil: verhandelbar und priorisierbar. Nachteil: konkurriert mit Funktionen und verliert regelmäßig.
Pfadfinderregel. Jede Änderung hinterlässt den berührten Bereich etwas besser. Vorteil: braucht keine Genehmigung und trifft automatisch die meistgeänderten Stellen — genau die, wo der Zins am höchsten ist. Nachteil: reicht nicht für strukturelle Probleme.
Meine Empfehlung ist die Kombination: Pfadfinderregel als Grundhaltung für den Alltag, plus zwei bis drei ausdrücklich eingeplante Vorhaben im Jahr für die Stellen aus dem Streudiagramm.
Was in Scrum-Teams zusätzlich hilft, ist eine Definition of Done, die Qualitätsanforderungen enthält — dann ist ein Teil der Tilgung nicht verhandelbar. Wie die Artefakte zusammenspielen, steht in Scrum: Rollen, Artefakte und was im Alltag davon ankommt.
Refactoring oder neu schreiben?
Die Frage, bei der die meisten Bauchentscheidungen fallen. Fünf Kriterien:
| Kriterium | Spricht für Refactoring | Spricht für Neubau |
|---|---|---|
| Fachwissen im System | viel, undokumentiert | wenig, gut dokumentiert |
| Stabilität der Fachlichkeit | stabil | ändert sich ohnehin grundlegend |
| Testabdeckung | vorhanden oder herstellbar | nicht herstellbar |
| Technologiebasis | wird noch unterstützt | abgekündigt, keine Fachkräfte |
| Parallelbetrieb | nicht nötig | tragbar über die Bauzeit |
Und der Erfahrungssatz, der in fast allen Fällen zutrifft: Der Neubau dauert länger als geschätzt und liefert weniger als erhofft. Der Grund ist immer derselbe — im Altsystem stecken hunderte Sonderfälle, die niemand aufgeschrieben hat. Diese Sonderfälle sind die eigentliche Spezifikation, und sie werden erst sichtbar, wenn der Neubau in Produktion geht und Dinge nicht mehr funktionieren, die vorher niemand erwähnt hat.
Wenn die Entscheidung dennoch auf Ablösung fällt, ist der schrittweise Weg dem Big Bang deutlich überlegen — beschrieben in Legacy-Software modernisieren, ohne das System anzuhalten.
Qualitätssicherung im Alltag
Drei Werkzeuge, die vorbeugend wirken:
Statische Analyse findet Muster, die erfahrungsgemäß Probleme machen. Der Nutzen steht und fällt mit der Konfiguration: Ein Werkzeug mit tausend aktivierten Regeln erzeugt tausend Warnungen und wird ignoriert. Zehn Regeln, die tatsächlich durchgesetzt werden, sind mehr wert.
Codereview ist die wirksamste Einzelmaßnahme gegen neue Schulden — vorausgesetzt, es geht um Struktur und nicht um Formatierung. Formatierung gehört einem Werkzeug, nicht einem Menschen.
Testabdeckung als Trend, nicht als Zielwert. Eine Zielvorgabe von achtzig Prozent erzeugt Tests, die Zeilen ausführen ohne etwas zu prüfen. Eine sinkende Abdeckung über drei Monate ist dagegen ein echtes Signal.
Auch der Architekturteil lässt sich prüfen: Zwei Regeln im Testlauf, die verbotene Abhängigkeiten rot färben, verhindern strukturellen Verfall wirksamer als jedes Dokument — Beispiele dafür stehen in Clean Architecture.
Ein Punkt, der neu dazugekommen ist: KI-Assistenten erzeugen schnell viel Code. Das verschiebt den Engpass vom Schreiben zum Prüfen — und wer die Prüfzeit nicht mitplant, nimmt Schulden in einem Tempo auf, das vorher nicht möglich war. Was sich dadurch an der Arbeit ändert, behandle ich in KI-Coding-Assistenten im Vergleich.
Häufige Fragen
Was versteht man unter technischen Schulden? Den zukünftigen Mehraufwand, den eine heute gewählte Abkürzung erzeugt. Die Metapher stammt von Ward Cunningham und umfasst Betrag, Zins und Tilgung.
Was ist Refactoring? Die Änderung der inneren Struktur ohne Änderung des äußeren Verhaltens. Wer Verhalten ändert, baut um — das ist etwas anderes.
Wie misst man technische Schulden? Über Änderungsaufwand je Bereich, Fehlerdichte, Dauer bis zum grünen Testlauf und die Anzahl berührter Stellen je Anforderung. Reine Metrikwerte ohne Bezug zur Änderungslast taugen nicht.
Wie erklärt man technische Schulden dem Management? In Zahlen: betroffener Bereich, Änderungshäufigkeit, Mehraufwand gegenüber einem Referenzwert, Bereinigungsaufwand, Amortisationszeit.
Wann refaktorieren, wann neu schreiben? Refactoring, wenn viel undokumentiertes Fachwissen im System steckt und die Fachlichkeit stabil ist. Neubau nur bei abgekündigter Technologiebasis und tragbarem Parallelbetrieb — und mit dem Wissen, dass er länger dauert als geschätzt.
Wie plant man Refactoring ein? Pfadfinderregel als Grundhaltung plus zwei bis drei ausdrücklich eingeplante Vorhaben im Jahr für die strukturellen Stellen.
Zusammenfassung und praktische Tipps
Technische Schulden sind eine betriebswirtschaftliche Größe, und wer sie so behandelt, bekommt Budget dafür. Die wichtigsten Punkte:
- Der Zins ist wichtiger als der Betrag. Schulden an selten geänderten Stellen kosten nichts.
- Bewusst eingegangene Schulden sind legitim — solange jemand sie aufschreibt.
- Änderungshäufigkeit gegen Komplexität findet die teuersten Stellen mit einem einzigen Befehl.
- Rechne, statt zu klagen. Bereich, Häufigkeit, Mehraufwand, Amortisation.
- Refactoring ändert kein Verhalten. Ohne Tests ist es Raten; Charakterisierungstests sind der Ausweg.
- Der Neubau dauert länger und liefert weniger — die Sonderfälle im Altsystem sind die eigentliche Spezifikation.
- Testabdeckung als Trend lesen, nicht als Zielwert.
Mein Rat für den Einstieg: Lass den git log-Befehl von oben einmal über euer Projekt laufen und stell die dreißig meistgeänderten Dateien ihrer Größe gegenüber. Diese Auswertung dauert zehn Minuten und liefert dir eine Liste von zwei bis fünf Dateien, an denen euer Team dieses Jahr die meiste Zeit verlieren wird. Damit hast du eine Grundlage für das Gespräch — und du hast sie mit Zahlen statt mit Gefühl.
Ressourcen
- Ward Cunningham über die Metapher – der Urheber erklärt, was er ursprünglich meinte
- Technical Debt Quadrant – Martin Fowlers Einteilung in vier Felder
- Refactoring – Martin Fowler – Katalog der Refactoring-Techniken
- Working Effectively with Legacy Code – Michael Feathers zu Charakterisierungstests