CppDepend: Schätzung und Management technischer Schulden
Einführung
Heutzutage ist die Metapher der technischen Schuld in der Softwarebranche weit verbreitet. Sie wurde geprägt von Ward Cunningham im Jahr 1992.
Dies Referenzartikel von Martin Fowler beschreibt die Metapher der technischen Schulden sehr detailliert. Zitat von M. Fowler:
In dieser Metapher lädt uns das schnelle und schmutzige Erledigen von Dingen eine technische Schuld auf, die einer finanziellen Schuld ähnelt. Wie eine finanzielle Schuld verursacht die technische Schuld Zinsen Zahlungen, die in Form des zusätzlichen Aufwands anfallen, den wir in der zukünftigen Entwicklung wegen der schnellen und schmutzigen Designentscheidung leisten müssen. Wir können wählen, weiter die Zinsen zu zahlen, oder wir können die Tilgung leisten, indem wir das schnelle und schmutzige Design in das bessere Design refaktorisieren. Obwohl die Tilgung Kosten verursacht, profitieren wir von reduzierten Zinszahlungen in der Zukunft.
Mit CppDepend Code-Regeln können über C#-LINQ-Abfragen geschrieben werden. Auf eine Codebasis angewendet, erzeugt eine Regel Probleme. Eine dedizierte Debt-API wird angeboten, um sowohl die technischen Schulden als auch die jährlichen Zinsen des Problems über in C# geschriebene Formeln zu schätzen. Sowohl die technischen Schulden als auch die jährlichen Zinsen eines Problems werden in Personenzeit gemessen.
- Der technische-schuld ist der geschätzte Zeitaufwand, der zur Behebung des Problems nötig wäre.
- Der jährliche-zinsen ist die geschätzte Personenzeit pro Jahr, wenn das Problem unbehebt bleibt. Dies liefert eine Schätzung von geschäftliche Auswirkung des Problems.
Zum Beispiel:
warnif count > 0
from m in Methods
where m.CyclomaticComplexity > 10
select new {
m,
m.CyclomaticComplexity,
Debt = (3*(m.CyclomaticComplexity-10)).ToMinutes().ToDebt(),
AnnualInterest = (m.PercentageCoverage == 100 ? 10 : 120).ToMinutes().ToAnnualInterest()
}In diesem Beispiel matcht die Regel Methoden, die zu komplex sind, wobei die Komplexität gemessen wird über Zyklomatische Komplexität Codemetrik. Wir sehen:
- Der technische-schuld ist proportional zur Komplexität oberhalb eines bestimmten Schwellenwerts.
- Der jährliche-zinsen beträgt 10 Minuten pro Jahr, wenn die Methode zu 100 % testabgedeckt ist, sonst 2 Stunden pro Jahr.
Eine komplexe Methode sowohl unrefaktorisiert als auch ohne Testabdeckung zu lassen, ist eine fehleranfällige Situation. Bestenfalls beeinträchtigt eine solche Situation die Wartbarkeit des Codes, schlimmstenfalls endet sie in Bugs zur Produktionszeit. Die jährlichen Zinsen schätzen die durchschnittlich Kosten pro Jahr, wenn die komplexe Methode nicht refaktoriert wird. Dies verschlimmert sich, wenn die Methode auch nicht testabgedeckt ist. Das Wort durchschnittlich wird hier hervorgehoben, weil beispielsweise von 8 komplexen und ungetesteten Methoden vielleicht nur eine einen Fehler hat, dessen Entdeckung, Untersuchung, Behebung und Auslieferung 2 Personentage (2x8 Stunden) kostet.
Jede Regel im Satz der Standardregeln enthält Formeln zur Berechnung der technischen Schulden und der jährlichen Zinsen für jedes Problem. Regeln und Formeln können erstellt und angepasst werden, um besser zu den Anforderungen und Gewohnheiten Ihres Teams zu passen, da es sich nur um rohes C# handelt, das in Visual Studio bearbeitet werden kann. Der Hauptvorteil ist, dass ist die Schätzung der technischen Schulden vollständig transparent und mit CppDepend leicht anpassbar.
Jahreszins und Schweregrad
Die jährlichen Zinsen sind ein Maß für Problemschweregrad. Der Schweregrad und die jährlichen Zinsen repräsentieren dasselbe Konzept wobei die jährlichen Zinsen ein kontinuierliches Maß sind, während der Schweregrad ein diskretes Maß ist.
CppDepend definiert 5 Schweregrade, und der Schweregrad eines Issues wird über Schwellenwerte auf Basis der jährlichen Zinsen geschätzt.
- Niedrig: Ein Problem mit niedrigem Schweregrad stellt eine kleine Verbesserung dar, eine Möglichkeit, den Code eleganter aussehen zu lassen. Standard-Annual-Interest-Schwellenwert: null oder weniger als 2 Mannminuten pro Jahr.
- Mittel: Ein Problem mit mittlerem Schweregrad stellt eine Warnung für ein Problem dar, das – selbst wenn es nicht behoben wird – keine signifikanten Auswirkungen auf die Entwicklung haben wird. Standard-Annual-Interest-Schwellenwert: weniger als 20 Mannminuten pro Jahr.
- Hoch: Ein Problem mit hohem Schweregrad sollte schnell behoben werden, kann aber bis zum nächsten geplanten Intervall warten. Standard-Annual-Interest-Schwellenwert: weniger als 2 Mannstunden pro Jahr.
- Kritisch: Ein Problem mit kritischem Schweregrad sollte nicht in die Produktion gelangen. Aus zwingenden geschäftlichen Gründen kann es dennoch geschehen, aber es muss spätestens in den nächsten Iterationen behoben werden. Standard-Annual-Interest-Schwellenwert: weniger als 10 Mannstunden pro Jahr.
- Blocker: Ein Issue mit dem Schweregrad Blocker darf nicht in die Produktion gehen, es muss behoben zu werden. Standard-Schwellenwert für Annual Interest: mehr als 10 Personenstunden pro Jahr.
Beachten Sie, dass das Konzept von kritisches Problem unterscheidet sich vom Konzept von kritische Regel. Der Schweregrad eines Problems hängt nicht damit zusammen, ob seine Regel kritisch ist oder nicht. Eine Regel kann als kritisch markiert werden, um eine Einschränkung durchzusetzen – zum Beispiel kann ein Quality Gate geschrieben werden, das bei einer kritischen Regelverletzung fehlschlägt.

Schuldeinstellungen
Berechnung und Ergebnisse der technischen Schulden können über die Einstellungen im Panel CppDepend > Projekteigenschaften > Issues and Debt.

Sie sehen:
- Schwellenwerte zu Issue-Schweregrad und jährlichen Zinsen, die im vorherigen Abschnitt erklärt wurden
- Schwellenwerte zum SQALE-Debt-Rating, erklärt im nächsten Abschnitt
- Zwei multiplikative Faktoren, die auf alle geschätzten Werte für technische Schulden und jährliche Zinsen angewendet werden können. Standardmäßig sind diese Faktoren auf 1 gesetzt.
- Um sicherzustellen, dass Schuldenschätzungen in aussagekräftigen Personenzeit-Maßen angezeigt werden, betreffen die Einstellungen Anzahl der Arbeitsstunden pro Tag oder Anzahl der Arbeitstage pro Jahr kann angepasst werden.
- Es gibt außerdem Einstellungen, um zu wählen, wie Debt-Werte formatiert werden, und um Schuldwerte in Personenzeit in Schuldwerte als Geldkosten.

SQALE-Schuldquote und Schuldbewertung
Der SQALE-Methode (üblicherweise "scale" ausgesprochen) ist eine standardisierte Methode zur Bewertung technischer Schulden. CppDepend implementiert Schuldquote und die Schuldbewertung die Teil der SQALE-Methode sind.
Der Schuldquote auf einer Codebasis oder einem Codeelement wird als Prozentsatz der geschätzten technischen Schulden ausgedrückt, verglichen mit dem geschätzten Aufwand, das Codeelement von Grund auf neu zu schreiben. Der geschätzte Aufwand für das Neuschreiben des Codeelements wird aus der Größe des Codeelements in Codezeilen abgeleitet, und aus dem Schuldeinstellung namens Geschätzte Anzahl an Personentagen zur Entwicklung von 1.000 logischen Codezeilen (siehe den Screenshot im vorherigen Abschnitt über die Debt-Einstellungen).
Der Wert des Geschätzte Anzahl an Personentagen zur Entwicklung von 1.000 logischen Codezeilen Einstellung ist nur eine Schätzung, daher ist sie kurzfristig bedeutungslos. Nach einigen Personenmonaten oder sogar Personenjahren Entwicklung ist dieser Wert typischerweise stabil genug, um sich für Schätzzwecke darauf zu verlassen. Diese geschätzte Einstellung muss auch die Kosten für das Schreiben von Unit-Tests berücksichtigen. Der Standardwert ist 18 Personentage, was einem Durchschnitt von 55 neuen logischen Codezeilen entspricht, 100 % durch Unit-Tests abgedeckt, geschrieben pro Tag, pro Entwickler.
Der Schuldbewertung einer Codebasis oder eines Codeelements wird aus Schwellenwerten abgeleitet, die auf das Debt Ratio angewendet werden. Das Debt Rating liegt im Bereich A, B, C, D, E. Die vier Schwellenwerte sind im Debt-Einstellungspanel anpassbar (siehe Screenshot im vorherigen Abschnitt über die Debt-Einstellungen). Die Standardschwellenwerte sind:
- [ 0 , 5 % [ Debt Ratio führt zu einem A-Rating.
- [ 5 % , 10 % [ Debt Ratio führt zu einem B-Rating.
- [ 10 % , 20 % [ Debt Ratio führt zu einem C-Rating.
- [ 20 % , 50 % [ Debt Ratio führt zu einem D-Rating.
- 50 % oder mehr Debt Ratio führen zu einem E-Rating.
Die Werte Debt Rating und Debt Ratio der Codebasis werden im Dashboard angezeigt. Im Abschnitt Durchsuchen der technischen Schuld zeigen wir, dass einfache C#-Code-Abfragen die Werte Debt Ratio und Rating für jedes Code-Element anzeigen können.

Priorisierung von Issue-Fixes und die Breaking-Point-Metrik
Der Breaking Point eines Problems oder einer Gruppe von Problemen ist der Zeitpunkt ab jetzt, an dem die geschätzten Kosten zur Behebung des Problems/der Probleme die geschätzten Kosten erreichen, das Problem/die Probleme unbehoben zu lassen.
Der Breaking Point ist der Schuld geteilt durch die jährlichen Zinsen. Wenn beispielsweise die geschätzten Kosten zur Behebung der Schuld 10 Personentage betragen und die geschätzten jährlichen Zinsen 2 Personentage pro Jahr betragen, liegt der Break-even-Punkt in 5 Jahren ab jetzt.
Beachten Sie, dass ein Breaking Point, der niedriger als pro Jahr bedeutet, dass es in den nächsten 12 Monaten geschätzt günstiger ist, die Schuld zu beheben, als sie nicht zu beheben.
Beachten Sie auch, dass ein Break-even-Punkt nicht in Personenzeit wie Schulden oder jährliche Zinsen gemessen wird (Personenmonat oder Personenjahr), sondern in regulärer Dauer (Monate oder Jahre). Break-even-Werte werden als TimeSpan typisiert.
Wenn es um Priorisieren der zuerst zu behebenden Problemeist der Schweregrad des Problems ein wichtiger Parameter. Zur Erinnerung: Der Schweregrad ist das diskrete Maß der jährlichen Zinsen. Je höher also die jährlichen Zinsen, desto wichtiger ist die Behebung.
Bei einem bestimmten Schweregrad sind jedoch nicht alle Probleme gleich. Einige erfordern mehr Aufwand zur Behebung. Dies wird durch die Technical-Debt-Messung geschätzt. Um daher die Return on Investment (ROI) einer Problembehebung ist es sinnvoll, die Schulden geteilt durch die jährlichen Zinsen zu schätzen. Diese Schätzung ist der Break-even-Punkt, bei dem gilt: je niedriger der Wert, desto höher der ROI.
Präzisieren wir, dass im Satz der Standardregeln Issues, die sich auf neue Probleme seit der Baseline beziehen, wie etwa API-Breaking-Changes, Qualität der Codeelemente, die noch schlechter wird, neue, nicht getestete Codeelemente... sind Issues, die höhere jährliche Zinsen und damit einen höheren Schweregrad erzeugen als die anderen Issues. Dies entspricht die bewährte Methode, kürzlich eingeführte Issues zuerst zu beheben.

Durchsuchen der technischen Schuld
In der Einführung haben wir gesehen, dass Code-Regeln werden über C#-LINQ-Abfragen implementiert und wir haben außerdem gesehen, dass die Schätzungen von Schulden und jährlichen Zinsen aus Formeln abgeleitet werden, die in diese LINQ-Abfragen eingebettet sind.
Dies C#-LINQ-Abfrageschema geht weiter und kann zum Durchsuchen und Erkunden der technischen Schulden verwendet werden. Die Domäne Probleme ist eine Aufzählung aller in der Codebasis gefundenen Probleme. Abfragen, die auf dieser Domäne basieren, werden offensichtlich ausgeführt, nachdem alle Regeln ausgeführt wurden.
Zum Beispiel beim Klicken auf eine Anzahl von Issues im Dashboard, etwa neue schwerwiegende Probleme seit Baseline wird im Beispiel unten eine Codeabfrage generiert, um relevante Probleme aufzulisten. Beachten Sie, dass die Probleme nach Regeln oder nach Codeelementen gruppiert werden können. Im Screenshot unten sind die Probleme nach Regel gruppiert.

Beachten Sie das Menü Explore Debt auf dem Dashboard, das Abfragen zu den Regeln, Problemen und Codeelementen generiert, um die technischen Schulden eingehend zu untersuchen.

Rechtsklick auf Regelkategorie, wie die Codeabdeckung Kategorie hier, zeigt Menüs zum Abfragen von Issues dieser Kategorie:

Einige Standard-Abfragen für Schulden und Issues finden Sie in Hotspots Gruppe. Zum Beispiel die Abfrage Typ-Hotspots listet die Typen mit der höchsten Schuld zuerst.

Der Regeln Domäne ist eine Aufzählung aller aktiven Regeln. Sie listet sowohl verletzte als auch nicht verletzte Regeln auf. Abfragen können geschrieben werden, um Regeln nach Schulden und Anzahl der Probleme aufzulisten. Gefundene Regeln können über Kategorien gruppiert werden.
Es überrascht nicht, dass Coverage, Codequalität und Architektur die Kategorien sind, die oft die meisten Schulden und Issues erzeugen.

Die Baseline spielt eine wichtige Rolle bei der Untersuchung des Problemsatzes, da neue oder behobene Probleme seit der Baseline die Qualität der jüngsten Arbeit bewerten.
Standardmäßig ist die Baseline das Verlaufs-Analyseergebnis, das am nächsten vor 30 Tagen liegt, und standardmäßig wird höchstens einmal täglich ein Verlaufs-Analyseergebnis gespeichert.
Weil man bei der Bewertung der Qualität der jüngsten Arbeit sicherlich zwischen den Baselines von gestern, letzter Woche und letztem Monat wechseln möchte, ermöglicht Ihnen das CppDepend-Dashboard, eine temporär Baseline mit einem einzigen Klick. Die Menge der Schulden und Issues wird dann entsprechend in wenigen Sekunden neu berechnet.
Und da die Bewertung von Issues und Schulden seit der Baseline, wie gerade gesehen, wichtig ist, Hotspots Standardabfragen werden mit geliefert seit Baseline Version. Hier ist zum Beispiel eine Abfrage zur Bewertung Neue Schuld und Probleme pro Regel seit der Baseline.

Erwähnen wir eine Feinheit beim Abfragen von Schulden und Problemen. Typen enthalten Methoden und Felder, Namespaces enthalten Typen und Assemblies enthalten Namespaces. Daher sind Typen, Namespaces und Assemblies Codeelement-Eltern.
Alle problembezogenen ICodeElement Erweiterungsmethoden wie elem.Debt(), elem.AnnualInterest(), elem.Issues(), deren Version mit beginnt Alle das die Schulden und Issues für das übergeordnete Code-Element und alle seine Kindelemente zurückgibt. Daher:
- elem.AllIssues() gibt eine Aufzählung der Probleme im übergeordneten Codeelement und der Probleme in seinen untergeordneten Codeelementen zurück. Im Produkt verwenden wir manchmal die Terminologie kumulierte Probleme eines übergeordneten Code-Elements wie einer Assembly, eines Namespace oder eines Typs.
- elem.AllDebt() gibt die geschätzte aufsummierte Schuld für das übergeordnete Code-Element und seine untergeordneten Elemente zurück.
- elem.AllAnnualInterest() gibt die geschätzten aufsummierten jährlichen Zinsen für das übergeordnete Code-Element und seine Kindelemente zurück.
- elem.AllBreakingPoint() gibt den geschätzten Breaking-Point für das übergeordnete Code-Element und seine untergeordneten Elemente zurück.
Technische Schuld und Quality Gate
Sie finden Standard-Quality-Gates zu technischen Schulden und Issues, darunter Schuldprozentsatz, Neue Schuld seit Baseline oder Neue Blocker- / kritische / schwerwiegende Probleme. Quality Gates, die sich auf absolute Werte technischer Schulden beziehen, sind standardmäßig deaktiviert, da die richtigen Schwellenwerte nur im Kontext eines bestimmten Projekts definiert werden können.

Auf dieselbe Weise Probleme und Regeln sind als abfragbare Domänen vordefiniert, die eine Aufzählung von Issues oder Regeln liefern, die Domäne QualityGates ist eine Aufzählung von Quality Gates. Die Standardabfrage unten schätzt den Quality-Gate-Trend seit der Baseline. Beachten Sie, dass Quality Gates, die auf der Baseline basieren (wie Neue Schuld seit Baseline) haben weder einen Wert noch einen Status in der Baseline definiert.

Gründe, warum technische Schulden null oder unvollständig sein können
- Meine Schätzung der technischen Schuld zeigt null oder ?
Wenn die technische Schuld null oder ? ist, analysieren Sie wahrscheinlich ein Projekt, das mit einer älteren Version von CppDepend (v6 oder älter) erstellt wurde. Der Regelsatz früherer CppDepend-Versionen hatte keine Schuldenformeln, daher haben Probleme ohne Schuldenformeln standardmäßig eine Schuld von null.
In der Dashboard > Schuld-Panel Sie sollten einen Link namens sehen Erstellen Sie eine Regeldatei mit Standardregeln.
Das Klicken auf diesen Link erstellt automatisch eine Regeldatei, die alle neuen Standardregeln enthält – diejenigen mit Schuldenschätzungsformeln. Danach wird empfohlen, die aktuellen Projektregeln durch die Regeln zu ersetzen, die die technischen Schulden schätzen. Dazu kann Drag & Drop verwendet werden von Abfragen- und Regeln-Explorer Panel (sowohl für Regeln als auch für Regelgruppen). Beachten Sie, dass Schuldenformeln Regel-Kompilierungsfehler verursachen, wenn sie von älteren Versionen von CppDepend (v6 und älter) gelesen werden. Wenn Sie dieses Projekt mit CppDepend v6 oder älter verwenden möchten, klonen Sie es bitte zuerst.
Für angepasste Regeln empfehlen wir, deren Quellcode zu ändern, um eigene Schätzformeln für Schulden zu schreiben.
Beachten Sie abschließend, dass die Standard-Regeldatei im selben Verzeichnis wie die Projektdatei erstellt und mit einem relativen Dateipfad an das Projekt angehängt wird. Dieser Pfad kann bearbeitet werden über CppDepend-Projekteigenschaften > Paths Referenced. - Meine Schätzung der technischen Schulden ist unvollständig, da keine Code-Coverage-Daten bereitgestellt wurden
Nicht oder nur teilweise durch Unit-Tests getesteter Code stellt eine große Quelle technischer Schulden dar. Tatsächlich trägt jede von Tests unabgedeckte Codezeile zu den technischen Schulden bei. Deshalb zeigt der Debt-Abschnitt des Dashboards eine Warnmeldung an, wenn Import von Codeabdeckungsdateien ist im CppDepend-Projekt nicht eingerichtet.
- Code-Coverage-Daten in der Baseline nicht verfügbar
Wenn Codeabdeckung im aktuellen Analyseergebnis verfügbar ist, aber nicht im Baseline-Analyseergebnis, erzeugen regeln zur Codeabdeckung keine Probleme. In dieser Situation können Abdeckungsprobleme auf der Baseline nämlich nicht geschätzt werden, und alle Abdeckungsprobleme würden dann als neue Probleme erscheinen.
Oft tritt diese Situation auf, wenn ein Projekt erstellt wurde und das erste erhaltene Analyseergebnis keine Abdeckungsdaten enthält. Im CppDepend-Projekt ist die Standard-Baseline-Einstellung, das Baseline-Analyseergebnis zu wählen, das am nächsten liegt an vor 30 Tagen erstellt, sodass dieses Problem einen Monat bestehen bleiben könnte.
Typischerweise um diese Situation zu behebenempfehlen wir, Verlaufs-Analyseergebnisse zu entfernen, die keine Codeabdeckungsdaten haben. Dazu müssen Sie den Ordner öffnen, der die in CppDepend-Projekteigenschaften > Analysis > Baseline for Comparison > Historic Analysis Results (standardmäßig auf den Projektausgabeordner gesetzt). Identifizieren Sie dann den Ordner, der das zu entfernende Verlaufs-Analyseergebnis enthält, und löschen Sie einfach den Ordner.
Im Screenshot unten stellt der ausgewählte Ordner beispielsweise das History-Analyseergebnis dar, das am 13. Dezember 2016 um 8:59 Uhr erstellt wurde.
Wir verstehen, dass dieser manuelle Ordner-Eingriff nicht der optimale Weg ist, eine solche Situation zu lösen. Wenn Sie möchten, dass wir eine UI bereitstellen, die Verlaufs-Analyseergebnisse auflistet, anzeigt, welche keine Abdeckungsdaten haben (oder andere Mängel wie nicht aufgelösten Quellcode), und die das Entfernen ermöglicht.
Wir könnten auch einen Filter zur Analysezeit bereitstellen, der ein Analyseergebnis nicht als Verlauf speichert, wenn es bestimmte Kriterien nicht erfüllt (z. B. verfügbare Abdeckungsdaten).
Testen Sie CppDepend noch heute
Starten Sie Ihre 14-tägige kostenlose Testversion mit vollem Zugriff auf alle Dokumentationsfunktionen. Keine Kreditkarte erforderlich.
