This article is also available in English
Technische Schulden (Technical Debt) sind eine von Ward Cunningham geprägte Metapher, um die impliziten Kosten zukünftiger Nacharbeiten zu beschreiben, die durch schnelle und unsaubere Entscheidungen im Code verursacht werden (Technical debt - Wikipedia).
In ihrer klassischen Form beziehen sich Technische Schulden auf „nicht ganz richtigen Code, dessen Korrektur wir aufschieben” – also bewusste Abkürzungen, die kurzfristig Entwicklungszeit sparen, aber langfristig zusätzlichen Aufwand verursachen (Technical Debt: From Metaphor to Theory and Practice). Frühe Diskussionen (z.B. von Cunningham 1992 und später vom Software Engineering Institute) konzentrierten sich auf Code-Probleme: unordentlicher, übermäßig komplizierter Code, der „Zinsen” ansammelt, indem er zukünftige Änderungen erschwert (Siehe Martin Fowler über Technical Debt).
Die Definition auf schlechten Code zu beschränken, ist jedoch zu eng gefasst. Reale IT-Systeme sammeln Schulden in vielen Formen an, nicht nur im Quellcode.
Architekturen können erstarren, Infrastrukturen veralten, Tests ausgelassen werden – all das bremst die Weiterentwicklung, genau wie schlecht gepflegter Code. Tatsächlich argumentieren viele Expert:innen, dass alle langlebigen Softwaresysteme im Laufe der Zeit verschiedene Schulden ansammeln und dass Schulden auf Code-Ebene (obwohl leichter zu erkennen) nur ein Teil des Gesamtbilds sind (Kruchten-20).
Ziel dieses Beitrags ist es, den Blick auf technische Schulden über reine Codequalität hinaus zu weiten – und aufzuzeigen, welche Arten von Schulden in IT-Organisationen entstehen können und wie sie zu typischen Herausforderungen in der Entwicklung beitragen.
Ein Cartoon, der technische Schulden illustriert – eine einfache Änderung (Hinzufügen eines „neuen Fensters”) dauert ewig, wenn die zugrunde liegende Struktur instabil ist. Wie ein Haus, das durch provisorische Stützen zusammengehalten wird, kaum noch renovierbar ist, lässt sich auch eine Codebasis voller schneller Hacks nur schwer erweitern. Ursprüngliche Idee von Vincent Denial.
Überblick über Schulden in IT-Systemen
Wenn wir von Schulden in der IT sprechen, müssen wir mehr als nur unordentlichen Code berücksichtigen. Der gesamte IT-Stack – von Anforderungen, Architektur und Infrastruktur über Kommunikation und Dokumentation bis hin zu Tests und Betrieb – kann „Schulden” ansammeln, die zukünftige Arbeit belasten. Genau wie es verschiedene Arten von finanziellen Schulden gibt, erstrecken sich IT-Schulden über mehrere Bereiche. Beispielsweise sind veraltete Serverplattformen oder nicht gepatchte Bibliotheken eine Form von Infrastrukturschulden, und ein Mangel an Automatisierung bei der Bereitstellung ist eine betriebliche Schuld. All diese Schulden verursachen „Zinsen”, indem sie Betrieb, Wartung und Weiterentwicklung im Laufe der Zeit langsamer oder riskanter machen.
Eine hilfreiche Analogie ist der Vergleich von technischen Schulden mit finanziellen Schulden. Manche technischen Schulden sind wie Kreditkartenschulden – kleine Abkürzungen und Hacks (z.B. hartcodierte Fixes oder das Überspringen von Tests), die schnelle Gewinne bringen, aber hohe Zinsen ansammeln, wenn sie nicht zurückgezahlt werden.
Andere Schulden sind eher wie ein langfristiges Darlehen oder eine Hypothek – ein bewusster Kompromiss, wie die Wahl einer einfachen Architektur, um eine Deadline einzuhalten, im Wissen, dass später investiert werden muss, um sie zu skalieren.
In beiden Fällen gilt die Schuldenmetapher: Man zahlt entweder jetzt (macht es richtig) oder zahlt später mehr.
Der Schlüssel ist, dass technische Schulden über den Code hinausgehen; sie umfassen mindestens Anforderungen, Architektur, Infrastruktur, Prozesse, Tests, Sicherheit und Betrieb, die alle kurzfristig kompromittiert werden können, nur um langfristig höhere Kosten oder Aufwände zu verursachen.
Im Gegensatz zum realen Leben könnte man ein komplettes IT-System wegwerfen, was dazu führt, dass (die meisten oder alle) Schulden verschwinden. Schade, dass das mit deiner Bank und deiner frisch gekauften Wohnung nicht funktioniert.
Kategorien von Schulden in IT-Systemen
Lasst uns technische und andere Schulden in IT-Systemen in mehrere Kategorien unterteilen.
Obwohl dieses Diagramm viele Abhängigkeiten enthält, habe ich mich entschieden, nur diejenigen zu zeigen, die ich für am wichtigsten halte. Da unser Problemraum unendlich ist, werden sicherlich Probleme auftreten, die man nicht leicht in die gezeigten Kategorien einordnen kann. Das Diagramm soll ein breites Spektrum umreißen, ohne Anspruch auf Vollständigkeit zu erheben.[1]
Anforderungsschulden
Definition: Anforderungsschulden entstehen durch Mängel bei der Anforderungsermittlung, der Kommunikation von Anforderungen oder den Anforderungen selbst. Solche Schulden führen oft zu einer Diskrepanz zwischen dem, was Stakeholder benötigen, und dem, was das Entwicklungsteam tatsächlich gebaut hat (siehe Why Product Owners Must Prioritize Managing Technical Debt?).
Dies kann passieren, wenn Anforderungen unvollständig, vage oder häufig wechselnd sind (z.B. durch Änderung der Produktrichtung oder ausufernden Scope-Creep). Wenn man durch die Anforderungsermittlung hastet – vielleicht um schnell ein MVP zu veröffentlichen – implementiert man möglicherweise Funktionen, die nicht ganz den tatsächlichen Benutzeranforderungen entsprechen oder nicht mit Blick auf die Zukunft gebaut sind.
Diese „Lücken” oder Defizite in den Anforderungen werden zu Schulden: Man muss das Produkt später (manchmal umfassend) überarbeiten oder anpassen, um es mit den tatsächlichen Anforderungen in Einklang zu bringen.
Klassische Beispiele für Anforderungsschulden sind:
- fehlende Qualitätsanforderungen (wie Performance, Kapazität oder Ähnliches (z.B. Antwortzeit < 200ms), siehe Q42 für mehrere Beispiele).
- fehlende oder unvollständige Beschreibungen von Sonderfällen: Wenn Ihr Anwendungsfall nur den Happy Path erklärt, aber Grenz- oder Spezialfälle auslässt.
- fehlende Stakeholder: Bestimmte Personen oder Organisationen wurden einfach nicht nach ihren Anforderungen an das betrachtete System gefragt.
- unvollständiges, fehlendes oder Domänenwissen
- widersprüchliche Stakeholder-Erwartungen (eine Person verlangt hohe Sicherheitsstufen mit strengen rechtlichen Freigabeprozessen, andere benötigen hohe Liefergeschwindigkeit)
Mein persönlicher Worst Case bei Anforderungsschulden ist die fehlende „Gesamtvision”, auch North Star oder Desired Outcome genannt: Wenn Entwicklungsteams von nur kleinteiligen Anforderungen ohne übergeordnetes Ziel oder Vision überwältigt werden, können sie den Wald vor lauter Bäumen nicht mehr sehen.
Code- und Designschulden
Definition: Code- und Designschulden beziehen sich auf schlechten Code und Implementierungsabkürzungen, wie verworrenen Spaghetti-Code, fehlende Modularität, doppelte Logik oder zu stark gekoppelte Komponenten. Solche Konstrukte machen Codebasen schwer verständlich und wartbar.
Diese Probleme entstehen oft durch das Überstürzen von Features oder das Umgehen etablierter guter Praktiken. Im Laufe der Zeit sammelt sich der interne „Cruft” des Codes (um Martin Fowlers Begriff zu verwenden) an und erhöht den Aufwand, der für das Hinzufügen oder Ändern von Funktionen erforderlich ist (siehe Martin’s Post über Technical Debt).[2]
Im Wesentlichen ist die zusätzliche Zeit, die Entwickler:innen mit schlechtem Code verbringen, der Zins auf Codeschulden. Wenn zum Beispiel das Hinzufügen einer neuen Funktion in einer sauberen Codebasis 2 Tage dauern würde, aber in einer unordentlichen 4 Tage, dann sind diese 2 zusätzlichen Tage die Zinszahlung dafür, dass früher nicht refaktorisiert wurde.
Ward Cunninghams ursprüngliche Metapher basierte auf dieser Idee:
„Das Ausliefern von Erstcode ist wie eine Verschuldung… Die Gefahr tritt auf, wenn die Schulden nicht zurückgezahlt werden”, was zu Zinseszinsen in Form von langsamen, schmerzhaften Verbesserungen später führt. (Wikipedia).
Ich bin ziemlich sicher, dass die meisten von euch/uns diese Situation erlebt haben: Viele, wenn nicht die meisten Legacy-Systeme enthalten mehrere Formen solcher Codeschulden.
Stellt euch eine jahrzehntealte Unternehmensanwendung mit tausenden von Kludges und „temporären” Fixes vor. Kleine Änderungen in einem Modul brechen unerwartet Funktionen in einem anderen aufgrund enger Kopplung. Entwickler:innen haben Angst, bestimmte „fragile” Teile des Codes anzufassen. Eine solche Fragilität und die Unwilligkeit der Entwickler:innen, einen bestimmten Teil der Codebasis anzufassen, kann als Management-Trigger verwendet werden.
Eine Illustration aus der realen Welt ist die allgegenwärtige „Big Ball of Mud” Legacy-Codebasis, mit der viele Unternehmen zu kämpfen haben – beispielsweise mussten frühe Versionen des Netscape-Browsers erheblich umgeschrieben werden, weil der Code zu verworren geworden war, um ihn zu erweitern.
Architektur- oder Strukturschulden
Definition: Architekturschulden (oder Strukturschulden) beziehen sich auf zu enge oder unangemessene Kopplung (Abhängigkeiten), mangelnde Kohäsion oder Modularität oder andere strukturelle Mängel.
Es ist das „große Bild”-Äquivalent zu Codeschulden. Strukturschulden sammeln sich an, wenn Entwicklungsteams solide Architekturprinzipien für schnelle Erfolge ignorieren – zum Beispiel ein eng gekoppeltes monolithisches Design, das für eine kleine App funktioniert, aber nicht skalieren kann, oder eine überentwickelte Microservices-Architektur, die zu einem Wartungsalbtraum wird.
Im Gegensatz zu Codeschulden sind Architekturschulden oft schwer mit Code-Level-Analysewerkzeugen zu finden, können aber noch kostspiligere Konsequenzen haben (siehe Philippe Kruchten Technical Debt: From Metaphor to Theory and Practice)
Philippe Kruchten stellt fest, dass, während Schulden auf Code-Ebene leichter zu finden sind, Architekturschulden oft die höchsten Besitzkosten über die Zeit tragen (Kruchten-2020), weil sie das gesamte System durchdringen (d.h. globalen Umfang haben) und es kostspielig ist, sie zu „refaktorieren”, sobald eine Anwendung in Produktion ist.
Man kann bestimmte Arten solcher strukturellen Mängel durch die Analyse von Code-Abhängigkeiten (z.B. durch Suche nach zirkulären Abhängigkeiten) herausfinden. Aber es ist zu beachten, dass Abhängigkeiten in vielen (!) verschiedenen Formen auftreten:
- Direkte Code-Compile-Zeit-Abhängigkeiten, eine Funktion oder ein Dienst, der eine andere Funktion oder einen anderen Dienst aufruft. Solche Abhängigkeiten sind meist im Quellcode sichtbar.
- Laufzeitabhängigkeiten, injizierte Abhängigkeiten. Es gilt oft als gute Praxis, Compile-Zeit-Abhängigkeiten durch Laufzeitabhängigkeiten zu ersetzen, aber letztere können schwieriger zu erkennen sein.
- Laufzeitabhängigkeiten wie „ein anderes Programm muss zuerst ausgeführt werden” und ein anderer Job muss beendet sein, bevor unser starten darf.
- Abhängigkeiten, die zur Laufzeit durch Vermittler aufgelöst werden (wie Broker, Nameserver, Registry, Konfigurationsdateien oder sogar Umgebungsvariablen).
- Unsichtbare Aufrufabhängigkeiten, wie andere Programme, die Ihre öffentliche API aufrufen.
- Abhängigkeiten durch gemeinsam genutzte Infrastruktur, wie gemeinsam genutzte Datenbanken, gemeinsam genutzter Speicher oder andere Arten von Infrastruktur, die zwischen ansonsten verschiedenen Systemen geteilt werden.
- Organisatorische Abhängigkeiten, wie „eine bestimmte Person muss die Änderung genehmigen oder den PR zusammenführen”.
Andere Formen von Strukturschulden sind falsche oder unangemessene Datenmodelle: Datenmodelle, die nicht den aktuellen Anforderungen entsprechen, Tabellen- oder Spaltennamen, die keinen Bezug zu ihrem Inhalt haben (ich erinnere mich an Spaltennamen wie col-1
bis col-10
in Produktionsdatenbanken).
Die folgenden realen Beispiele verdeutlichen, wie gravierend sich Architekturschulden auf den Geschäftsbetrieb auswirken können – bis hin zum Totalausfall:
Friendster, eines der frühesten sozialen Netzwerke, wurde 2002 gegründet und wuchs innerhalb von Monaten auf über 3 Millionen Nutzer. Es wurde als monolithische PHP-Anwendung mit begrenzten Skalierungsmechanismen gebaut. Das monolithische Backend konnte nicht mit dem Wachstum des sozialen Graphen umgehen; das Datenbankdesign skalierte nicht mit den Benutzerbeziehungen. Friendster versuchte eine komplette Neuarchitektur, aber es dauerte zu lange. Als es bereit war, hatte es die kritische Masse verloren.
„Friendster brach unter dem Gewicht seiner eigenen Architektur zusammen… Sie bauten nicht für Skalierbarkeit, und ihr Code und ihre Datenbank konnten mit dem Erfolg nicht umgehen.” — John Adams, ehemaliger Site Reliability Engineer, Facebook
Wissensschulden
Definition: Wissensschulden beziehen sich auf Wissen oder Know-how, das nicht ausreichend verbreitet, kommuniziert oder bewahrt wird. Ein anderer Begriff ist fehlende oder veraltete Dokumentation.
Gerüchten zufolge mangelt es in der Realität mehreren IT-Projekten an angemessener Dokumentation. Im Gegensatz dazu verlassen sich viele andere Ingenieursdisziplinen (zum Beispiel Maschinenbau, Elektrotechnik oder Bauingenieurwesen) stark auf strukturierte und standardisierte Dokumentation.
In ihrer schlimmsten Form bedeuten Wissensschulden, dass die einzigen Personen, die sich in bestimmten Aspekten des Systems auskennen, verschwunden sind und nicht mehr zugänglich sind. Eine andere wird (ziemlich brutal) als „Truck Factor von eins” bezeichnet: Nur eine einzige Person kann bestimmte Aufgaben ausführen oder kennt bestimmte Teile des Codes. Wenn diese Person geht (oder, wie der Name andeutet, von einem Lastwagen überfahren wird), könnte die Entwicklung oder der Betrieb des Systems sofort zum Stillstand kommen.
Eine dritte Form von Wissensschulden ist zu viel und veraltete Dokumentation. Dies kann in großen oder hochbürokratischen Organisationen passieren, besonders wenn die Ziele und Vorteile von Dokumentation, Kommunikation oder Wissenstransfer unklar oder unspezifisch bleiben.
Weitere Beispiele für Wissensschulden sind:
- Mangel an Onboarding-Leitfäden oder Tutorials
- Keine Post-mortem- oder Retrospektiven-Aufzeichnungen: Nach Vorfällen oder größeren Änderungen werden keine Aufzeichnungen darüber erstellt und aufbewahrt, was schief gelaufen ist, wie es behoben wurde und welche Lehren gezogen wurden.
Randnotiz: Ich bin (Mit-)Autor und Betreuer von arc42, einem Open-Source-Framework für effiziente und pragmatische Architekturkommunikation. Wenn ein System oder Team unter Wissensschulden leidet, ist zu empfehlen, mit dem Architecture Canvas zu starten, also buchstäblich einer einseitigen Dokumentation des Systems.
Technologieschulden
Definition: Technologieschulden beziehen sich auf unangemessene Technologien oder die Verwendung falscher, veralteter oder übermäßig gehypter Technologien für eine bestimmte Aufgabe. In der Software kann dies leicht passieren, wenn Abhängigkeiten von grundlegenden Technologien (wie Frameworks, Bibliotheken oder sogar Programmiersprachen) nicht regelmäßig aktualisiert werden.
Beginnen wir mit veralteter Technologie: Beispiele dafür sind Java 6 (letztes offizielles Update 2013) oder PHP 2 (Support-Ende 1997). Während Code- oder Architekturreviews identifizieren wir regelmäßig bestimmte Abhängigkeiten als veraltet. Aber warum ist veraltete Technologie ein Problem, da selbst ein älterer Dialekt einer Programmiersprache oder Bibliothek noch läuft?
Alte oder veraltete Technologie kann Sicherheitsrisiken enthalten, da bestimmte Schwachstellen oder Angriffe möglicherweise nicht erkannt wurden, als die Technologie aktuell war. Wenn das allein nicht ausreicht, leiden ältere Technologien oft unter Leistungs- oder Stabilitätsrisiken oder sind möglicherweise nicht mit neueren oder aktuellen Betriebssystemen kompatibel. Schließlich fehlen älteren Technologien oft bestimmte Funktionen oder Merkmale, die neuere Versionen mitbringen. Stellen Sie sich vor, Sie möchten eine bestimmte Bibliothek oder ein Framework verwenden, das genau Ihr Problem löst, aber Java-20 erfordert, und Ihr System läuft nur auf Java-6.
Insgesamt reduziert das Aktuellhalten von Technologien mehrere Risiken, muss aber offensichtlich gründlich getestet werden.
Nun zum nächsten Technologieschuldenproblem: unangemessene Technologie. Natürlich können Systeme über E-Mail integriert werden, aber das fühlt sich in den meisten Fällen nicht angemessen an. Weitere Beispiele:
- Verwendung einer relationalen Datenbank zur Speicherung und Abfrage graphenähnlicher Strukturen wie Karten oder Netzwerktopologien. Funktioniert, aber umständlich und langsam.
- Verwendung von Excel (TM) als Datenbank für Mehrbenutzeranwendungen.
- Verwendung von Fax zum Senden digitaler Dokumente an andere Systeme.
- Verwendung der Druckfunktionen für Logging und Tracing in einer Client/Server-Umgebung.
Sicherlich könnten wir diese Liste von besser nicht noch eine Weile fortsetzen, aber ich brauchte nur ein paar Beispiele.
Infrastrukturschulden
Definition: Infrastrukturschulden beziehen sich auf Probleme oder Risiken in den zugrunde liegenden Plattformen und der Hardware, auf denen Ihre Systeme laufen. Betrachten Sie dies als Sonderfall der Technologieschulden aus dem vorherigen Abschnitt.
Dies umfasst veraltete Server oder Betriebssysteme, Legacy-Hardware oder Netzwerke. Es sind die Schulden, die Sie eingehen, wenn Sie sich mit alter oder brüchiger Infrastruktur „zufriedengeben”, anstatt aufzurüsten – oft, weil Upgrades kostspielig oder riskant sind. Die Zinsen für diese Schulden werden jedoch in Form steigender Wartungskosten, schlechter Leistung und Schwierigkeiten bei der Implementierung neuer Funktionen gezahlt, die auf moderner Technologie basieren. Mit anderen Worten, wenn Ihr Fundament (Infrastruktur) altert, anstatt erneuert zu werden, sammeln Sie Infrastrukturschulden an. Organisationen häufen diese Schulden oft an, indem sie notwendige Upgrades verschieben oder aus kurzfristiger Bequemlichkeit oder Angst vor Veränderungen an Legacy-Systemen festhalten.
Das Software Engineering Institute beschreibt Fälle, in denen jahrzehntealte Mainframe-Anwendungen „über Jahrzehnte hinweg erhebliche technische Schulden angesammelt haben” – unter Verwendung veralteter Komponenten und Muster, die Release-Zyklen und Wartung verlangsamen (Demystifying mainframe technical debt).
Ein weiterer Aspekt ist erwähnenswert: Cloud-Migration ohne Berücksichtigung der erforderlichen Leistungs- und Sicherheitskonsequenzen (auch bekannt als falsch durchgeführtes Lift-and-Shift): Die „Lift and Shift”-Strategie bietet einen schnellen Weg in die Cloud, ist aber mit Risiken verbunden, wenn sie ohne sorgfältige Planung und Bewertung eingesetzt wird. Sie kann kläglich scheitern (und Infrastrukturschulden produzieren), wenn Leistungs-, Kosten- oder Sicherheitsüberlegungen übersehen werden oder Organisationen Cloud-Vorteile erwarten, ohne Cloud-native Funktionen zu nutzen.
All das sind Infrastrukturschulden. Die Fallstudien sind überall: Fluggesellschaften, deren alte Reservierungssysteme Check-in-Zusammenbrüche verursachen, Krankenhäuser, die veraltete Systeme betreiben, die Daten nicht einfach teilen können, usw. Die wichtigste Erkenntnis ist, dass das Vernachlässigen von Infrastruktur-Upgrades wie das Ignorieren eines rostenden Fundaments ist – je länger man wartet, desto schwieriger (und kostspieliger) wird die eventuelle Reparatur sein.
Randnotiz: Die Pragmatik des (Nicht-)Aktualisierens von Technologie
Bei der Entscheidung, ob und ob nicht zugrunde liegende Technologie oder Infrastruktur aktualisiert oder modernisiert werden soll, berücksichtigen Sie diese zusätzlichen Aspekte:
1. Das Risiko der Unterbrechung kann die Vorteile überwiegen. „Wenn es nicht kaputt ist, repariere es nicht.” – besonders wenn menschliche Sicherheit oder große finanzielle Konsequenzen involviert sind.
2. Menschen, die das System ursprünglich gebaut oder gewartet haben, könnten gegangen sein. Ohne ein tiefgreifendes/fundiertes Verständnis könnte die Modernisierung gefährlich oder unmöglich sein, ohne zuerst erhebliches Domänenwissen wieder aufzubauen. Siehe den Abschnitt über „Wissensschulden” oben.
Laufzeitqualitätsprobleme
Definition: Laufzeitqualitätsprobleme sind unerwünschte Verhaltensweisen des Systems, die während der Laufzeit oder während der Installation oder Konfiguration auftreten. Beispiele sind Leistungs- und Stabilitätsprobleme, mangelnde Benutzerfreundlichkeit, übermäßig hoher Ressourcenverbrauch usw.
Diese Laufzeitqualitätsprobleme sollten als eine spezifische Art von technischen Schulden gezählt werden. Sie können aus jeder Kombination von Codierung, Abhängigkeiten, unangemessener Technologie oder Infrastruktur oder sogar unklaren oder fehlenden Anforderungen resultieren.
Betrachten Sie die folgende These:
Man kann sauberen Code schreiben, der sich zur Laufzeit ineffizient oder unsicher verhält.
Daher müssen Sie schlussfolgern, dass es nicht ausreicht, sauberen und verständlichen Code mit sowohl loser Kopplung als auch hoher Kohäsion zu schreiben. Selbst solcher Code kann unerwünschtes Laufzeitverhalten zeigen, Sicherheitslücken enthalten und Ressourcen wie Speicher oder Bandbreite verschwenden.
Eine Voraussetzung zur Vermeidung von Laufzeitqualitätsproblemen scheint offensichtlich: Sie müssen Ihre spezifischen Qualitätsanforderungen kennen… das haben wir im Abschnitt über Anforderungsschulden behandelt. Ein anderer Weg, einigen Laufzeitproblemen entgegenzuwirken, ist Testen, was uns zur nächsten Kategorie von Schulden bringt:
Testschulden
Definition: Testschulden entstehen durch unzureichende Test- und QA-Prozesse.
Dies umfasst unzureichende automatisierte Testabdeckung, Mangel an Unit-/Integrationstests, eine unzuverlässige oder langsame Testsuite oder sogar fehlende Testumgebungen. In einigen schnelllebigen Teams wird das Testen verkürzt oder nicht priorisiert („wir fügen später Tests hinzu”) – das spart kurzfristig Zeit, aber akkumuliert später erhebliche Risiken und Kosten. Die „Zinsen” für Testschulden werden in Form von Bugs in der Produktion, langsamen Releases (weil man Dinge manuell testen oder Probleme direkt lösen muss) und einer allgemeinen Angst vor Änderungen gezahlt.
Wenn eine Codebasis eine schlechte Testabdeckung hat, trägt jede Änderung Unsicherheit in sich: Entwickler:innen sind nicht sicher, ob die Änderung nicht etwas anderes kaputt macht. Im Laufe der Zeit kann dies Verbesserungen lähmen oder erhebliche Anstrengungen für Bugfixes erfordern. Testschulden umfassen auch veraltete Testfälle (die keine Regressionen mehr erkennen) oder einen Mangel an kontinuierlicher Integration, was bedeutet, dass Bugs durch die Ritzen fallen. Zusammenfassend: Wenn Ihre Testdisziplin schwach ist, gehen Sie Schulden ein, deren Kosten sich als Softwarefehler und Wartungskopfschmerzen manifestieren werden.
Viele Organisationen können Geschichten über solche Testprobleme erzählen: Eine kleine Änderung bleibt ungetestet und verursacht einen größeren Ausfall. Zum Beispiel hatte die Royal Bank of Scotland (RBS) 2012 einen massiven Ausfall, der Millionen von Kunden daran hinderte, auf Konten zuzugreifen, verursacht durch ein fehlgeschlagenes Software-Update ihres Batch-Verarbeitungssystems (siehe 37 Epic Software Failures).
Das Grundproblem wurde auf eine Kombination von Faktoren zurückgeführt, darunter unzureichende Tests des Update-Verfahrens auf dem Legacy-System – effektiv eine Test-/Betriebsschuld, die sich als mehrtägiger Ausfall manifestierte.
Testschulden sind auch häufig in Projekten, die mit einer MVP-Denkweise beginnen: Teams schreiben vielleicht nur ein paar Happy-Path-Tests, um das Produkt auf den Markt zu bringen, und verschieben umfassende Tests. Dies ist tatsächlich eine bekannte Praxis in Startups; zum Beispiel autorisieren manche Product Owner nur grundlegende Tests für ein MVP und nehmen bewusst Testschulden auf, um einen schnellen Start zu erreichen (Why Product Owners Must Prioritize Managing Technical Debt?).
Die Gefahr kommt später: Wenn das Produkt wächst, bedeuten diese fehlenden Tests, dass neue Bugs unerwartet auftreten oder alte Bugs wieder auftauchen.
Ein realer (und tragischer) Fall waren die Softwareprobleme der Boeing 737 Max (MCAS): Obwohl es sich um ein sehr komplexes und tragisches Beispiel handelt, deuteten Untersuchungen darauf hin, dass Test- und Aufsichtslücken dazu beitrugen, dass kritische Fehler nicht erkannt wurden. (Siehe den FAA-Bericht über Boeing MCAS)
In kleinerem Maßstab können selbst routinemäßige Bugs wie ein Absturz einer mobilen App nach einem Update auf Testschulden hindeuten (vielleicht hat das Team nicht auf einer bestimmten OS-Version oder Bildschirmgröße getestet). Der kumulative Effekt von Testschulden ist ein langsamerer, riskanterer Entwicklungszyklus. Teams mit hohen Testschulden sagen manchmal Dinge wie „wir haben Angst, diesen Code anzufassen” oder „wir können nicht garantieren, dass das nächste Release nichts kaputt macht”, was zeigt, wie diese Schulden den Fortschritt einschränken.
Die Rückzahlung von Testschulden beinhaltet Investitionen in Testautomatisierung, Abdeckung kritischer Pfade und kontinuierliche Integration, was viele Teams erst tun, nachdem sie einige schmerzhafte Vorfälle erlitten haben, die sie zwingen, sich wieder auf Qualität zu konzentrieren. Im Wesentlichen erinnern uns Testschulden daran, dass „wenn Sie jetzt keine Tests schreiben, Sie später länger debuggen werden.”
Sicherheitsschulden
Definition: Sicherheitsschulden (eine Teilmenge der Qualitätsschulden) beziehen sich auf Abkürzungen und Mängel bei Sicherheitsmaßnahmen, die sich im Laufe der Zeit ansammeln.
Dies umfasst bekannte Schwachstellen, die ungepatcht bleiben, veraltete Verschlüsselung oder Protokolle, die noch in Verwendung sind, mangelnde Einhaltung von Sicherheitsstandards, schwache Zugriffskontrollen und generell jede aufgeschobene Sicherheitsarbeit. Es bedeutet auch, etablierte organisatorische Sicherheitspraktiken und die Notwendigkeit ständiger Wachsamkeit in Bezug auf alle Aspekte der Sicherheit zu ignorieren.
Organisationen gehen Sicherheitsschulden ein, wenn sie Sicherheitspraktiken der Geschwindigkeit oder Bequemlichkeit wegen ignorieren – zum Beispiel, indem sie ein Upgrade überspringen, das Schwachstellen behebt, weil es die Kompatibilität beeinträchtigen könnte, oder die Implementierung von Audit-Logs verzögern, weil „wir es später machen werden”. Kurzfristig passiert nichts Schlimmes und die Entwicklung geht weiter, aber das Risiko summiert sich im Laufe der Zeit. Die „Zinsen” für Sicherheitsschulden werden oft in der Währung von Sicherheitsverletzungen, Datenlecks und Notfall-Patches gezahlt, wenn Schwachstellen ausgenutzt werden.
Mit anderen Worten, wenn Sie kontinuierlich Sicherheits-Haushaltsführung aufschieben, „leihen” Sie im Wesentlichen gegen die Sicherheit des Systems, und Verstöße sind der katastrophale Schuldeneintreiber.
In der Datensicherheit ist es eine gute Heuristik anzunehmen, dass Ihre Angreifer mehr Geld, Zeit und Wissen plus bessere Technologie haben. Erwarten Sie, dass der Gegner oder Angreifer in jeder Hinsicht überlegen ist. Mit anderen Worten: Erwarten Sie das Schlimmste.
Eines der berüchtigtsten Beispiele für Sicherheitsschulden war die Equifax-Datenverletzung von 2017. Equifax, eine große Kreditauskunftei, erlitt einen Verstoß, der persönliche Daten von etwa 147 Millionen Menschen offenlegte.
Die Ursache? Equifax hatte es monatelang versäumt, eine kritische bekannte Schwachstelle in dem von ihnen verwendeten Apache Struts Web-Framework zu patchen, nachdem der Fix verfügbar war (siehe Equifax’s patching blunder).
Konkret wurde die Apache Struts-Schwachstelle (CVE-2017–5638) im März 2017 mit einem fertigen Patch offengelegt, aber Equifax wandte den Patch nicht an; Angreifer nutzten sie von Mai bis Juli 2017 aus, und Equifax entdeckte den Verstoß erst Ende Juli. Dieses Beispiel von ungepatchter Software zeigt Sicherheitsschulden in Aktion: Das Unternehmen „sparte” kurzfristig Aufwand, indem es sein System nicht aktualisierte, aber die Zinsen summierten sich enorm – was zu einer der größten Datenverletzungen in der Geschichte, Hunderten von Millionen an Bereinigungskosten, Führungsausfällen und irreparablen Rufschäden führte.
Ein weiteres Beispiel: Der „WannaCry Ransomware”-Angriff im Jahr 2017 traf viele Organisationen (vom britischen NHS bis zu globalen Unternehmen), die verfügbare Windows-Sicherheitsupdates nicht angewendet hatten; diejenigen, die mit Patches gezögert hatten, fanden ihre Systeme durch Malware gesperrt. Dies war eine harte Rückzahlung von Sicherheitsschulden. Selbst weniger dramatische Fälle zählen: Die Verwendung schwacher Passwörter oder hartcodierter Anmeldeinformationen mag nicht sofort zubeißen, aber sie sitzen als tickende Zeitbombe (Schuld), bis eines Tages ein Insider oder Hacker sie ausnutzt.
Der einzige Ausweg ist, diese Schulden proaktiv zu tilgen durch Patchen, Aktualisieren und Integration von Sicherheit in den Entwicklungslebenszyklus, anstatt sie am Ende aufzusetzen.
Betriebsschulden
Definition: Betriebsschulden beziehen sich auf Ineffizienzen und manuelle Arbeit in den Bereitstellungs-, Überwachungs- und Wartungsprozessen von IT-Systemen.
Es sind die Schulden, die Sie ansammeln, wenn Sie nicht in optimierte Abläufe investieren – zum Beispiel, wenn Sie sich auf manuelle Bereitstellungsschritte verlassen, keine ordentlichen Incident-Response-Playbooks haben, keine Überwachung/Beobachtbarkeit haben oder generell Routineaufgaben nicht automatisieren.
Kurzfristig könnten Sie mit Ad-hoc, manuellen Ops davonkommen („es funktioniert, fass es nicht an”), aber wenn das System wächst, werden diese manuellen Prozesse fehleranfällig und langsam. Die „Zinsen” für Betriebsschulden werden in Form von Ausfällen, langsamer Erholung von Vorfällen, Konfigurationsfehlern und betrieblichem Overhead gezahlt. Im Wesentlichen, wenn Ihre Ops-Praktiken die modernen DevOps/Automatisierungsstandards aufholen, zahlen Sie eine kontinuierliche Steuer in Form von Instabilität und verschwendeter Zeit. Diese Kategorie umfasst auch Dokumentations- und Wissensschulden im Betrieb – z.B. kennt nur eine Person das Deployment des Systems, was ein Risiko darstellt.
Einige Beispiele: Im Jahr 2017 wurde ein Amazon S3-Ausfall durch einen Ingenieur verursacht, der manuell ein Routine-Skript mit einem Tippfehler ausführte und versehentlich mehr Server offline nahm als beabsichtigt. Das Fehlen einer Sicherheitsprüfung oder einer automatisierten Begrenzung im Prozess verwandelte einen kleinen Fehler in einen weit verbreiteten, stundenlangen Ausfall.
Ebenso erlebte Microsoft Azure im Juni 2023 einen mehr als 10-stündigen Ausfall in einer Region aufgrund eines Tippfehlers – ein fehlerhafter Befehl in einem Wartungsskript führte zur versehentlichen Löschung von 17 Produktionsdatenbanken (TechRadar). Der Vorfall unterstrich, wie ein einzelner manueller Fehler in Abwesenheit robuster Validierungs- oder Wiederherstellungsprozesse Verwüstung anrichten kann. Wir können das als Betriebsschuld betrachten: Vielleicht fehlte dem System ein „Rückgängig” oder eine ordnungsgemäße Überprüfung für den Löschbefehl – eine Funktion, die vielleicht auf der To-do-Liste stand, aber nicht da war, als sie benötigt wurde.
Ein weiteres häufiges Beispiel sind manuelle Deployments. Unternehmen, die ihren Release-Prozess nicht automatisiert haben, sammeln oft Bereitstellungsskripte, Server-Konfigurationsanpassungen usw. an, die nur bestimmte Personen kennen. Dies kann zu Ausfällen führen wie „wir haben die falsche Version bereitgestellt” oder „die Konfiguration war auf einem Server anders.”
Ein klassischer Fall war das „Knight Capital”-Fiasko von 2012 (eine Handelsgesellschaft): Ein Fehler im Bereitstellungsprozess ließ ein altes Feature-Flag auf einigen Servern eingeschaltet, was zu einem unkontrollierten algorithmischen Handelssturm führte und die Firma in 45 Minuten 460 Millionen Dollar kostete. Die Grundursache wurde auf schlechte Deployment-Praktiken zurückgeführt – im Wesentlichen Betriebsschulden im Release-Management.
Ein Mangel an Beobachtbarkeit (Logging, Monitoring, Alerting) ist eine Form von Betriebsschulden – Sie sparen Zeit, indem Sie jetzt keine Dashboards einrichten, aber später, wenn etwas schief geht, „zahlen” Sie, indem Sie blind für das Problem sind. Stellen Sie sich zum Beispiel eine E-Commerce-Seite ohne ordentliches Monitoring vor: Wenn der Checkout-Service langsamer wird, bemerkt es niemand, bis Benutzer sich beschweren, und es dauert Stunden, den Engpass zu lokalisieren – eine klare Zinszahlung auf Betriebsschulden.
Branchenstudien haben festgestellt, dass die Hauptursache für Ausfälle menschliches Versagen bei Änderungen ist (OpsView.com).
Deshalb predigt die DevOps-Bewegung „Infrastructure as Code” und Automatisierung: um manuelle Schritte zu reduzieren und dadurch Betriebsschulden zu verringern. Zusammenfassend sammeln sich Betriebsschulden in Teams an, die auf Automatisierung, Dokumentation und belastbare Prozesse verzichten. Es mag nicht sofort zuschlagen (vielleicht ist alles in Ordnung, wenn das System klein ist oder der eine Guru-Admin immer da ist), aber wenn Systeme skalieren oder Personal wechselt, zeigt sich diese Schuld in langen Ausfällen und Brandbekämpfung.
Prozessschulden
Aus meiner persönlichen Erfahrung betrifft eine besonders unangenehme Art von Schulden Prozesse, insbesondere Projektmanagement, Anforderungen oder Entwicklungsmethodologie – zum Beispiel das Umgehen von Code-Reviews, das Überspringen agiler Zeremonien oder das Fehlen eines effektiven Wissensaustauschprozesses.
Diese Abkürzungen können kurzfristig Geschwindigkeit bringen, aber auf Kosten der Teameffizienz und Produktqualität später (die Zinsen für Prozessschulden können Dinge wie Team-Burnout, Kommunikationsprobleme oder Feature-Neubearbeitung sein). Im Wesentlichen, wenn Ihre Entwicklungsprozesse oder Anforderungsdefinitionen nicht solide sind, sammeln Sie eine Art organisatorische Schuld an, die zukünftige Änderungen schwieriger macht.
Solche Prozessschulden werden (!) zu mehreren anderen Arten von Schulden führen, z.B. Kommunikationsschulden, Anforderungsschulden, Strukturschulden und andere.
Zusammenfassung & Erkenntnisse
Technische Schulden sind weit mehr als ein Problem der Codequalität; es ist ein ganzheitliches Konzept, das viele Arten von Bremswirkungen auf IT-Systeme erfasst. Wir haben ein breiteres Verständnis eingeführt, das Anforderungen, Code, Architektur, Technologie und Infrastruktur, Prozesse, Tests, Sicherheit und Betrieb umfasst.
Wenn wir technische Schulden durch diese breitere Linse betrachten, sehen wir, dass jede Abkürzung oder aufgeschobene Arbeit in einem IT-System zu einer „Schuld” werden kann, die später mit Zinsen zurückgezahlt werden muss.
Bewusstsein ist der erste Schritt zur Verwaltung und Minderung dieser Arten von Schulden. Sobald die Schulden sichtbar und anerkannt sind, können Teams informierte Entscheidungen darüber treffen, wann und wie sie sie abbauen.
Bedenken Sie, dass nicht alle Schulden schlecht sind – manchmal ist es notwendig, strategisch technische Schulden einzugehen, um ein Geschäftsziel zu erreichen (genauso wie die Aufnahme eines Kredits ein kluger Geschäftszug sein kann). Der Schlüssel ist, absichtlich damit umzugehen: Schulden nur mit einem Plan zur Bedienung oder Tilgung eingehen. Unbeabsichtigte oder unkontrollierte Schulden – die Art, die „einfach passiert”, wenn Teams unter Zeitdruck stehen oder die Wartung vernachlässigen – neigen dazu, außer Kontrolle zu geraten.
Wie Ward Cunningham in seiner Schuldenmetapher warnte, besteht die Gefahr darin, Zinsen anzusammeln:
„Jede Minute, die mit nicht ganz richtigem Code verbracht wird, zählt als Zinsen auf diese Schuld” und schließlich kann eine Organisation „unter der Schuldenlast zum Stillstand gebracht werden”, wenn diese nie angegangen wird
Letztendlich werden Organisationen, die ihre technischen und anderen Schulden strategisch verwalten, agiler, widerstandsfähiger und erfolgreicher sein als diejenigen, die Schulden unkontrolliert anwachsen lassen.
Möge daher die Kraft angemessener architektonischer und technischer Entscheidungen mit Ihnen sein!
Abschließende Bemerkung
Manchmal ist es unmöglich, eine Entscheidung als „schuldenreich” zu beurteilen oder nicht, weil die Konsequenzen derzeit nicht bekannt sein können. Wir (und unser IT-System) könnten mit dieser Entscheidung glücklich leben und davon profitieren. Dann stellt sich plötzlich heraus, dass diese Entscheidung die Wurzel eines großen und kostspieligen Problems ist:
Zum Beispiel ist die Log4j-Sicherheitskatastrophe, bekannt als „Log4Shell” (CVE-2021–44228), ein Paradebeispiel für eine weit verbreitete, kritische und leicht ausnutzbare Schwachstelle, die im Dezember 2021 auftrat. Diese weit verbreitete Logging-Bibliothek für Java-Systeme wurde zu einem Sicherheitsalbtraum, sobald die Schwachstelle veröffentlicht wurde.
Bildquellen
Die Bilder wurden von ChatGPT basierend auf Prompts des Autors generiert.
Ressourcen und weiterführende Literatur
In Anbetracht dessen, dass technische und andere Schulden für die meisten Probleme, die wir in IT-Systemen antreffen, einflussreich sind, wurde erstaunlich wenig geforscht und veröffentlicht (mit Ausnahme von Nischen-Wissenschaftskonferenzen).
- Phillippe Kruchten, Robert Nord und Ipek Ozkaye: Managing Technical Debt: Reducing Friction in Software Development. Addison-Wesley 2019. Sehr empfehlenswert für Architekten und IT-Manager.
- Neil Ernst, Rick Kazman, Julien Delange: Technical Debt in Practice: How to Find It and Fix It. MIT-Press, 2021. Breiter Überblick, mit guter tiefgehender Abdeckung vieler „Schulden-Vermeidungs”-Praktiken. Empfohlen für Architekt:innen und Entwickler:innen.
- Nikita Golovko and Maxim Silaev: Technical Debt. Design, risk and beyond.
Danksagungen
Mein Dank gilt Gerrit Beine, Sven Johann und Dr. Nikita Golovko für ihre Hinweise, das Aufspüren kleiner Fehler und ihre Beiträge zur inhaltlichen Schärfung. Besonderer Dank gilt „m”, einer erstklassigen Sprach-, Zeichensetzungs- und Grammatikspezialistin. Alle verbleibenden Fehler sind meine.
-
Eine besondere Art von Problem, auf die ich manchmal während Software–Reviews gestoßen bin, bezieht sich auf Daten, z.B. Datenstrukturen, Datenbank– oder Tabellenschemata, die Korrektheit der Daten selbst oder ähnliche Probleme. Sie könnten diese Arten von Problemen als eine eigene Kategorie betrachten, aber Sie könnten sie auch als Teil von Struktur–, Laufzeit– oder Technologieschulden ansehen. ↩
-
„Code, der umgeschrieben wird, um technische Schulden zu verwalten, beinhaltet typischerweise einen Produktivitätsverlust und höhere Kosten, oft geschätzt auf bis zu 25–30% der Gesamtprojektkosten in großen Systemen.” Quelle: Besker, T., Martini, A., & Bosch, J. (2018). Managing Technical Debt in Software Development: Current State of Practice. In Proceedings of the 2018 International Conference on Software Engineering: Software Engineering in Practice (ICSE–SEIP). ↩