Was ist eine der unangenehmsten Erfahrungen für einen Entwickler? Viele werden sofort sagen: Änderungen an bestehendem Code durchführen, den man nicht selbst entwickelt hat und der am besten auch nicht dokumentiert und Unit-getestet ist.
Persönlich habe ich in einem hoch kritischen Projekt genau diese Erfahrung machen müssen. Selbst kleinste Änderungen an fremden Komponenten, die harmlos hätten sein müssen, sorgten dafür, dass etliche Unit-Tests (wenn vorhanden) fehlschlugen. Aufgaben, die an sich nur einige wenige Stunden hätten dauern sollen, führten zu tagelangen Reverse-engineering-Sessions. Ganz zu schweigen davon, dass nötige Refactorings nicht durchgeführt werden konnten, weil sie Querwirkungen auf die komplette Anwendung von UI bis Datenbank und einen anschließenden vollständigen Regressionstest bedeutet hätten.
Dieser Zustand änderte sich nach und nach, als sich mein Team darauf einigte, mehrere neue Architekturansätze zu verfolgen. Einer der wichtigsten davon ist der Ansatz der Clean Architecture.
Clean Architecture hat unser Team letztlich in die Lage versetzt, stabile, gut wartbare und leicht änderbare Software zu produzieren.
Nachfolgend möchte ich Ihnen diesen Ansatz erläutern.
Die Geschäftsregeln (Business Rules) einer Anwendung, egal wie groß, bilden den eigentlichen Wert einer Anwendung. Das hat mehrere Implikationen für deren Umsetzung: Sie sollten möglichst einfach und verständlich umsetzbar sein, sie sollten möglichst unabhängig von technischen Rahmenbedingungen zu pflegen sein und der Testaufwand bei Änderungen sollte möglichst niedrig sein.
Clean Architecture ermöglicht uns genau das, nämlich eine von Frameworks, der UI und der Datenbank unabhängige Umsetzung sowie eine bessere Testbarkeit der Business Rules.
Für die Entwicklung im Rahmen der Clean Architecture bedeutet dies grundlegend, dass die Business Rules von allen externen Faktoren unabhängig gemacht werden sollen, sodass Änderungen an „unwesentlichen“ Teilen der Software diese unberührt lassen.
Erreicht wird diese Unabhängigkeit durch eine Aufteilung der Software in verschiedene Schichten, die nur auf eine fest definierte Art und Weise miteinander kommunizieren dürfen.
Diese Schichten werden in innere und äußere Schichten unterteilt. Keine innere Schicht besitzt dabei Wissen über die Existenz von Schichten, die weiter außen liegen als sie selbst. Damit ist automatisch der Kontrollfluss vorgegeben. Eine Kommunikation kann nur von außen nach innen erfolgen und nicht umgekehrt.
Der Kontrollfluss richtet sich von den äußeren Schichten nach innen. Zwischen den Schichten werden Nachrichten in Form von einfachen, isolierten Datenstrukturen wie beispielsweise DTOs [Data Transfer Objects] ausgetauscht.
Die Anzahl der Schichten beschränkt sich nicht zwangsläufig auf die vier hier aufgezeigten Schichten. Bei Bedarf können so viele weitere hinzukommen, wie es für eine gegebene Software sinnvoll ist. Durch eine saubere Umsetzung dieser Architekturvorgabe wird es zwischen den Schichten keine zyklischen Abhängigkeiten geben.
Zyklische Abhängigkeiten entstehen, wenn Komponenten sich gegenseitig referenzieren.
Dadurch sind diese Komponenten nicht mehr lose gekoppelt und sie sind gegenseitig voneinander abhängig. Änderungen in Komponente A wirken sich direkt auf Komponente B aus. Dies kann zu unerwünschtem Verhalten der Software führen und erschwert auch deren Wartung.
Die Kapselung der einzelnen Schichten bietet unter anderem auch den großen Vorteil, dass das Austauschen eines Frameworks, beziehungsweise „Details“, wie zum Beispiel des OR[Object-Relational]-Mappers (Wechsel von MyBatis zu Hibernate) nur die konkrete Implementierung dieser Komponente betrifft und die Business Rules nach dem Austausch unbeschadet und ohne jegliche Anpassung weiter existieren.
Dies hat die positive Auswirkung, dass durch gute Schichtentrennung die Business Rules der Software zukunftssicher implementiert werden können. Die anfallenden Kosten eines Framework-Wechsels werden dadurch weitaus geringer sein, als wenn durch eine solche Änderung die komplette Anwendung angepasst werden muss.
Dies wird durch die Anwendung des Dependency-Inversion-Prinzips ermöglicht. Übergänge von Schicht zu Schicht können so sauber implementiert werden. Die Definition des Dependency-Inversion-Prinzips liest sich folgendermaßen:
Auf diesem Bild wird dargestellt, wie ein nicht näher definiertes Repository durch Anwendung des Dependency-Inversion-Prinzips zu einer Art „Plugin“ für eine Business-Klasse wird. Die konkrete Repository-Implementierung ist nun für die Business-Klasse unsichtbar geworden, sie verlässt sich auf die vom Interface bereitgestellte Funktionalität.
Ein weiterer Vorteil der Schichtentrennung ist, dass durch diese Aufteilung die Business-Logik einer Anwendung leicht testbar wird. Unit-Tests in der Business-Schicht müssen einzig die implementierte Logik abdecken.
Abbildung 3: Module höherer Ebenen sollten nicht von Modulen niedrigerer Ebenen abhängen. Beide sollten von Abstraktionen abhängen. Abstraktionen sollten nicht von Details abhängen. Details sollten von Abstraktionen abhängen.
Robert C. Martin: The Dependency Inversion Principle. 5/1996
Wenn man die Clean Architecture als Werkzeug ansieht, um eine gute Schichtentrennung und damit eine leichtere Änderbarkeit der Software zu erreichen, ist es eine meines Erachtens sehr gute Vorgehensweise, die die Qualität des entwickelten Produktes steigert.
Horrorszenarien wie das in der Einleitung angesprochene habe ich in mehreren Folgeprojekten, die auf Clean Architecture basierten, nicht mehr erlebt.
Tatsächlich hat mein Team es geschafft, eine sehr stabile Architekturgrundlage zu etablieren. Teammitglieder sind ohne nennenswerte Einarbeitungszeit in der Lage, von der Entwicklung einer Applikation, die darauf beruht, in ein anderes Entwicklungsteam zu wechseln und dort Features zu entwickeln. Und das, ohne dass Unit-Tests explodieren.
Allein diese Tatsache spricht aus meiner Sicht stark für diesen Ansatz.
Ich freue mich auf Ihre Fragen und Anmerkungen zum Thema „Softwarearchitektur“ und Clean Architecture. Auch bin ich sehr gespannt auf Ihre Meinung über Clean Architecture als modernen Architekturansatz.
Dieser Blogpost wurde bisher 10604 mal aufgrufen.
Blogpost teilen
Aktuelle Themen frisch aus dem Kopf. Wir freuen uns diese mit Ihnen zu teilen und zu diskutieren.