Was ist falsch an Schichten-Architekturen?
Die Abbildung veranschaulicht die Grundprobleme traditioneller Schichtenarchitekturen: Erstens die Verflechtung von Anwendung und externen Systemen. Und zweitens die ungeeignete Topologie des Schichtenmodells für die Modellierung mehrerer externer Systeme.
zu 1. Die Anwendung ist eng and die Datenbank gekoppelt. Die Anwendung funktioniert nicht ohne Datenbank. Änderungen im Datenbank-Layer haben direkte Auswirkung auf die Anwendung.
zu 2. Anwendungen nutzen i.d.R. mehr als ein externes System. Schichtenarchitekturen zwingen dem Modell eine starre Hierarchie der Schichten auf, die die parallele und gleichwertige Existenz mehrerer externer Systeme unberücksichtigt lässt.
Schritt 1: Entkopplung durch Abstraktion
Statt zum Beispiel in der Business-Logik direkt die Datenbank anzusprechen, kann diese durch die Einführung eines Adapters entkoppelt werden. Häufig werden Adapter als Teil der Anwendung implementiert, was die Anwendung weiterhin eng an die Datenbank koppelt. Dieses Problem lässt sich durch die Anwendung des Inversion of Control-Prinzips entschärfen.
Dazu definiert die Anwendung ein sog. "Required Interface", was so viel besagt wie: Damit ich arbeiten kann, muss irgendwer dieses Interface implementieren. Diese Aufgabe übernimmt der Adapter. Dieser befindet sich außerhalb der Anwendung und bindet die Datenbank gemäß den Vorgaben der Anwendung an. Der Kontrollfluss läuft jetzt entgegen der Abhängigkeitsrichtung. Die Anwendung ist nicht mehr von der Datenbank, sondern die Datenbank von der Anwendung abhängig.
Schritt 2: Auflösung der Schichten
Das zweite Problem von Schichtenarchitekturen, die strenge Hierarchie von Schichten, lösen wir auf, indem wir Schichten als externe Systeme modellieren und entsprechend neu anordnen.
Für jedes externe System definiert die Anwendung einen Port. Für eingehende Kommunikation (z.B. UI) beschreibt ein Port, wie die Anwendung benutzt wird. Für ausgehende Kommunikation (z.B. Datenbank) beschreibt ein Port, wie die Anwendung das externe System nutzen wird. Ports entkoppeln die Anwendung vollständig von ihrer Umgebung. Adapter adaptieren die Sprache der externen Systeme auf die Anforderung der Anwendung.
Schritt 3: Flexibilität durch Hexagone
Die Verwendung von Hexagonen schafft Platz und Flexibilität für die Modellierung einer größeren Anzahl von Ports und Adaptern ohne spezielle Hierarchie.
Hexagone bieten Platz, visualisieren das Drinnen und Draußen und machen klar, dass ausschließlich über Ports kommuniziert wird.
Was ist der Punkt?
Ports (aka. Interfaces) und Inversion of Control sind nichts Neues. Was also ist so besonders an Hexagonaler Architektur? Für mich sind dies zwei Punkte. Erstens eine neue Architektur-Topologie: Drinnen und Draußen. Und zweitens eine neue Sichtweise: Ich sage dir, wie du mit mir zu sprechen hast - I'll tell you.
Der zentrale Leitgedanke beim Entwurf der Anwendung ist, zu entscheiden, was Teil der Anwendung (drinnen) und was Teil der Umgebung (draußen) ist. Für Datenbanken, Message-Broker, etc. ist die Entscheidung einfach. Schwieriger hingegen wird die Entscheidung bei der UI. Ist das User-Interface Teil der Anwendung oder nicht?
I'll tell you: Das zweite Prinzip Hexagonaler Architekturen ist die Kommunikationshoheit. Diese ist für eingehende Kommunikation einfach: Die Anwendung definiert ein klares Protokoll zur Nutzung ihrer Dienste. Für ausgehende Kommunikation lautet die Regel: Dies ist das Protokoll, nach dem ich mit dir reden werde.
Zusammengenommen bewirken beide Prinzipien maximale Entkopplung und den Fokus auf den eigentlichen Kern der Anwendung.