Tools: NDepend v2017.1 Smart Technical Debt Estimation

Jeder Entwickler dürfte das folgende Szenario aus dem Alltag kennen: Es soll ein neues Feature/Anforderung in die bestehende Software integriert werden und dafür gibt es (wie fast immer) mehrere Möglichkeiten:

  • die Quick & Dirty Lösung – lässt sich schnell erledigen, obwohl man sich darüber bewusst ist über kurz oder lang wieder über diese Codestelle „stolpern“. Zukünftige Änderungen sind dadurch evtl. auch schwieriger zu implementieren und dann ist es in der Praxis oft so, dass man genau diese Codestelle im Nachhinein wieder ändern muss. Was oft mit deutlichem Mehraufwand verbunden ist (im Vergleich zur direkten sauberen Implementierung der neuen Funktion)

  • die „saubere“ Lösung – für die aber mehr Zeit und evtl. auch umfangreichere Änderungen an der bestehenden Software notwendig sind

Ward Cunningham entwickelte genau für dieses Problem die Metapher der technischen Schuld (engl. technical debt) für die möglichen Konsequenzen schlechter technischer Umsetzung von Software. Unter der technischen Schuld versteht man den zusätzlichen Aufwand, den man für Änderungen und Erweiterungen an schlecht implementierter Software im Vergleich zu gut implementierter Software einplanen muss. Im Grunde genommen entspricht eine technische Schuld einer monetären Schuld, da ja jeder zusätzliche Aufwand entsprechend zusätzliche Kosten generiert. Je länger nun eine monetäre Schuld besteht desto höher werden die Zinsen und je länger die technische Schuld besteht desto größer wird der Aufwand bzw. die Anstrengungen diese zu beheben. Nun hat man die Wahl die technische Schuld (z.B. durch Refactoring bzw. besseres Design) sofort zu begleichen oder später den höheren Aufwand in Kauf zu nehmen. Das Refactoring kostet dann zwar in diesem Moment Geld spart aber lange Sicht Aufwand (oder in Bezug auf eine monetäre Schuld Zinsen)!

NDepend bietet nun in der neuen Version die Möglichkeit die technische Schuld zu ermitteln, so dass man sich diese Codestellen gezielt analysieren und entsprechende Gegenmaßnahmen ergreifen kann.

Ursachen für die Entstehung der technischen Schuld

Technische Schuld entsteht überwiegend ganz bewusst. Ein Team steht vor einer Aufgabe und entscheidet sich für eine „Quick & Dirty“ Lösung. Irgendwann später, wenn man mehr Zeit hat, will man sich darum kümmern und eine saubere Lösung implementieren. Jetzt ist es leider oft so, dass die technische Schuld dabei nicht linear sondern exponentiell wächst. Dann kommt der erste „Workaround“ für die „Quick & Dirty“ Lösung, denn wenn diese eine Codestelle sowieso schon schlecht geschrieben ist, fällt es ja nicht weiter auf, wenn man noch ein paar weitere Zeilen schmutzigen Code dazu packt. Hier mal noch ein paar weitere Ursachen für die Entstehung einer technischen Schuld:

  • Versäumen der Korrektur von zu großem oder zu komplexen Code und Design
  • Fehlerhafte Definition oder Umsetzung der Architektur durch enge Kopplung, zyklische Abhängigkeiten der Komponenten oder das Fehlen geeigneter Schnittstellen und Fassaden
  • bewusstes Umgehen von definierten Regeln um (vermeintlich) schneller zu sein (Workarounds)
  • Fehlende Coding Standards/Coding Conventions
  • Aufschieben oder Nicht-Aktualisierung technischer und fachlicher Softwaredokumentation
  • Missachtung von Compilerwarnings und Ergebnissen statischer Code-Analyse
  • Aufschieben, Verzicht oder ungenügende Umsetzung automatisierter Modultests und Regressionstests
  • Missachtung von TODO oder FIXME oder XXX Hinweisen im Code
  • Missachtung von Codewiederholungen (redundanter Code)

Die oben gezeigte Liste von Ursachen hat keinen Anspruch auf Vollständigkeit und wenn man sich nun einzelne Punkte anschaut ist NDepend schon mit den Standardregeln in der Lage einzelne Ursachen zu ermitteln (z.B. zyklomatische Komplexität, zirkuläre Referenzen, enge Kopplung, usw.). Auf dieser Basis ist NDepend nun in der Lage die technische Schuld zu ermitteln (dazu später mehr). Neben den rein technischen Ursachen kann es aber durchaus noch weitere Ursachen geben:

  • Fachlicher Druck – neue Fachlichkeiten sollen schnell ausgeliefert werden (meistens bevor technische Aufräumarbeiten abgeschlossen sind). Dieser Druck könnte beispielsweise durch ein zeitnahes Produkt-Release erfolgen -> SCRUM-Iterationen von zwei Wochen inkl. Auslieferung den Kunden in diesem Rhythmus

  • Ungenügende qualitätssichernde Prozesse – wenn es in einem Projekt keine qualitätssichernden Prozesse gibt (oder diese nicht gelebt werden), welche die Technische Schuld laufend messen und Verbesserungsmaßnahmen einleiten

  • Ungenügendes technisches Wissen, um technische Entscheidungen treffen zu können, welche die Technische Schuld nicht erhöhen und im Optimalfall reduzieren

  • Ungenügende Kommunikation der gewählten technischen Lösungen und ihrer Hintergründe. Die Kommunikation kann auf vielerlei Arten erfolgen, beispielsweise durch selbsterklärenden Code, Dokumentation, Diagramme, Videos etc.

  • Hintenangestelltes Refactoring, wenn in Codeteilen, welche verbesserungswürdig sind, weiter Fachlichkeiten umgesetzt werden, ohne davor die Verbesserungen umzusetzen. Je mehr diese notwendigen Refactorings verzögert werden, desto aufwändiger werden sie bzw. die Umsetzung von Fachlichkeiten

Technische Schuld baut sich aber auch auf – wenn auch in geringerem Maße – wenn keiner der oben genannten Faktoren zutrifft. Technische Fehler entstehen bei der Softwareentwicklung ebenso wie fachliche Fehler. Wenn ihnen nicht durch qualitätssichernde Maßnahmen entgegengewirkt wird, erhöht sich die technische Schuld unwillkürlich mit jeder Änderung und Erweiterung der Software.

Smart Technical Debt Estimation von NDepend

Mit dieser Funktion sieht man auf einen Blick wie viel Zeit es kosten würde kritische Codestellen/Funktionen zu fixen bzw. ein Refactoring durchzuführen. Angenommen ein Entwickler implementiert eine neue Funktion und die NDepend Analyse würde ergeben, dass diese neu implementierte Funktion 30 Minuten an technischer Schuld generieren würde. Mit diesem Wissen kann der Entwickler diese Codestelle jetzt direkt fixen bevor sie überhaupt eingecheckt wird. Was dann wiederum auf lange Sicht Zeit und evtl. späteren zusätzlichen Aufwand einspart. NDepend weist dafür zwei Werte aus:

  • der Wert technical-debt (technische Schuld) ist geschätzte Zeit in Mann-Tagen, die es dauern würde das eigentliche Problem zu beheben

  • der Wert annual-interest (Jahreszins) ist die geschätzte Zeit in Mann-Tagen, die pro Jahr aufgewendet werden muss wenn das Problem nicht behoben wird (hiermit kann man die geschäftlichen Auswirkungen des Problems besser abschätzen)

Dabei kann der Wert für den annual-interest (Jahreszins) in folgende Schweregrade unterteilt/gruppiert werden:

  • Info – ein Problem, welches als Info ausgewiesen wird stellt eine kleine Verbesserung dar oder eine Möglichkeit, den Code eleganter zu gestalten. Standard annual-interest Schwelle: 0 oder weniger als 2 Minuten pro Jahr

  • Minor – ein als Minor gekennzeichnetes Problem stellt eine Warnung dar, auch wenn das Problem nicht gefixt wird sind keine wesentlichen Einflüsse auf die Entwicklung zu erwarten. Standard annual-interest Schwelle: weniger als 20 Minuten pro Jahr

  • Major – ein Problem, das als Major eingestuft wird sollte schnell behoben werden, kann aber bis zum nächsten geplanten Intervall warten. Standard annual-interest Schwelle: weniger als 2 Stunden pro Jahr

  • Critical – ein als kritisch ausgewiesenes Problem sollte nicht ausgeliefert werden bzw. in produktiven Code gelangen. Eine Behebung des Problems sollte auf alle Fälle eingeplant werden. Standard annual-interest Schwelle: weniger als 10 Stunden pro Jahr

  • Blocker – solche Probleme dürfen auf keinen Fall ausgeliefert bzw. in produktiven Code gelangen und müssen behoben werden. Standard annual-interest Schwelle: mehr als 10 Stunden pro Jahr

Einstellungen

Die Technical-debt Berechnungen und Ergebnisse können unter NDepend > Project Properties > Issues and Debt im Detail konfiguriert werden:

NDepend - Smart Technical Debt Estimation Settings

NDepend – Smart Technical Debt Estimation Settings

Einstellungen für Mann-Tage und Monetärwerte:

Einstellungen für Mann-Tage und Monetärwerte

Einstellungen für Mann-Tage und Monetärwerte

Auswertung der ermittelten Werte

Um die technische Schuld zu beurteilen verwendet NDepend die standardisierte SQALE-Methode. NDepend implementiert hierfür die Kennzahlen Debt Ratio (Schuldenqoute) und Debt Rating, die Bestandteil der SQALE-Methode sind. Dabei repräsentiert die Debt Ratio den Prozentsatz der geschätzten technischen Schuld, verglichen mit dem geschätzten Aufwand, den man aufwenden müsste, um den untersuchten Quellcode von Grund auf neu zu schreiben. Dieser ermittelte Wert wird dann in fünf Schwellwerte, das sogenannte Debt Rating, unterteilt. Dafür werden die folgenden Kategorien verwendet: A, B, C, D, E. Die Standardwerte innerhalb von NDepend sind dabei wie folgt definiert:

  • [0 , 5%] Debt Ratio entspricht einem A-Rating
  • [5% , 10%] Debt Ratio entspricht einem B-Rating
  • [10% , 20%] Debt Ratio entspricht einem C-Rating
  • [20% , 50%] Debt Ratio entspricht einem D-Rating
  • [50% oder mehr] Debt Ratio entspricht einem E-Rating

Diese Werte lassen sich natürlich in den NDepend-Einstellungen anpassen (siehe Screenshot weiter oben). Um sich die ermittelten Werte anschauen zu können wurde das NDepend Dashboard erweitert:

NDepend Dashboard v2017.1

NDepend Dashboard v2017.1

Zunächst ist unter 1 die Gesamteinschätzung des analysierten Quellcodes zu sehen (in diesem Fall ein B-Rating). Es wird auch gleichzeitig eine Aufwandsschätzung angezeigt, die den geschätzten Aufwand angibt, den man aufbringen müsste um ein A-Rating zu erreichen. Details kann man sich über den Menüpunkt Explore Debt anschauen. Im gezeigten Screenshot sieht man die technische Schuld pro definierter NDepend-Regel. Unter dem Menüpunkt Types Hot Spots sieht man die Gruppierung auf Typebene:

NDepend Types Hot Spots

NDepend Types Hot Spots

Mit Hilfe dieser Auswertung können einzelne Hotspots (auf Basis des Ratings) gezielt analysiert werden, um dann entsprechende Maßnahmen (Refactoring, neues Design, …) einzuleiten. In der Spalte Issues können erhält man detaillierte Informationen:

NDepend Issues

NDepend Issues

Fazit

Ich bin wirklich begeistert von diesem neuen Feature. Gerade in größeren Projekten, mit immer kürzer werdenden Releasezyklen, kann die technische Schuld stetig größer werden. Mit diesem Feature ist das Qualitätsmanagement immer auf einem aktuellen Stand und es können frühzeitig geeignete Gegenmaßnahmen ergriffen werden um die technische Schuld so gering wie möglich zu halten. Eine weitere Möglichkeit neue technische Schuld einzugrenzen ist die Erweiterung der Definition of Done (Voraussetzung ist hier natürlich der Einsatz der SCRUM-Methodik). Am Ende eines Sprints soll eine potentiell auslieferbare Version der Software vorhanden sein und ein vorher definierter Schwellwert an technischer Schuld darf nicht überschritten werden.

Doch die Zahlen/Auswertungen bzw. die Offenlegung der Codequalität kann auch mit Problemen verbunden sein, denn nicht jeder versteht die dargebotenen Zahlen und diese können dann dazu verwendet werden den Entwickler bzw. das Team unter Druck zu setzen. Gerade das Management hat oft nicht das technische Verständnis und zieht dann womöglich die falschen Schlüsse aus den ermittelten Zahlen. Als Beispiel könnte man die Lines of Code (LOC) nennen: Diese Kennzahl wird ja gerne verwendet um den Fortschritt zu messen. Doch was ist hier gut? 2000 Zeilen in zwei Wochen oder doch nur 500? Genau so wenig ist ein Entwickler, der pro Tag 200 Zeilen Code schreibt besser, als einer, der nur 30 verfasst. Hier ist also Vorsicht geboten und genau abzuwägen wem die gewonnen Zahlen präsentiert werden!

Literaturverzeichnis und Weblinks

Abk.Quelle
[1]NDepend - Smart Technical Debt Estimation
http://www.ndepend.com/features/technical-debt#Debt
[2]Compute and Manage the Technical Debt with NDepend
http://www.ndepend.com/docs/technical-debt
[3]Ward Cunningham - Wikipedia
https://en.wikipedia.org/wiki/Ward_Cunningham
[4]Martin Fowler - Technical Debt
https://martinfowler.com/bliki/TechnicalDebt.html
[5]Mit technischer Schuld (technical debt) umgehen
https://www.scrum.de/mit-technical-debt-umgehen/
[6]Wikipedia - Technische Schulden
https://de.wikipedia.org/wiki/Technische_Schulden
[7]Wer ist für technische Schulden verantwortlich?
https://www.norberteder.com/wer-ist-fur-technische-schulden-verantwortlich/

Kommentar verfassen

Fork me on GitHub