Im Softwareentwicklungsprozess können Zustände entstehen, die den Projekterfolg verzögern, gefährden oder gänzlich unmöglich machen. Schon manches Projekt musste wegen mangelnden Bewusstseins über solche Risiken wiederholt neu aufgesetzt oder gänzlich begraben werden. Selbst dann jedoch bleiben die Ursachen häufig im Verborgenen. Ich nenne sie daher stille Killer – die unerkannte, zuweilen auch nur unterschätzte Gefahr.
Der Begriff der Technischen Schulden ist heute den meisten, die in irgendeiner Weise mit Softwareentwicklung zu tun haben, geläufig. In agilen Entwicklerteams wird er für gewöhnlich regelmäßig thematisiert. Unter dem Kürzel TD für Englisch Technical Debt wird die Technische Schuld gerne bemüht, um Verzögerungen oder Fehlerraten zu begründen. Und obwohl das Konzept der Technischen Schuld in den letzten Jahren auf unrühmliche Weise populär geworden ist, gibt es einen Umstand, der allzu leicht übersehen wird: die Entstehung von Technischer Schuld ist unvermeidbar.
Technische Schuld ist ein Naturgesetz
Wir sind nicht hellsichtig, und Zeit ist ein knappes Gut (glauben wir)
Soviel wir uns auch bemühen, wir können nicht jedes Detail vorausahnen. Auch können wir uns nicht beliebig viel Zeit nehmen, immer die ideale Lösung zu entwerfen. So manche weitreichende Entscheidung treffen wir innerhalb von Sekunden. Manchmal bemerken wir zu spät, dass uns zur optimalen Umsetzung schlicht Wissen fehlte.
Architektur erodiert
Und dann ist da noch etwas, das Dr. Carola Lilienthal als Architekturerosion bezeichnet. Damit ist gemeint, dass selbst ein idealer Entwurf mit der Zeit seine Gültigkeit verlieren kann, und aus einer ehemals guten mit der Zeit eine weniger gute Implementierung wird. Eine Architektur, die gestern noch perfekt war, ist heute falsch, da die Umstände sich verändert haben. Gesetzliche Vorgaben oder neue Verfahren im Zahlungsverkehr sind gute Beispiele dafür. Davon abgesehen entsteht Erosion häufig auch dadurch, dass verschiedene Entwickler mit unterschiedlichem Hintergrund und Sachverstand den Code mit der Zeit in ein Stadium zunehmender Unordnung überführen. Kurz gesagt: der Code wird mit der Zeit immer schlechter. In vielen Softwareprojekten ist das eine feststehende Tatsache.
Es ist also schwer, TDs in Softwaresystemen ganz zu vermeiden. Wohl aber gibt es Möglichkeiten, die Schäden zu minimieren, indem wir ihr Ausmaß innerhalb eines „Korridors geringer technischer Schulden“ (Lilienthal) halten. Doch zunächst wollen wir versuchen zu umreißen, was Technische Schuld für uns bedeutet.
Definition
Tatsächlich gibt es zur Definition von TD unterschiedliche Betrachtungsweisen. Die einfachste ist, jedwede unsachgemäße Programmierung als TD zu bezeichnen. Unsachgemäß bedeutet hier: den Stand der Kunst missachtend oder schlichtweg schäbig programmiert.
Eine andere Auffassung besagt, dass es immer eine bewusste Entscheidung sein muss, Technische Schulden aufzunehmen – schlechte Programmierung oder mangelhafte Architektur fielen dann also nicht darunter. Hier würden wir kurzfristig und bewusst ein TD akzeptieren, um ein anderes Ziel, beispielsweise einen bevorstehenden Releasetermin, schneller zu erreichen.
Als Verallgemeinerung beider Sichten ließe sich definieren, dass Technische Schuld potenziell jeder Zustand einer Software ist, der eine nahtlose Weiterentwicklung verhindert.
Gründe und Auswirkungen
Aufgeschobene Refactorings
Sobald durch eine anstehende Erweiterung die Umstrukturierung bestehender Teile der Software erforderlich wird, droht ein Schuldenloch. Ob es sich auftut und wir hineinfallen hängt davon ab, ob das Refactoring durchgeführt wird oder nicht. Wenn ja, ist alles gut – keine TD aufgebaut. Wenn wir es nicht tun, haben wir von dem Moment an eine TD, die mit jedem kommenden Change Request ihre Zinsen einfordern wird. Der Zinseszinseffekt ist bekanntlich ein exponentielles Phänomen. Das gilt auch in der Softwareentwicklung.
Häufig wird mit der Umsetzung von Erweiterungen begonnen, ohne vorher zu prüfen, ob die bestehende Architektur den neuen Anforderungen standhält. Nötige Refactorings werden so erst spät erkannt, wenn überhaupt. Nach zwei oder drei Erweiterungszyklen ist das Dilemma oftmals bereits so weit fortgeschritten, dass Maßnahmen zur Behebung sehr deutlich zu Buche schlagen würden. Die Lösung heißt dann allzu oft „Augen zu und durch“ – und so manövriert sich das Projekt selbst immer tiefer in den Schuldenberg hinein. In dieser Phase beginnen die Schmerzen groß genug zu werden, um Aufmerksamkeit „von oben“, also des Managements oder des Kunden zu gewinnen. Die Frage lautet dann, warum selbst kleine Feature-Erweiterungen „so lange“ dauern.
Featuritis
Es ist eine Binsenweisheit, dass viele Softwareprojekte mit Bazillus Featuritis infiziert sind. Das giftige Stoffwechselprodukt dieses Erregers ist TD. Eine der Schwierigkeiten bei der Diagnose von TD ist die lange Inkubationszeit. Während funktionale Softwarefehler meist frühzeitig zutage treten, wirken sich TDs eine Zeit lang eher unterschwellig aus. Wenn ihre unschönen Symptome wie erschwerte Wartbarkeit und steigende Defect-Raten sich endlich zeigen, ist das Softwareprodukt bereits derart heruntergewirtschaftet, dass ein Gegensteuern nicht mehr ohne deutlichen Mehraufwand zu bewerkstelligen ist. Das liegt daran, dass TD ein Aspekt der inneren Softwarequalität ist, beziehungsweise ein Mangel derselben. Die innere Qualität eines Produkts ist von außen nicht direkt sichtbar. Sie wird nur dann wahrgenommen, wenn sie so dürftig ist, dass sie zu Fehlfunktionen oder steigenden Aufwänden führt.
Das Gesetz von Conway
Nach dem vielzitierten Gesetz von Conway, englisch Conway‘s Law, entsprechen die Strukturen eines Softwaresystems zwangsläufig denen der Organisation, die es hervorgebracht hat. Verschiedene Studien haben dieses Postulat aus den Achtzigerjahren bestätigt. Das bedeutet am konkreten Beispiel, ein zentralistisch-hierarchisch organisiertes Unternehmen wird sich mit Microservice-Architekturen, wo Dezentralisierung, Ereignissteuerung, Informationsaustausch und Entkopplung eine große Rolle spielen, vermutlich schwertun. Technischen Schulden fallen in dieselbe Kategorie. Steile Hierarchien, Führung in Form von Kommandostrukturen anstatt Servant Leadership sowie fachliche und soziale Inkompetenz begünstigen den Nährboden für das Wachstum von TD.
Wege aus der Schuldenfalle
Schuldeingeständnis
Ist ein Projekt einmal in einen Zustand technischer Überschuldung eingetreten, gibt es dennoch Wege hinaus. Sie erfordern im ersten Schritt ein Schuldeingeständnis der Beteiligten: Product-Owner, Development-Team und Projektleitung müssen sich über ihre jeweiligen Anteile im Klaren sein und gemeinsam an der Lösung arbeiten. Ein Coach kann dabei hilfreich sein. Vielleicht gibt es einen fähigen Scrum Master, der die Parteien dabei unterstützt, einen gangbaren Weg zu finden.
Schadenanalyse
Sind sich PO, PL/Kunde und Dev-Team einig, kann der negative Effekt von TD zumindest abgemildert, manchmal sogar beseitigt werden. Jedenfalls gilt es nun, beherzt zu handeln. Zunächst muss das Ausmaß der Technischen Schulden umrissen werden, damit die Aufwände zu ihrer Behebung eingeplant werden können. Nicht selten gibt es hierbei unerwartete Ergebnisse: mehrere Wochen bis Monate an Konsolidierungsarbeiten sind für ein Projekt schwer zu verkraften. Mut, eine der fünf agilen Tugenden, ist hier besonders gefragt. In einer solchen Lage müssen wir uns folgendes immer vor Augen halten: erstens haben wir diesen Zustand selbst verursacht, und zwar kollektiv auf allen Ebenen. Zweitens, wenn wir den Mut jetzt nicht aufbringen, den Zustand zu verbessern, wird es später noch härter.
Coaching
Ebenfalls schwierig wird es, wenn die oben genannten Conway-Gründe vorliegen. Dann haben wir es mit einem echten Härtefall zu tun. Unter solchen Umständen ist es unerlässlich, einen erfahrenen Coach hinzuzuziehen, der Führung und Entwicklung miteinander in Einklang bringen hilft.
Vorsicht ist besser als Nachsicht: Technische Schulden einplanen
Um die Entstehung von TD möglichst von vornherein zu verhindern, gilt es, die drohenden Schuldenlöcher rechtzeitig zu erkennen. Idealerweise prüfen wir die bestehende Implementierung, bevor wir mit der Weiterentwicklung beginnen. Das schließt auch die Makroarchitektur mit der Kommunikation zwischen beteiligten Systemen mit ein. In diesem Fall könnten die Refactoring-Aufwände bereits in der Planung berücksichtigt werden.
Versäumen wir, eine Voranalyse durchzuführen oder ist es nicht möglich, können wir immer noch während der Entwicklung TDs identifizieren. Nun ist zu prüfen, wie wir damit umgehen wollen.
Die edelste Option wäre, die TDs sofort zu beheben und zu akzeptieren, dass sich der Planungshorizont entsprechend nach hinten verschiebt. Das kann eine agile Projektorganisation leicht verkraften. Im klassischen Managementumfeld kann es jedoch passieren, dass wir damit allergische Reaktionen auslösen. Hier wäre ein Kompromiss, die TD zunächst zu akzeptieren, um das Feature – notfalls mit Workarounds um die TD herum – planmäßig funktional fertigzustellen. Nun aber müssen wir sofort ein Ticket erstellen, um die TD anschließend so schnell wie möglich einplanen und auflösen zu können. Eine gute Releaseplanung sollte diesen Fall auch im klassischen Umfeld abfedern können.
Organisatorische Maßnahmen
Qualität mit einplanen
Organisatorische Maßnahmen betreffen alle Ebenen der Projektorganisation. Am Ende jedoch läuft es darauf hinaus, dass die Projektleitung für das Gelingen oder Scheitern Sorge tragen muss. Die PL bestimmt maßgeblich die Projektkultur, und damit auch, wie mit Herausforderungen umgegangen wird, gerade wenn sie Geld kosten. Nicht zuletzt bestimmt sie, welche Qualitätsmaßstäbe anzulegen sind und wie die Sicherung der Softwarequalität erfolgen soll.
Project Staffing
Zunächst einmal sollte unser Projekt mit fähigen Menschen ausgestattet sein: wir benötigen beispielsweise ein Product-Management-Team und einen Führungsstab, die wissen, wie Softwareentwicklungsprozesse funktionieren. Wir brauchen ein Development-Team, das auf dem Stand der Technik und bereit ist, sich stetig weiterzuentwickeln. Und wir sollten einen Projektcoach engagieren, beispielsweise einen Scrum Master, der dafür sorgt, dass die Organisation der Zusammenarbeit im Projekt rund läuft.
Wenn die Qualitätsziele gesteckt sind und das Projekt gut gestafft ist, sind die Grundlagen gesetzt. Nun gibt es eine Reihe von Tools, um die innere Qualität des Softwareprodukts zu gewährleisten.
Architekturwissen vom Elfenbeinturm ins Entwicklerteam
Eines der wichtigsten Werkzeuge ist die Fähigkeit des Entwicklerteams, die Software mit Hilfe einer zweckmäßigen Makro- und Mikroarchitektur gut zu strukturieren. Dadurch wird die langfristige Wartbarkeit gewährleistet, und Technische Schulden können leichter vermieden oder behoben werden.
Eine beliebte Falle ist hierbei, die Software-Architektur als eine eigene, von der Programmierarbeit getrennte Disziplin zu betrachten. Es empfiehlt sich jedoch vielmehr, dafür zu sorgen, dass die Entwickler über profundes Architekturwissen verfügen und dieses in ihrer täglichen Arbeit stetig anwenden. Mit der dazugehörigen Disziplin lässt sich dann die Architekturerosion in Grenzen halten.
Poka-Yoke-Entwicklungsprozess – Fehler besser vorher vermeiden statt später beheben
Um durch Unachtsamkeit oder Tollpatschigkeit entstehende Technische Schuld von vornherein zu berücksichtigen, empfiehlt es sich, den Entwicklungsprozess so zu gestalten, dass alleine dadurch die Entstehung von TD bereits eingeschränkt wird. Dieses Vorgehen ist als Poka Yoke bekannt. Beispielsweise implementieren wir Domain Driven Design als festen Bestandteil des Prozesses. Dadurch wird sichergestellt, dass Änderungen in der Fachdomäne adäquat in der Software abgebildet werden. Als nächstes sollte Clean Code gelebt werden. Dadurch minimiert sich das Aufnehmen von Technischen Schulden von selbst. Für den passionierten Clean Coder gehört kontinuierliches Refactoring zu den Standardmitteln, um gerade auch die Technischen Schulden klein zu halten. Ebenso sind effektiv durchgeführte Codereviews ein fester Bestandteil der Clean-Code-Praxis.
SonarQube für statische Codeanalyse nach der SQALE-Methode
Als technisches Tool hat sich in vielen Projekten SonarQube etabliert, das in die Build-Pipeline integriert werden kann, um mit Hilfe von statischer Codeanalyse unter anderem das Ausmaß an TD zu bemessen. Dabei wird der Grad der Technischen Schuld in Manntagen beziffert.
Allerdings dürfen wir uns nicht darüber hinwegtäuschen lassen, dass SonarQube semantische Qualitätskriterien wie Lesbarkeit und Verständlichkeit des Sourcecodes genauso wenig messen kann wie dessen sachliche Korrektheit. Wichtige Designprinzipien wie das Single Responsibility Principle sind ebenfalls schwer automatisiert zu prüfen. Daher ist SonarQube zwar eine gute Unterstützung, sollte jedoch keinesfalls als alleinige Quelle der Wahrheit dienen.
Fazit
Fassen wir zusammen:
- Technische Schuld entsteht laufend während der Entwicklung. Das ist natürlich und ganz normal.
- Obwohl die Technische Schuld als Buzzword in der Softwareszene hinlänglich bekannt ist, finden ihre Ursachen und Auswirkungen wenig Beachtung. Allzu oft werden sie ignoriert.
- Die besten Programmierer und Architekten können Technische Schulden nicht abwenden, wenn der Entwicklungsprozess und/oder die Unternehmenskultur wirksame Maßnahmen konterkarieren.
- Ein großer Anteil technischer Schulden lässt sich bereits durch rein organisatorische Maßnahmen unterbinden. Neben einer fähigen Projektmannschaft müssen somit auch kulturelle und prozessuale Voraussetzungen geschaffen werden.
- Softwareprojektcoaching ist ein probates Mittel, um die Verschuldung von Anfang an klein zu halten, oder ein Softwareprojekt aus der TD-Sackgasse herauszuführen.
In diesem Sinne, happy engineering 🙂