Software-Erosion gezielt vermeiden

18. September 2014Kai Spichale

Wenn Softwaresysteme wachsen oder über einen längeren Zeitraum entwickelt werden, nimmt deren Komplexität zu, falls keine Maßnahmen ergriffen werden, dies zu verhindern. Ein anderes Problem sind die Unterschiede zwischen geplanter und tatsächlich realisierter Architektur. Sicherlich kann sich die Architektur eines Systems im Verlauf seiner Entwicklung verändern − in agilen Projekten ist dies sogar die Regel, aber diese Änderungen sollten sich nicht zufällig ergeben, sondern bewusst getroffen werden. Daher sind Modulgrenzen klar zu definieren und regelmäßig zu überprüfen. Wie dies gemacht werden kann, beschreibt dieser Artikel.

Abbildung 1 zeigt die Größe der Bibliothek hibernate-entitymanager.jar von der Version 3.2.0.GA bis 4.3.5.Final. Die Code-Basis wuchs in diesen Versionen um ein Vielfaches. Gründe hierfür sind beispielsweise die Implementierung von JPA 2.0 und 2.1. Die Größe der Bibliothek macht deren Weiterentwicklung nicht einfacher, stellt aber nicht das eigentliche Problem dar: Kritisch ist die Zunahme der strukturellen Komplexität, welche ebenfalls in Abbildung 1 abgebildet ist. Die Metrik Average XS wurde mit Structure101 berechnet und kann als Metrik für „Überkomplexität“ bezeichnet werden. In der Version 3.2.0.GA waren 10% der Code-Basis laut dieser Metrik zu komplex. In der aktuellen Version 4.3.5.Final sind es jedoch fast 100%. Dieser hohe Wert lässt den Schluss zu, dass diese Bibliothek nur mit erhöhtem Aufwand verstanden und weiterentwickelt werden kann.

adesso_Software-Erosion

Die Metrik Average XS basiert auf den Komponenten Tangle und Fat. Tangles sind zyklische Abhängigkeiten zwischen Packages. Fat beschreibt die Komplexität der Vernetzung der Objekte in der Code-Basis. Auf Methodenebene wird Fat mit der zyklomatischen Komplexität berechnet.

Kopplung ist jedoch in einem objektorientierten System nicht nur unvermeidbar, sondern sogar erwünscht. Ein Objekt mit hohem Fan-In bedeutet beispielsweise hohe Wiederverwendung. Dennoch ist nicht jede Form von Kopplung erwünscht. Einige Beispiele dieser vermeidbaren starken Kopplung sind:

  • Vererbung: Tiefe Vererbungsbäume deuten auf einen komplexen Entwurf hin. Je tiefer die Vererbung, desto höher die Fehlerhäufigkeit. Vererbung kann meistens durch eine einfachere Komposition ersetzt werden.
  • Zeitliche Kopplung: Eine API mit nicht offensichtlicher Reihenfolgeerwartung sollte vermieden werden. Denn einerseits könnte die API falsch verwendet werden. Und andererseits wird das Wissen über die Eigenheiten einer API und ihrer Implementierung in den Client-Code übertragen, so dass dieser stärker als notwendig an die API und ihre Implementierung gebunden werden.
  • Zyklische Abhängigkeiten: Die Objekte eines Tangles können nicht unabhängig voneinander entwickelt, getestet und releast werden.

Es gibt somit verschiedene Formen der Kopplung, auf die geachtet werden sollte. Doch selbst harmloses Message Passing Coupling ist nicht zwischen beliebigen Objekten erlaubt, denn Modulgrenzen müssen eingehalten werden, um eine beabsichtigte Architektur zu implementieren.

Eclipse IDE unterscheidet zwischen non-accessible, discouraged und accessible Rules für Bibliotheken im Java Build Path. Mit der non-accessible Rule java/io/** können beispielsweise Dateizugriffe für bestimmte Module verboten werden. Es ist jedoch ratsam, solche Architekturregeln außerhalb der Eclipse zu definieren, um diese auch auf einem Continuous Integration Server anwenden zu können.

Auch mit SonarQube lassen sich Architekturregeln definieren. Mit der Regel Architectural Constraint kann analog zur non-accessible Rule in Eclipse der Import von Klassen bestimmter Packages eingeschränkt werden.

Empfehlenswert ist die Import-Kontrolle von Checkstyle, welche sowohl in Eclipse (bzw. vergleichbaren IDEs) als auch zentral in SonarQube angewandt werden kann. Zur automatischen Architekturvalidierung mittels Import-Kontrolle eignet sich auch Structure101 und Sonargraph Architect. Diese bieten im Gegensatz zu Checkstyle eine grafische Oberfläche zur Definition der Architekturregeln.

Ein weiteres Open-Source-Werkzeug zur Architekturvalidierung und -analyse ist jQAssistant. Dieses Werkzeug kann sehr einfach in den Build-Prozess integriert werden. Es ist vielseitig einsetzbar: Beispielsweise können auch fehlende Abhängigkeiten identifiziert werden, um ein Reflexion Model umzusetzen. Auch die Einhaltung von Namenskonventionen kann mit jQAssistant sichergestellt werden.

Mit den genannten Werkzeugen lassen sich Modulgrenzen definieren und durchsetzen. Einen alternativen Ansatz bieten OSGi Bundles. Deren interne Packages bleiben vor anderen Bundles verborgen. Eine potentielle Kopplung ist somit ausgeschlossen. Das heißt selbst Code mit viel Verbesserungspotential innerhalb eines OSGi Bundles, hat möglicherweise keinen negativen Effekt auf andere Bundles, sofern das für dieses Bundle verantwortliche Team damit umgehen kann.

Typischerweise werden Anwendungen in Schichten geteilt. Treu dem Motto „Teile und Herrsche“ besteht das System beispielsweise aus den Schichten Presentation, Service und Repository. Diese primär technische Aufteilung ist jedoch schon für mittelgroße Applikationen unzureichend. Die Service-Schicht, auf die die komplette Presentation-Schicht zugreifen kann, erlaubt zu viele potentielle Abhängigkeiten. Daher sollte die Code-Basis auch in fachliche Submodule eingeteilt werden. Diese Submodule, auch Slices genannt, sind vertikale Schnitte über alle technischen Schichten.

Fazit

Software-Erosion ist leider keine Ausnahme, sondern betrifft viele Projekte. Denn fast jede Softwareänderung führt zu einer Komplexitätszunahme. Daher ist es wichtig, regelmäßig durch Refactoring-Maßnahmen gezielt den Code zu verbessern. Software-Metriken und Coding-Rules helfen, die entsprechenden Stellen zu identifizieren. Zur Definition und Überprüfung von Modulgrenzen existieren unterschiedliche Werkzeuge. Der regelmäßige Vergleich zwischen geplanter Architektur und Implementierung hilft langfristig, die Qualität und Wartbarkeit einer Code-Basis aufrecht zu halten.

Wie schützen Sie Ihre Software vor dem Zerfall? Haben Sie weitere Lösungsvorschläge?

Kai Spichale Kai Spichale ist Software Architect bei der adesso AG. Sein Tätigkeitsschwerpunkt liegt in der Konzeption und Implementierung von Softwaresystemen auf Basis von Spring und Java EE. Er ist Autor verschiedener Fachartikel und regelmäßiger Sprecher auf Konferenzen.
Artikel bewerten:
1 Star2 Stars3 Stars4 Stars5 Stars
Loading...

Kommentar hinzufügen:

Ihr Kommentar: