Suche
Test & Quality

Technische Schulden als Entscheidungsgrundlage: Wie Product Owner und Entwickler für langlebige Architekturen sorgen

Dr. Carola Lilienthal
BT-Magazin-1-16_Aufmacher_Lilienthal_iStock_richterfoto_900x600

© iStock / richterfoto

Die wenigsten Product Owner haben heute noch die Chance, ein System auf der grünen Wiese entwickeln zu lassen. Meistens stehen sie gemeinsam mit ihrem Entwicklungsteam vor der Herausforderung, ein oder mehrere über Jahre gewachsene Systeme um neue Features zu erweitern und zu warten. Aus Sicht des Entwicklungsteams braucht man dafür eine qualitativ hochwertige und flexible Architektur mit möglichst wenig technischen Schulden. Sind die technischen Schulden gering, dann können Bugs schnell und einfach gefixt werden, und Erweiterungen sind kostengünstig umzusetzen – aber was braucht der Product Owner?

Für den Product Owner sind technische Schulden etwas sehr Abstraktes, und er kann sie allein auf Basis der Aussagen der Entwickler schlecht nachvollziehen. Noch dazu sind Entwickler aus seiner Sicht häufig qualitätsversessen – ständig jammern sie über schlechten Code und fehlende Zeit für die aus ihrer Sicht notwendigen Refactorings. Damit Product Owner und Entwicklungsteam sinnvolle Entscheidungen über den Abbau technischer Schulden treffen können, brauchen sie ein gemeinsames Verständnis, wo Schulden existieren und welche Schulden wann und warum abgebaut werden sollten.

Technische Schulden

Der Begriff „Technische Schulden“ wurde 1992 von Ward Cunningham geprägt [1]. Technische Schulden entstehen, wenn bewusst oder unbewusst falsche oder suboptimale technische Entscheidungen getroffen werden. Diese führen zu einem späteren Zeitpunkt zu Mehraufwand, der Wartung und Erweiterung teurer macht. Zu dem Zeitpunkt der falschen oder suboptimalen Entscheidung hat man also technische Schulden aufgenommen, die man mit ihren Zinsen irgendwann abbezahlen muss, wenn man nicht überschuldet enden will.

In der Literatur werden verschiedene Arten und Varianten von technischen Schulden aufgeführt. Für diesen Artikel stelle ich die Schulden in den Fokus, die das Entwicklungsteam dem Product Owner nahebringen muss. Andere Problemfelder, die man auch als Schulden von Softwareprojekten betrachten kann, wie fehlende Dokumentation, schlechte Usability oder ungenügende Hardware, bleiben hier außen vor.

Implementationsschulden: Im Sourcecode finden sich so genannte Code Smells, wie lange Methoden, leere Catch-Blöcke etc. Implementationsschulden sind heute weitgehend automatisiert mit einer Vielzahl von Tools im Sourcecode zu finden. Jedes Entwicklungsteam sollte diese Schulden in seiner täglichen Arbeit sukzessive beheben, ohne den Product Owner damit zu belasten. Der Aufwand, um dem Product Owner diese sehr programmiersprachennahen Schulden zu vermitteln, steht in keinem Verhältnis zum Nutzen.

Testschulden: Es fehlen Tests bzw. nur der Gutfall wird getestet. Die Testabdeckung mit automatisierten Unit Tests ist gering. Auch die Testabdeckung lässt sich heute mit Werkzeugen messen und auf Dashboards wie SonarQube Teamscale etc. hervorragend visualisieren. Über den Abbau von Testschulden sollte es zwischen Product Owner und Entwicklungsteam keinen Dissens geben, denn eine angemessen hohe Testabdeckung bewahrt vor Fehlern und Folgefehlern. Hier Kompromisse einzugehen, ist wie Autofahren ohne Sicherheitsgurt: eindeutig fahrlässig.

Design- und Architekturschulden: Das Design der Klassen, Pakete, Subsysteme, Schichten und Module ist uneinheitlich, komplex und passt nicht mit der geplanten Architektur zusammen. Diese Schulden sind durch einfaches Zählen nicht zu ermitteln und dadurch auch schwerer zu vermitteln. Im Abschnitt „Identifizieren von Design- und Architekturschulden“ wird das näher betrachtet.

Je nachdem wie Product Owner und Entwicklungsteam mit diesen technischen Schulden umgehen, erstellen sie entweder eine Software, die im Korridor geringer technischer Schulden bleibt, oder ein System mit einer sich immer weiter ausbreitenden Architekturerosion (Abb. 1).

Wie technische Schulden entstehen

Schauen wir uns Abbildung 1 einmal im Detail an: Stellen wir uns vor, ein erfahrenes Entwicklungsteam beginnt mit der Entwicklung eines neuen Systems. Dieses Team wird all sein gesammeltes Know-how in den Entwurf der Softwarearchitektur einbringen. Dieses System befindet sich am Anfang in einem Korridor geringer technischer Schulden. Erweitert man das System, entstehen zwangsläufig technische Schulden (gelbe Pfeile in Abb. 1). Softwareentwicklung ist ein ständiger Lernprozess, bei dem der erste Wurf einer Lösung selten der endgültige ist. Die Überarbeitung der Architektur (Architekturerneuerung, grüne Pfeile in Abb. 1) muss in regelmäßigen Abständen durchgeführt werden. Es entsteht so eine stetige Folge von Erweiterung und Refactoring.

Kann ein Team diesen Zyklus von Erweiterung und Refactoring beibehalten, so wird das System im Korridor geringer technischer Schulden bleiben. Aber gerade dieser Aspekt der frühzeitigen Refactorings ist vielen Product Ownern nicht einfach zu vermitteln, obwohl er jedem Entwickler und Architekten absolut logisch erscheint. Wir müssen also zu anderen Mitteln, wie betriebswirtschaftlicher Bewertung greifen, wie wir später in diesem Artikel sehen werden.

lilienthal_tschulden_1

Abb. 1: Entwicklung und Effekt von technischen Schulden

Darf das Entwicklungsteam die Architekturqualität nicht ständig im Auge behalten, so setzt im Laufe der Zeit zwangsläufig Architekturerosion ein(rote Pfeile in Abb. 1). Die Architektur des Systems erodiert, die Komplexität nimmt zu und es werden Schritt für Schritt technische Schulden aufgebaut. Sind erst einmal technische Schulden angehäuft, werden Wartung und Erweiterung der Software immer teurer, Folgefehler sind immer schwerer nachvollziehbar, bis zu dem Punkt an dem jede Änderung zu einer schmerzhaften Anstrengung wird. Abbildung 1 macht diesen langsamen Verfall dadurch deutlich, dass die roten Pfeile immer kürzer werden. Pro Zeiteinheit kann man bei steigenden Schulden immer weniger Funktionalität umsetzen. Um aus diesem Dilemma der technischen Schulden herauszukommen, muss die Architektur rückwirkend verbessert werden. Auf diesem meist beschwerlichen Weg muss das System Schritt für Schritt wieder in den Korridor geringer technischer Schulden zurückgebracht werden (siehe rote absteigende Pfeile in Abb. 1).

Natürlich kann es auch passieren, dass zu Beginn der Entwicklung kein fähiges Team vor Ort war. Technische Schulden werden in diesem Fall gleich zu Beginn der Entwicklung aufgenommen und kontinuierlich erhöht. Über solche Softwaresysteme kann man wohl sagen: Sie sind unter schlechten Bedingungen aufgewachsen. Weder den Softwareentwicklern noch Product Owner oder Management wird ein System in einem solchen Zustand auf Dauer Freude machen.

Eine solche Betrachtung von technischen Schulden ist für Product Owner und für das Management normalerweise verständlich und nachvollziehbar. Niemand will technische Schulden anhäufen und sich mit der Entwicklung langsam festfressen, bis jede Anpassung zu einer unkalkulierbaren Kostenschraube wird. Auch der Aspekt, dass es kontinuierliche Arbeit bedarf, um die technischen Schulden über die gesamte Lebensdauer der Software gering zu halten, lässt sich gut vermitteln. Problembewusstsein haben die meisten Nicht-IT-ler also durchaus, aber welche technischen Schulden muss man wirklich angehen?

Identifizieren von Design- und Architekturschulden

Die meisten Entwicklungsteams können aus dem Stand eine Liste an Design- und Architekturschulden für das System aufzählen, an dem sie gerade entwickeln. Diese Liste lässt sich gut als Ausgangspunkt für die Analyse von technischen Schulden nutzen. Um den Design- und Architekturschulden weiter auf den Grund zu gehen, passende Darstellungen für den Product Owner zu finden und sinnvolle Refactorings herauszuarbeiten, empfehle ich meinen Kunden eine Architekturanalyse.

Mit einer Architekturanalyse lässt sich überprüfen, inwieweit die geplante Architektur im Sourcecode tatsächlich umgesetzt worden ist. Für solche Soll-/Istvergleiche steht heute eine Reihe guter Tools zur Verfügung: Lattix, Sotograph/SotoArc, Sonargraph, Structure101 u. v. m. Die Sollarchitektur ist der Plan für die Architektur, der auf Papier oder in den Köpfen des Architekten und Entwicklers existiert (Abb. 2).

lilienthal_tschulden_2

Abb. 2: Soll-/Istvergleich der Architektur

Dieser Plan ist eine Abstraktion und Vereinfachung des Sourcecodes. Häufig wird dieser Plan zu Beginn der Implementierung erstellt und im Laufe der Zeit an die Gegebenheiten angepasst (siehe Abschnitt zu technischen Schulden). Der Sourcecode enthält im Gegensatz dazu die implementierte Istarchitektur. In allen mir bekannten Fällen weicht die Istarchitektur von der Sollarchitektur ab. Die Ursachen dafür sind vielfältig und hängen oft auch mit Architekturerosion und technischen Schulden (siehe oben) zusammen.

In Abbildung 3 sieht man den Ablauf einer Architekturanalyse zur Identifizierung von technischen Schulden. Nachdem sich der Reviewer vorab mit Dokumenten einen ersten Eindruck des Systems verschafft hat (1), wird die eigentliche Architekturanalyse gemeinsam mit den Architekten und Entwicklern des Systems in einem Workshop durchgeführt. Zu Beginn des Workshops wird der Sourcecode des Systems mit dem Analysewerkzeug geparst (2) und so die Istarchitektur erfasst. Auf die Istarchitektur wird nun die Sollarchitektur modelliert, sodass der Vergleich von Soll und Ist möglich wird (3).

Dabei werden technische Schulden sichtbar, und man macht sich gemeinsam auf die Suche nach einfachen Lösungen, wie die Istarchitektur an die Sollarchitektur angeglichen werden kann (3). Oder aber es wird die Sollarchitektur diskutiert und festgestellt, dass die im Sourcecode gewählte Lösung besser ist. Manchmal ist aber auch weder die Sollarchitektur noch die abweichende Istarchitektur die beste Lösung, und man entwirft gemeinsam ein neues Zielbild für die Architektur.

Insbesondere, wenn ein System vor einer größeren Erweiterung steht, tritt dieser Fall ein. Die geplante Architektur war für die anstehende Erweiterung nicht ausgelegt, sodass eine grundlegende Weiterentwicklung der Architektur notwendig wird. Dabei werden Fragen beantwortet, wie: Ist die vorhandene Architektur flexibel genug für die Erweiterung? Muss die Kopplung an einigen Stellen reduziert werden, damit eine Umstrukturierung möglich wird? Ist der Schnitt der Module und Schichten richtig gewählt, um die neuen Module mit der neuen Funktionalität konsistent zu integrieren?

Hat man ein Softwaresystem übernommen, das man nicht selbst mitentwickelt hat, dann lohnt sich auf jeden Fall eine tief gehende Architekturanalyse, um das System überhaupt erst einmal kennenzulernen. Ist die Sourcecode-Basis dem Entwicklungsteam unbekannt, so können auf diese Weise die ursprünglich geplanten Strukturen überhaupt erst sichtbar gemacht werden.

Der Vollständigkeit halber ist in Abbildung 3 auch die Überprüfung von Metriken erwähnt. Metriken fallen in den Bereich der Implementationsschulden, weshalb wir sie hier nicht weiter betrachten.

lilienthal_tschulden_3

Abb. 3: Identifizieren von technischen Schulden bei der Architekturanalyse

Im Laufe einer solchen Architekturanalyse sammelt der Reviewer mit dem Entwicklungsteam technische Schulden und mögliche Refactorings an einem Whiteboard (3). Der nächste Schritt ist nun, diese Schulden und Refactorings betriebswirtschaftlich zu bewerten, um für den Product Owner eine Entscheidungsgrundlage zu haben.

Technische Schulden betriebswirtschaftlich betrachten

Haben die Liste der bekannten technischen Schulden und die Liste der möglichen Refactorings nach einer Architekturanalyse einen befriedigenden Stand erreicht, müssen die Schulden und Lösungen aus betriebswirtschaftlicher Sicht bewertet werden. Die Fragen an dieser Stelle sind: Wie sehr tut die jeweilige technische Schuld dem Unternehmen weh? Was kostet es das Unternehmen, wenn nicht gehandelt wird? Und auf der anderen Seite: Wie teuer ist das Refactoring und für welche Schulden ist das Refactoring eine Lösung?

Das Schätzen der Kosten für das Unternehmen ist dabei der weitaus schwierigere Teil des Unterfangens. Schon das Schätzen von Lösungen ist für Entwicklungsteams oft nicht einfach. Um vieles schwammiger erscheinen die Kosten, die die technische Schuld für das Unternehmen darstellt.

Um den Product Owner mit ins Boot zu holen, ist dieser Schritt aber unerlässlich. Was können wir tun? aim42 empfiehlt hier: Kosten sollten grundsätzlich immer als ein Intervall bestehend aus den niedrigsten und den höchsten zu erwartenden Kosten geschätzt werden. Die Intervallschätzung fällt uns häufig leichter, weil wir auf diesem Weg Eventualitäten mit berücksichtigen und unsere Unsicherheit beim Schätzen ausdrücken können. Wenn das Intervall sehr groß wird, dann ist das ein deutliches Zeichen dafür, dass die Unsicherheit zu groß ist und wir uns mehr Informationen besorgen müssen.

Selbstverständlich braucht solche Schätzung auch Erfahrung und Übung. Gerrit Beine regte in seinem Artikel über technische Schulden dazu an, solche Schätzungen mit einigem Abstand mehrfach zu wiederholen, um in Übung zu kommen [3]. Aber nicht nur um Schätzen zu üben, muss dieser Prozess regelmäßig wiederholt werden. Auch die Weiterentwicklung des Systems führt dazu, dass sich die Schätzungen verändern sollten.

Ist dieser schwierige Schritt des Schätzens gelungen, so hat man eine gute Basis, um mit dem Product Owner über technische Schulden zu sprechen. Wenn der Product Owner beispielsweise erfährt, dass die technischen Schulden einer seiner Softwarekomponenten monatliche Kosten zwischen 30 000 und 50 000 Euro verursacht, das Beheben des Problems wiederum 100 000 Euro bedeuten würde, kann er eigenständig bewerten und entsprechende Entscheidungen treffen.

Beispiel einer Schätzung von technischen Schulden

Als Beispiel soll uns eine Client-/Server-Anwendung dienen. Die Architektur der clientseitigen Software erlaubt es nicht, Remote-Services gegen lokale Dummyservices auszutauschen. Folglich muss währen der UI-Entwicklung die Anwendung beim Start darauf warten, dass ein Remote-Service Daten vom Server abholt und im Client visualisiert. Folgende Messungen und Annahmen sind in unserem Beispiel möglich:

  • Die messbare Zeit der Datenübertragung beim Start der Anwendung beträgt 45 Sekunden pro Start.
  • Zwei Entwickler arbeiten im Pair zu einem Tagessatz von 800 Euro/Person
  • Wir nehmen an, dass die Anwendung 50 Mal pro Tag zur Überprüfung des UI-Layouts gestartet wird.
  • Die Entwicklung der UI-Komponenten wird schätzungsweise acht Wochen beanspruchen.

Daraus resultieren folgende Kosten:

  • 800 Euro Tagessatz = 0,028 Euro/Sekunde
  • 2 Entwickler * 45 Sek * 50 Anwendungsstarts/Tag * 0,028 Euro/Sek = 126 Euro/Tag
  • 40 Tage * 126 Euro = 5 040 Euro

Die technischen Schulden werden sich in den acht Wochen Entwicklungszeit auf 5 040 Euro summieren. Darin ist lediglich die reine Entwicklungszeit eingerechnet. Schätzungsweise 70 Prozent der Kosten einer Software entstehen erst nach der Auslieferung, in der Wartungsphase. Diese Kosten müssen wir über die Lebensdauer einer Software ebenfalls einberechnen. Annahmen dazu sind jedoch schon viel schwieriger zu treffen, daher bleiben wir bei den 5 040 Euro. Diesen kann nun der Aufwand für ein Refactoring gegenübergestellt und monetär bewertet werden. Liegt der Refactoring-Aufwand deutlich unter den technischen Schulden, wird der Product Owner dem Refactoring positiv gegenüber stehen. Ob er es sofort beauftragt, hängt allerdings von der Priorisierung der anderen technischen Schulden ab.

Der nächste Schritt

Hat man den Product Owner mit den Auswirkungen von technischen Schulden und ihren Kosten vertraut gemacht, kann der Product Owner allein oder auch zusammen mit dem Entwicklungsteam eine Priorisierung der technischen Schulden erarbeiten. Refactorings, die am meisten Einsparungen versprechen, stehen oben auf der Liste. Mit dieser Darstellung der Einsparungen gegen die Kosten des Refactorings kann der Product Owner in der Regel auch das Management überzeugen. Ist keine Einsparung zu erkennen, dann muss das Entwicklungsteam weiter mit den für sie offensichtlichen technischen Schulden leben – nur weil eine Konstruktion nicht den vom Entwicklungsteam gewünschten Qualitätskriterien genügt, muss der Product Owner kein Geld ausgeben. Möglicherweise sind aber auch funktionale Erweiterungen mehr wert als Refactorings – hier muss der Product Owner die Balance halten, damit das Produkt funktional wachsen kann und gleichzeitig seine Qualität auf einem guten Niveau bleibt. Hier ist die umfassende und mutige Entscheidung des Product Owners gefordert, die ihm kein Entwicklungsteam und kein Management abnehmen können. Im Endeffekt ist die Frage, ob der Product Owner die langfristige Verantwortung für das bei ihm angesiedelte Softwaresystem übernehmen will und kann. Steht das Management hinter dem Product Owner? Darf der Product Owner im Rahmen seines Budgets frei entscheiden?

Hat der Product Owner den Status in seinem Unternehmen, dass er über lange Zeit für die Erweiterung und den Erhalt „seines“ Softwaresystems zuständig ist, kann die Zusammenarbeit zu technischen Schulden zwischen Entwicklungsteam und Product Owner noch weiter gehen. Sind die ersten Erfolge beim Abbau von technischen Schulden sichtbar, kann es nach einiger Zeit sogar gelingen, dass der Product Owner regelmäßig kleinen Refactorings zustimmt. Dann kann das Entwicklungsteam kleinere technische Schulden und ihr Refactoring als eigene Tasks im Backlog vermerken, mit dem Product Owner priorisieren und schließlich entsprechend einplanen.

Hat das Team zudem noch die Möglichkeit, pro Iteration 10–20 Prozent des Budgets für Refactorings einzuplanen, so kann man davon ausgehen, dass die technischen Schulden auf den Korridor geringer Schulden begrenzt werden können. So schließt sich der Kreis wieder zurück zu Abbildung 1 und dem dort postulierten stetigen Wechsel zwischen Erweiterung und Erneuerung.

Weitere Details zur Analyse von technischen Schulden und Architektur verbessernden Refactorings finden Sie in meinem Buch „Langlebige Softwarearchitekturen – Technische Schulden analysieren, begrenzen und abbauen“ [2].

Geschrieben von
Dr. Carola Lilienthal
Dr. Carola Lilienthal
Dr. Carola Lilienthal ist Senior-Softwarearchitektin bei der Workplace Solutions GmbH und Mitglied der Geschäftsleitung. Sie hat an der Universität Hamburg studiert und dort zum Thema „Komplexität von Softwarearchitekturen“ promoviert. Seit 2003 analysiert sie im Auftrag ihrer Kunden in ganz Deutschland regelmäßig die Architektur von Softwaresystemen und fasst das Ergebnis in Qualitätsgutachten sowie mit priorisierten Refactoring-Maßnahmen zusammen. Außerdem leitet sie seit 2000 Softwareprojekte von unterschiedlicher Größe im Banken-/Versicherungs- und Logistikbereich und berät das Management kleiner und mittelständischer Unternehmen bei der Entwicklung einer modernen IT-Strategie.
Kommentare

Hinterlasse eine Antwort

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