Dirk Richter
Software-Entwicklung und Architektur

Hintergrundwissen zu Technischen-Schulden


Inhaltsverzeichnis

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
  • Technische Schulden - Grafik

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 entsorgen
    • CA1062: Argumente auf null prüfen
    • CA1707: 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, die async sind, aber kein await 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.

Tipp: Sortiere die gefundenen Issues nach Typ und bearbeite zunächst kritische und häufige Warnungen.


ReSharper Testabdeckung auswerten

a) Testabdeckung messen

  1. Menü: ReSharper → Unit Tests → Cover Unit Tests
    (bzw. im Test-Explorer → Rechtsklick auf Testprojekt → Cover Unit Tests)
  2. 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.

Code-Analyse ohne Resharper (Demo)

Direkte Suche nach Sync-over-Async Pattern Sichere Codequalität bei asynchronen Methoden:

  1. Strg+Shift+F (Suche in gesamter Solution).
  2. Suche nach folgenden Mustern:
  • .GetAwaiter().GetResult()
  • .Result
  • .Wait()
  1. 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

  1. Menü: ReSharper → Unit Tests → Cover Unit Tests
    (bzw. im Test-Explorer → Rechtsklick auf Testprojekt → Cover Unit Tests)
  2. 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.

#Technicaldebt