Dirk Richter
Software-Entwicklung und Architektur
Hintergrundwissen zu Technischen-Schulden
Inhaltsverzeichnis
- Zusammenfassung
- Was sind Technische Schulden?
- Code-Analysen (CA) und CA-Regeln
- Warum sind CA-Regeln wichtig?
- Wie hilft ReSharper?
- Live-Code-Analyse (Demo)
- Code-Analyse (Demo)
- ReSharper Testabdeckung auswerten
- Code-Analyse ohne Resharper (Demo)
- Visual Studio Code Metric Results
- Modularität und Entkopplung
- ReSharper Project Dependency Diagramm
- Unit-/Komponenten- und Integrationstests gegen technische Schulden
- ReSharper Testabdeckung auswerten
Zusammenfassung
- Der Text erklärt,
- was technische Schulden sind,
- wie sie entstehen
- und welche Folgen sie haben.
- Er beschreibt
- Methoden zur Erkennung technischer Schulden,
- insbesondere durch Code-Analysen (CA-Regeln)
- und Tools wie ReSharper.
- Es werden
- die Vorteile automatisierter Code-Prüfungen,
- die Bedeutung von Testabdeckung
- und Metriken wie Wartbarkeitsindex und Komplexität erläutert.
- Zudem wird auf
- Modularität,
- Entkopplung
- und die Visualisierung von Abhängigkeiten eingegangen.
- Abschließend zeigt der Text,
- wie Unit- und Integrationstests helfen, technische Schulden zu vermeiden und die Codequalität langfristig zu sichern.
Was sind Technische Schulden?
- Definition:
Kurzfristige, suboptimale Lösungen im Code, die langfristig zu höherem Wartungsaufwand führen. - Ursachen:
Zeitdruck, fehlende Tests, schlechte Architektur, unsaubere Implementierung - Folgen:
Mehr Aufwand, Fehleranfälligkeit, sinkende Entwicklungsgeschwindigkeit, höhere Kosten -
Code-Analysen (CA) und CA-Regeln
- Code-Analysen (CAs):
Automatisierte Prüfungen, die den Quellcode auf Fehler, Stil, Performance und Qualität untersuchen - CA-Regeln:
Nummerierte, konkrete Qualitätsregeln (z.B.CA2000
,CA1062
) aus der .NET-Welt- Decken Bereiche wie Design, Performance, Sicherheit, Wartbarkeit ab
- Beispiele:
CA2000
: Objekte vor Verlust des Gültigkeitsbereichs entsorgenCA1062
: Argumente auf null prüfenCA1707
: Keine Unterstriche in Membernamen verwenden
Warum sind CA-Regeln wichtig?
- Höhere Code-Qualität:
Frühzeitige Erkennung von Fehlern und schlechten Praktiken - Automatisierte Prüfung:
Integration in Build-Prozesse und IDEs möglich - Weniger technische Schulden:
Nachhaltige Codebasis, weniger Nacharbeit
Wie hilft ReSharper?
- Live-Code-Analyse:
Erkennt Fehler, CA-Regelverstöße und Verbesserungspotenziale direkt beim Schreiben - Sichtbare Hinweise:
Zeigt Probleme und Vorschläge im Editor mit Symbolen und Unterstreichungen - Quick-Fixes:
Sofortige Behebung vieler Verstöße per Tastenkombination (z.B. Alt+Enter) - Refactoring-Tools:
Umfangreiche Werkzeuge zur nachhaltigen Code-Verbesserung
Live-Code-Analyse (Demo)
- Farbliche Markierungen im Code
- Alt+Enter => beheben von Code Smells
- Cleanup (Vorsicht bei Cleanup über Solution)
Code-Analyse (Demo)
- ReSharper → Inspect → Code Issues in Solution
- Wichtige Issues gezielt untersuchen
- Reference/Null Reference Issues:
Suche nach Warnungen wie „Possible ’null’ reference exception“. - Empty general catch clause:
Filtere nach „Empty general catch clause“ – das fängt alle Exceptions, macht Debugging schwer. - Async function without await Expression:
Prüfe Methoden, dieasync
sind, aber keinawait
enthalten – das ist häufig ein Fehler. - Possible Multiple Enumeration:
Diese Warnung weist auf mehrfaches Durchlaufen von Enumerables hin (Leistungs- und Nebenwirkungsprobleme). - Weitere wichtige Issues:
- Unused Members: Toter Code.
- Redundant Suppression: Überflüssige Suppressions, die auf zu viele Fehler hinweisen könnten.
- Performance Critical Calls: Z.B. LINQ in Schleifen.
- Reference/Null Reference Issues:
Tipp: Sortiere die gefundenen Issues nach Typ und bearbeite zunächst kritische und häufige Warnungen.
ReSharper Testabdeckung auswerten
a) Testabdeckung messen
- Menü: ReSharper → Unit Tests → Cover Unit Tests
(bzw. im Test-Explorer → Rechtsklick auf Testprojekt → Cover Unit Tests) - Achtung: Da Unittests und Integrationstests vermischt sind und Integrationstests lange laufen:
- Isoliere Unittests:
Führe zunächst nur Unittests aus, um schnelle Rückmeldung zu bekommen. - Filter:
Nutze Test-Kategorien/[Traits] in den Attributen oder Testprojektstruktur, um Unittests zu selektieren. - Integrationstests separat:
Starte diese Tests ggf. manuell oder außerhalb der Abdeckungsauswertung. b) Auswertung
- Isoliere Unittests:
- Analysiere die Testabdeckung insbesondere im Produktivcode.
- Bereiche mit <70% Abdeckung sind kritisch.
- Prüfe, ob kritische oder komplexe Klassen ausreichend getestet sind.
Code-Analyse ohne Resharper (Demo)
Direkte Suche nach Sync-over-Async Pattern Sichere Codequalität bei asynchronen Methoden:
- Strg+Shift+F (Suche in gesamter Solution).
- Suche nach folgenden Mustern:
.GetAwaiter().GetResult()
.Result
.Wait()
- Prüfe, ob diese Aufrufe in asynchronem Kontext auftreten – das kann Deadlocks und Performanceprobleme verursachen.
Visual Studio Code Metric Results
- Maintainability Index:
Zeigt, wie wartbar der Code ist (niedrige Werte = Warnsignal). - Cyclomatic Complexity:
Misst Komplexität von Methoden. Hohe Werte sind kritisch (>10). - Class Coupling:
Zeigt die Abhängigkeit einer Klasse zu anderen. Hohe Werte erschweren Änderungen.
Modularität und Entkopplung
- Modularität:
Aufteilung der Software in klar abgegrenzte, eigenständige Module oder Schichten - Entkopplung:
Geringe Abhängigkeiten zwischen Modulen → Änderungen in einem Modul wirken sich kaum auf andere aus - Strikte Beziehungen:
Definition klarer, wohldefinierter Schnittstellen und erlaubter Abhängigkeitsrichtungen
(z.B. keine Abhängigkeit von unten nach oben in Schichtenarchitekturen) - Vorteile:
- Bessere Wartbarkeit und Testbarkeit
- Einfachere Wiederverwendbarkeit
- Mehr Übersicht und geringeres Risiko von Seiteneffekten
- Technische Schulden werden reduziert
ReSharper Project Dependency Diagramm
- Visualisierung:
Grafische Darstellung der Projekt- und Modulabhängigkeiten im Solution Explorer - Überblick:
Schnell erkennen, wie Projekte, Bibliotheken und Schichten miteinander verbunden sind - Problemerkennung:
Zyklische Abhängigkeiten, unerwünschte Kopplungen, Verletzungen der Schichtentrennung werden sichtbar - Optimierung:
Identifikation von Verbesserungsmöglichkeiten und gezielte Maßnahmen zur Entkopplung
Unit-/Komponenten- und Integrationstests gegen technische Schulden
- Frühes Erkennen von Fehlern:
Tests decken Fehler und unerwünschte Seiteneffekte sofort auf. - Sicheres Refactoring:
Mit guter Testabdeckung kann Code angstfrei umstrukturiert werden. - Dokumentation des Verhaltens:
Tests beschreiben das erwartete Verhalten und helfen neuen Entwicklern. - Schutz vor Verschlechterung:
Tests verhindern, dass bestehende Funktionalität versehentlich zerstört wird. - Förderung von Modularität:
Testbarer Code ist meist modular und sauber entkoppelt – das reduziert technische Schulden.
ReSharper Testabdeckung auswerten
a) Testabdeckung messen
- Menü: ReSharper → Unit Tests → Cover Unit Tests
(bzw. im Test-Explorer → Rechtsklick auf Testprojekt → Cover Unit Tests) - Achtung: Da Unittests und Integrationstests vermischt sind und Integrationstests lange laufen:
- Isoliere Unittests:
Führe zunächst nur Unittests aus, um schnelle Rückmeldung zu bekommen. - Filter:
Nutze Test-Kategorien/[Traits] in den Attributen oder Testprojektstruktur, um Unittests zu selektieren. - Integrationstests separat:
Starte diese Tests ggf. manuell oder außerhalb der Abdeckungsauswertung. b) Auswertung - Analysiere die Testabdeckung insbesondere im Produktivcode.
- Bereiche mit <70% Abdeckung sind kritisch.
- Prüfe, ob kritische oder komplexe Klassen ausreichend getestet sind.