Beliebte Suchanfragen
|
//

Hexagonale Architektur ist auch nur eine Insel

22.1.2025 | 10 Minuten Lesezeit

Stellt euch eine Insel namens "Alistair Island" vor. Diese Insel ist ein lebendiger Ort mit Häusern, fruchtbaren Böden und einer eingespielten Gemeinschaft von Bewohnern, die nach klaren Abläufen leben. Jedes Geschehen auf der Insel ist von Bedeutung und dient einem bestimmten Zweck. Die täglichen Aufgaben und Rituale sind festgelegt, und die Insel funktioniert wie ein gut koordiniertes Ensemble.

Die Insel ist von einem Festland umgeben, auf dem verschiedene Länder mit unterschiedlichen Industrien und Bevölkerungsgruppen existieren. Diese produzieren unterschiedliche Waren, bieten diverse Dienstleistungen an und sprechen verschiedene Sprachen. Die Bewohner des Festlands sind vielfältig und umfassen Handwerker, Händler, Postboten und viele andere Berufe.

Nicht nur variieren die Sprachen und Waren der verschiedenen Gebiete des Festlands. Auch die Bewohner der Insel haben ihre eigene Sprache und eine einzigartige Kultur, die sich von allem auf dem Festland Bekannten unterscheidet.

Obwohl die Insel isoliert ist, gibt es zahlreiche Verbindungen zur Außenwelt. An verschiedenen Küstenpunkten befinden sich Häfen, die Handel und Kommunikation mit dem Festland ermöglichen. Für den Transport von Nachrichten, Gütern und weiteren legen Schiffe an den Häfen des Festlands und der Insel an.

Um den Handel geordnet abzuwickeln, existiert ein Handelsabkommen. Es legt fest, dass Schiffe, die Waren von der Insel zum Festland transportieren oder umgekehrt, bestimmte Handelsrouten nutzen müssen. Schiffe, die vom Festland zur Insel fahren, nutzen die Routen, welche westlich der Insel liegen, während Schiffe, die von der Insel zum Festland fahren, die östlichen Routen befahren.

Es gibt verschiedene Arten von Schiffen. Große Frachtschiffe sind beladen mit Lebensmitteln und Vorräten. Passagierschiffe bringen Besucher zur Insel. Kleinere Boote dienen dazu, spezielle Nachrichten und Aufträge zu überbringen.

Jedes Schiff hat einen Heimathafen. Schiffe, die auf den westlichen Handelsrouten fahren und vom Festland aus entsandt werden, legen an einem festgelegten Hafen am Festland an. Die Schiffe von der Insel warten an den Häfen der Insel, um ihre Reise anzutreten.

Entscheidend ist also nicht, in welche Richtung Waren oder Nachrichten übermittelt werden, sondern wer den Auftrag dazu gegeben hat. Betrachten wir das Ganze stets aus Sicht der Insel, so sind Schiffe, welche vom Festland aus kommen, eingehende Schiffe. Schiffe, die von der Insel entsandt werden, sind ausgehende Schiffe. Egal ob sie Waren liefern oder eine Anfrage senden um Waren zu bekommen. Ein ausgehendes Schiff kann also durchaus die Intention haben, Waren vom Festland zur Insel zu transportieren. Dennoch gilt es als ausgehend, da die Intention von der Insel ausgeht.

Aufgrund der unterschiedlichen Sprachen der Inselbewohner und des Festlands müssen die Schiffe mit Übersetzern ausgestattet sein, um die Nachrichten des Festlands für die Inselbewohner verständlich zu machen. Auch die Güter müssen möglicherweise umverpackt werden, da auf dem Festland z. B. große Kräne zum Verladen genutzt werden, während auf der Insel alles händisch transportiert wird. Eine Qualitätsprüfung ist ebenfalls sinnvoll, um sicherzustellen, dass die Waren den Bedürfnissen der Insel entsprechen. Falls nicht, gibt das Schiff direkt Rückmeldung an das Festland. Das Ganze gilt selbstverständlich auch andersherum. Die ausgehenden Schiffe packen um, übersetzen und prüfen, ob die Waren für das Festland korrekt sind.

Die Schiffe sind die einzigen, die sowohl die Sprache der Insel als auch die des Festlands beherrschen und wissen, wie die Waren entsprechend umverpackt werden müssen. Sie sind jedoch nur für ihre jeweilige Handelsroute spezialisiert. Wenn neue Handelsrouten entstehen, kommt ein anderes Schiff zum Einsatz.

Ein weiterer wichtiger Aspekt dieser Welt ist die Stabilität der Insel. Die Stabilität der Insel bleibt, unabhängig von Änderungen der Güter oder des Baus neuer Häfen, erhalten. Lediglich die Art des Schiffes und dessen Besatzung müssen sich anpassen oder eine neue Handelsroute eingeführt werden. Die Bewohner der Insel erhalten ihre Waren und Nachrichten jedoch immer in der für sie gewohnten Art und Sprache.

So existiert Alistair Island, sicher und stabil, inmitten des weiten Ozeans. Ungeachtet neuer Schiffe oder Veränderungen auf dem Festland bleibt die Insel das, was sie ist: ein Ort voller Leben, Struktur und mit einer besonderen Verbindung zur Welt um sie herum.

Übertragung der Analogie in die Hexagonale Architektur

Lasst uns nun die Analogie der Insel, Häfen und Schiffe in die Begriffe der hexagonalen Architektur übertragen, um ihre Zusammenhänge zu verdeutlichen.

Insel - Domäne

Die Insel in unserer Analogie repräsentiert die Domäne – den Kern der Geschäftslogik. Die Insel ist das Zentrum, in dem alle wichtigen Prozesse und Abläufe stattfinden, genauso wie die Domäne der Ort ist, an dem die Geschäftslogik verwaltet und verarbeitet wird.

Schiffe - Adapter

Die Schiffe in der Analogie stehen für die Adapter in der hexagonalen Architektur. Sie sorgen dafür, dass die Kommunikation zwischen der Außenwelt und der Domäne tatsächlich stattfinden kann. Sie sind spezialisierte Übersetzer, welche die Sprache zwischen der Domäne und der Außenwelt (in beide Richtungen) übersetzen.

Adapter sind also maßgeblich dafür verantwortlich, dass die Anforderungen von außen in eine Form gebracht werden, die im Inneren der Domäne verarbeitet werden kann. Zudem bringen sie auch die Anforderungen nach außen in eine Form, die von der Außenwelt verstanden werden kann. Zum Beispiel könnte ein eingehender Adapter eine REST-API-Anfrage in ein Domänenobjekt übersetzen, während ein ausgehender Adapter die Domänenobjekte in eine für Datenbankabfragen oder externe API-Aufrufe verständliche Form bringt.

Wir unterscheiden also zwischen eingehenden und ausgehenden Adaptern:

  • Eingehende Adapter nehmen Aufträge von externen Systemen oder Aktoren (Festland) entgegen, übersetzen sie und stellen sie der Domäne bereit. Die eingehenden Adapter entsprechen den eingehenden Schiffen, die von den Häfen des Festlands starten, um auf die Insel zu gelangen.
  • Ausgehende Adapter hingegen nehmen die Antworten oder Daten der Domäne und bereiten sie für externe Systeme oder Aktoren (Festland) auf, damit sie verständlich und nutzbar sind. Die ausgehenden Adapter sind die ausgehenden Schiffe, die an den Häfen der Insel bereitstehen, um Informationen von der Domäne zurück an das Festland zu transportieren.

Ob ein Adapter nun ein eingehender oder ausgehender ist, entscheidet maßgeblich, wer den Auftrag initial gegeben hat. Dabei schauen wir immer aus der Sicht der Domäne (Insel).

Häfen - Ports

Die Häfen, die wir in der Analogie verwendet haben, entsprechen in der hexagonalen Architektur den sogenannten Ports. Ports sind die klar definierten Schnittstellen, über die die Domäne, also der Kern der Geschäftslogik, sich von der Außenwelt abgrenzt. Dabei wird zwischen eingehenden und ausgehenden Ports unterschieden. Wir haben in der Analogie schon einmal erwähnt, dass die Schiffe ebenfalls in eingehende und ausgehende unterteilt werden. Dabei war wichtig, wer den Auftrag erteilt und somit das Schiff entsendet hat. Die Ports (Häfen) bilden dies ebenfalls ab.

Zum Beispiel kann ein eingehender Port eine Bestellung aus einem Webshop entgegennehmen, während ein ausgehender Port Zahlungsinformationen an einen externen Zahlungsdienstleister übermittelt.

Wie ist die Domäne aufgebaut?

Interessanterweise haben wir uns bisher kaum mit dem Innenleben der Insel selbst beschäftigt – also damit, wie die Bewohner agieren, welche Strukturen und Rituale sie pflegen. Beispielsweise könnte man sich fragen, wie sie Güter effizient verteilen, Entscheidungen im Konsens treffen oder Regeln für ein harmonisches Zusammenleben festlegen. Was machen sie mit den Gütern und Nachrichten? Wie sind die Wege in der Stadt, welche Regeln gibt es und wie werden diese eingehalten? Das liegt daran, dass die eigentliche Gestaltung der Domäne – also der Kern der Geschäftslogik – kein Bestandteil der hexagonalen Architektur ist.

Die hexagonale Architektur konzentriert sich ausschließlich auf die Gestaltung der Schnittstellen (Ports) und den zugehörigen Adaptern. Diese Fokussierung ist zentral, da sie sicherstellt, dass die Domäne unabhängig bleibt und flexibel auf Änderungen in der Außenwelt reagieren kann, ohne ihre interne Logik zu gefährden. Wie die Menschen auf der Insel miteinander interagieren, welche Regeln sie befolgen und wie die alltäglichen Prozesse ablaufen, wird durch andere Architekturprinzipien geregelt. Ein Konzept wie Domain-Driven Design (DDD) kann unter anderem dafür verantwortlich sein, wie die Domäne strukturiert wird. Ihr könnt euch auch eigene Prinzipien ausdenken oder einfach drauf los bauen – all das hat keinen direkten Einfluss auf die hexagonale Architektur und wird auch nicht von ihr vorgeschrieben.

Die wichtigste Regel der hexagonalen Architektur ist: Trennt die Domäne von der Außenwelt. Lasst die Bewohner der Insel autark arbeiten und leben, keine Änderung der Außenwelt darf direkten Einfluss auf die Bewohner der Insel haben.

Warum eigentlich ein Hexagon?

Eine Frage, die bei Einsteigern in die hexagonale Architektur häufig aufkommt, ist: Warum ist es ein Hexagon? Braucht es immer sechs Elemente? Haben die gegenüberliegenden Seiten des Hexagons eine besondere Beziehung?

Die einfache, wenn auch etwas ernüchternde Antwort lautet: Es gibt keine tiefere Bedeutung hinter der Form des Hexagons. Alistair Cockburn, der diese Architektur konzipiert hat, fand die Form des Hexagons einfach spannend und wollte eine anschaulichere Bezeichnung für die Architektur als nur "Ports und Adapter". Tatsächlich ist "Ports und Adapter" der eigentlich korrekte Name für diese Architektur, aber er ist zu generisch und nicht besonders einprägsam.

Wie wir an dem Beispiel der Insel gesehen haben, funktioniert das Ganze auch mit komplett organischen Formen und braucht keine spezielle Geometrie. Das Hexagon ist nur ein symbolisches Mittel, um die unterschiedlichen Schnittstellen und Beziehungen anschaulicher darzustellen.

Vom Hafen zum Java Interface

Ein kleiner Hinweis vorweg: Wer Sprachen wie JavaScript, Python und Co. nutzt, wird die Interfaces vergebens suchen. In solchen Sprachen gibt es diese Schnittstellen nur als implizite Signatur. Das Prinzip bleibt jedoch gleich, auch wenn dort die Schnittstellen nicht explizit als Interface erzeugt werden.

Nun wollen wir uns aber anschauen, wie wir das Ganze im Code umsetzen. Dazu schauen wir uns einmal das folgende Diagramm an.

Wie wir sehen, haben wir hier zwischen eingehenden und ausgehenden Adaptern unterschieden. Das sind unsere Schiffe, die zwischen dem Festland und der Insel hin- und herfahren.

Die Insel ist auch in Form der Domäne vorhanden. Diese beinhaltet die Services und die Ports. Anhand der Pfeile könnt ihr nun gut erkennen, wer wen nur nutzt und wer wen implementiert. Wichtig ist hierbei noch, dass der Outbound-Port zwingend notwendig ist, da er dafür sorgt, dass die Dependency umgedreht wird. Dies folgt dem Dependency Inversion Principle. Der Inbound-Port ist technisch nicht zwingend notwendig. Der Adapter kann ohne Weiteres direkt auf den Service zugreifen. Durch die Einführung von Interfaces erhaltet ihr jedoch eine losere Kopplung. Außerdem leidet die Testbarkeit ein wenig, wenn ihr direkt von dem Adapter auf den Service zugreift. In der Regel solltet ihr also auch auf der eingehenden Seite einen Port vorsehen.

Nun schauen wir uns noch kurz an, wie das Ganze im Code aussieht.

Wir gehen einmal davon aus, dass wir ein Framework nutzen, welches die Dependency Injection für uns übernimmt. Spring wäre hier ein gutes Beispiel. Dann ist das alles ganz einfach: Wenn eine Klasse ein Interface nutzt, dann gebt ihr es als Übergabeparameter in den Klassenkonstruktor mit.

1//uses
2@Service
3class SomeService(private val forUsingPort: ForUsingPort){
4    // what ever your service does
5}

Implementiert eine Klasse nun ein Interface, dann tut ihr das, was der Name schon sagt. Ihr lasst die Klasse den Port (ForImplementingPort) implementieren. Das sieht dann so aus:

1// implements
2@Service
3class SomeService(): ForImplementingPort{
4     override fun functionOfPort(){
5         // what ever you should do here
6     }
7}

Und das ist es im Grunde auch schon.

Fazit

Die hexagonale Architektur wird häufig als überladenes Konzept wahrgenommen, doch sie beruht auf wenigen klaren Prinzipien, die ihre Anwendung überraschend einfach machen.

  • Trenne die Domäne von der Außenwelt. Die Geschäftslogik und Datenverarbeitung sollten unabhängig von der Datenbank oder Webframeworks gestaltet werden. Damit sie leichter ausgetauscht oder erweitert werden können.
  • Alles, was Technologie betrifft, sollte nicht in der Domäne sein.
  • Füge Ports rund um deine Domäne hinzu, um die beiden anderen Punkte sicherzustellen.

Wenn diese Grundsätze einmal verstanden sind, lässt sich die hexagonale Architektur fast immer anwenden. Selbst in kleinen Projekten ist es sinnvoll, die Domäne frei von technischen Details zu halten, um sie einfacher testen zu können. Zum Beispiel kann eine Geschäftslogik, die keine direkte Abhängigkeit zu einer spezifischen Datenbank hat, leicht in isolierten Unit-Tests überprüft werden. Die hexagonale Architektur hilft dabei und eignet sich hervorragend zur Unterstützung dieser Trennung.

Ein Tipp zum Einstieg: Ein Tool wie ArchUnit kann euch helfen, eure Umsetzung mit Tests zu überprüfen. Falls ihr darüber mehr wissen möchtet, schaut bei meinem Blogbeitrag zu ArchUnit vorbei: ArchUnit in der Praxis: Architektur sauber halten und optimieren

|

Beitrag teilen

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.