Blog Sichtbare Komplexität gegen das verborgene Chaos

Sichtbare Komplexität gegen das verborgene Chaos

Ein Modul kann installiert, bereitgestellt, verwaltet, wiederverwendet und zusammengesetzt werden. Es ist eine zustandslose Software-Einheit, die eine präzise Schnittstelle bietet. So schreibt es Kirk Knoernschild in seinem Buch „Java Application Archicture“ (1), in dem er Entwurfsmuster zur Modularität erörtert. Werden diese Eigenschaften bei der Entwicklung einer modularen Software-Architektur berücksichtigt, lässt sich ein Softwaresystem gut strukturiert gliedern.

Es bietet sich an, die Module eines Systems sowohl horizontal entlang von Architekturschichten als auch vertikal entlang von fachlichen Grenzen zu schneiden. Auf der unteren Ebene entstehen so Module für Entity-Objekte. Darüber werden Module für den Zugriff auf die Persistenzschicht angelegt, bis am oberen Rand des Domain-Models schließlich Service-Module die Modellschicht abschließen. Ist der Client der Services eine Anwendung, so entstehen darüber noch Module für die Präsentationsschicht.

Im Sinne einer losen Kopplung werden die Module noch nach Interfaces und Implementierungen getrennt, so dass importierende Module nur Abhängigkeiten zu den Schnittstellendefinitionen haben. Auf diese Weise kommt schon in kleineren Anwendungen oft eine beträchtliche Anzahl von Modulen zusammen. Alle diese Module müssen ihre Abhängigkeiten untereinander in Form von Exporten und Importen inklusive Versionsangaben beschreiben. Dazu eignet sich OSGi besonders gut. Aber auch z.B. mit Maven lässt sich das Dependency Management bewerkstelligen.

Das ist komplex? Ich finde, ja! Die Abhängigkeiten der Module untereinander im Blick zu halten, ist nicht immer leicht.

Die Verwaltung von Abhängigkeiten ist deutlich einfacher, wenn Software als Monolith entworfen wird. Wie komplex aber ist in einem solchen Entwurf das Beachten von wohldefinierten Abhängigkeiten, die die Architekturschichten berücksichtigen und keine Zyklen zulassen? Wie aufwendig ist die Recherche nach Abhängigkeiten innerhalb der Software, wenn Änderungen durchgeführt werden müssen, ohne dass ungewollte Seiteneffekte entstehen? Die Abhängigkeiten sind da. Sie sind aber nicht offensichtlich, da sie nicht beschrieben werden. Der Entwickler muss sie also im Kopf haben oder aufwendig im Code recherchieren.

Meine Erfahrung ist, dass die Komplexität von Software aufgrund interner Abhängigkeiten erst spät in Erscheinung tritt. Oft ist dies der Fall, wenn mit einem Update ein Defekt in die Software eingebaut wird. Solche Defekte treten dann gerne an unerwarteten Stellen auf, da die Abhängigkeit zum geänderten Teil der Software nicht offensichtlich war.

Dies kann verhindert werden, wenn von vorneherein eine modulare Architektur mit wohldefinierten Abhängigkeiten entworfen wird. Die damit verbundene Komplexität und der entstehende Aufwand betrifft dabei im Wesentlichen das Dependency- und Build-Management. Hier ist die Komplexität zu verwalten. In der täglichen Entwicklungsarbeit tritt sie nicht zu Tage. Im Gegenteil: Durch die explizit beschriebenen Abhängigkeiten navigiert man als Entwickler zielsicher durch den Source Code.

Modularisierung bringt also keine zusätzliche Komplexität. Vielmehr macht sie Komplexität sichtbar!


(1) Knoernschild, Kirk (2012): Java Application Architecture: Modularity Patterns with Examples Using OSGi, Addison Wesley

 

Kommentar schreiben

Sicherheitscode
Aktualisieren