Arbeitsplatz Bild G+D Netcetera

Hexagonal Architecture

Description

Thomas Wimmer von netcetera gibt in seinem devjobs.at TechTalk eine Einführung in das Software-Architektur-Prinzip der Hexagonal Architecture.

Beim Videoaufruf stimmst Du der Datenübermittlung an YouTube und der Datenschutzerklärung zu.

Video Zusammenfassung

In "Hexagonal Architecture" erklärt Thomas Wimmer das Ports-and-Adapters-Modell im Kontrast zur klassischen Schichtenarchitektur: Der Anwendungskern wird von der Außenwelt getrennt, Interaktionen erfolgen über Input-/Output-Ports sowie primäre (driving) und sekundäre (driven) Adapter. Er arbeitet heraus, dass die entscheidende Differenz die Richtung der Abhängigkeiten ist und verknüpft dies mit Prinzipien wie Single Responsibility/Common Closure und Dependency Inversion, gestützt auf stabile Schnittstellen (Ports). Zuschauer lernen, den Kern über Interfaces von Infrastruktur zu isolieren, Abhängigkeiten nach innen zu richten und Änderungen an UI oder Datenzugriff ohne Auswirkungen auf die Fachlogik zu ermöglichen.

Hexagonale Architektur vs. Schichten: Ports, Adapter und die Richtung der Abhängigkeiten – Ein Recap zu „Hexagonal Architecture“ von Thomas Wimmer (G+D Netcetera)

Warum wir zugehört haben: Ein kurzer Überblick

In „Hexagonal Architecture“ gab Thomas Wimmer (G+D Netcetera) in rund zehn Minuten einen konzentrierten Überblick über ein Architekturmuster, das viele Engineering-Teams aktuell beschäftigt. Wir haben aufmerksam zugehört – nicht nur, um die Grundidee der Hexagonalen Architektur zu verstehen, sondern vor allem, um den entscheidenden Unterschied zur klassischen Schichtenarchitektur präzise herauszuarbeiten. Seine Kernbotschaft lässt sich in einem Satz kondensieren: In der Hexagonalen Architektur zeigen alle Abhängigkeiten von außen nach innen. Diese in der Praxis oft übersehene Asymmetrie sorgt für klare Grenzen, stabilere Schnittstellen und weniger Änderungskaskaden.

Im Folgenden fassen wir den technischen Kern des Vortrags zusammen – präzise, ohne Spekulationen, und fokussiert auf das, was Software-Teams in ihrem Alltag anwenden können.

Ausgangspunkt: Die Schichtenarchitektur (Layered Architecture)

Wimmer startet bewusst mit einem Muster, das in nahezu jedem Projekt anzutreffen ist: die Schichtenarchitektur. Die Hauptidee: Das System wird in mehrere Schichten unterteilt, die jeweils einen bestimmten technischen Aspekt abbilden. Typischerweise denkt man an UI, Business-Logik und Datenhaltung. In der Praxis reicht diese Dreiteilung selten aus; komplexe Systeme führen zu mehr Schichten und damit zu feineren Trennlinien. Dennoch bleibt die Regel: Eine Schicht darf nur mit der unmittelbar darunterliegenden Schicht kommunizieren.

Der Vorteil dieser Sichtweise ist eingängig: Wer an der Oberfläche (z. B. UI) arbeitet, soll sich nicht darum kümmern müssen, wo Daten herkommen oder wie sie zusammengesetzt werden. Die Delegation nach unten kapselt technische Details. Doch genau hier liegt auch die Schwäche, die später im Vergleich wichtig wird: Die Richtung der Abhängigkeiten verläuft nach unten – und das prägt, wie Änderungen durchs System propagieren.

Hexagonale Architektur in Kürze: Innen vs. Außen, Ports vs. Adapter

Die Hexagonale Architektur – auch als „Ports-and-Adapters-Architektur“ bekannt – teilt das System in eine Innenwelt (den Anwendungskern) und eine Außenwelt (alle externen Interaktionen) auf. Der Anwendungskern interagiert mit der Außenwelt ausschließlich über Ports. Die tatsächliche Anbindung an externe Systeme übernehmen Adapter, die an diese Ports „angedockt“ werden.

Wimmer führt durch einen typischen Kontrollfluss einer User-Interaktion:

  • Ein Benutzer will, dass das System etwas tut. Er interagiert mit einem UI-Adapter.
  • Adapter, die die Anwendung antreiben – also Aktionen initiieren – nennt er „treibende“ oder „primäre“ Adapter. Das UI ist ein Beispiel dafür.
  • Damit der UI-Adapter mit dem Anwendungskern sprechen kann, bietet der Kern Eingangsports an. Über diese Input Ports werden „Commands und Queries“ an das System gerichtet.
  • Der Anwendungskern führt daraufhin die Business-Logik aus: Regeln prüfen, Berechnungen durchführen, Entscheidungen treffen.
  • Wenn der Kern dabei externe Systeme benötigt (z. B. Datenbank, externe Services), ruft er Ausgangsports auf. Diese Output Ports werden von „getriebenen“ oder „sekundären“ Adaptern implementiert, die die tatsächliche Integration zu den externen Systemen herstellen.

Die Grundidee ist einfach und konsequent: Der Kern definiert, was gebraucht wird (Ports), die Adapter liefern, wie es angebunden wird (Implementierungen). So bleibt der Kern unabhängig von konkreten Technologien.

Der entscheidende Unterschied: Die Richtung der Abhängigkeiten

Auf den ersten Blick lassen sich Schichtenarchitektur und Hexagonale Architektur visuell ähnlich darstellen – bis man die Pfeile betrachtet. Laut Wimmer liegt der „wesentliche Unterschied“ im Richtungssinn der Abhängigkeiten.

  • In der Schichtenarchitektur zeigt die Business-Logik typischerweise nach unten auf die Datenhaltung. Änderungen in der Datenhaltung können sich daher nach oben fortpflanzen.
  • In der Hexagonalen Architektur hingegen zeigen die Abhängigkeiten der äußeren Schalen konsequent nach innen, auf den Anwendungskern. Adapter hängen vom Port ab, nicht umgekehrt. Wörtlich formuliert: „In der hexagonalen Architektur zeigen alle Abhängigkeiten der äußeren Schichten auf den Anwendungskern.“

Diese Umkehrung ist keine kosmetische Änderung – sie ändert, wie wir Grenzen ziehen, Zuständigkeiten verteilen und Änderungen managen.

Warum das wichtig ist: Prinzipien, die die Architektur tragen

Wimmer verankert den Unterschied in bekannten Designprinzipien und macht deutlich: Hexagonale Architektur setzt Grundsätze um, die wir aus SOLID kennen – aber auf Komponentenebene.

Single-Responsibility-Prinzip (SRP) auf Architekturebene

„Eine Klasse sollte nur einen Grund zur Änderung haben“ – auf höherer Ebene gilt das sinngemäß für Komponenten. Wenn das Datenzugriffslayer eine Änderung erfährt, sollte die Business-Logik nicht gezwungen sein, mitzuziehen, nur weil Abhängigkeiten das diktieren. In klassischen Schichtenaufbauten passiert jedoch genau das: Die oberen Schichten haben „immer mehr Gründe zur Änderung als die unteren Schichten“ – weil sie von ihnen abhängen.

Hexagonale Architektur adressiert dieses Problem: Änderungen in Adaptern sollen den Kern nicht beeinflussen – und umgekehrt. Das ist SRP operationalisiert über klare, stabile Schnittstellen.

Common Closure Principle (CCP)

Robert C. Martin hebt das „Common Closure Principle“ hervor: „Du solltest Dinge zusammenbringen, die sich zur gleichen Zeit und aus den gleichen Gründen ändern. Und du solltest Dinge trennen, die sich zu unterschiedlichen Zeiten oder aus unterschiedlichen Gründen ändern.“ Wimmer verweist darauf als SRP auf Architekturebene. In der Konsequenz heißt das: Wir gruppieren Volatiles zusammen und kapseln es vom Stabilen, sodass Änderungen sich nicht unnötig verbreiten.

Dependency Inversion Principle (DIP)

Wimmer nennt das Abhängigkeitsumkehrprinzip mit seinen zwei Regeln:

1) „High-Level-Module sollten nicht von Low-Level-Modulen abhängen. Beide sollten von Abstraktionen abhängen.“ In der Schichtenarchitektur hängt die Business-Logik (High-Level) vom Datenlayer (Low-Level). Das verletzt die Regel. Außerdem fehlen oft explizite Abstraktionen.

2) „Abstraktionen sollten nicht von Details abhängen, Details sollten von Abstraktionen abhängen.“ In der Hexagonalen Architektur übernehmen Ports diese Rolle als stabile Abstraktionen. Ports hängen nicht von Adaptern oder dem Anwendungskern ab; vielmehr hängen die Details (Adapter) von den Ports ab – ebenso wie der Kern. Wimmer formuliert es klar: „Wir führen stabile Abstraktionen ein … damit High-Level-Belange nicht von Änderungen der Low-Level-Belange betroffen sind.“

Das Ergebnis ist ein konsistentes Bild: Ports stehen im Zentrum als Verträge; Details richten sich danach aus.

Stabil vs. volatil: Verträge schützen vor Änderungsketten

Ein weiterer Akzent in Wimmers Vortrag ist die Unterscheidung zwischen stabilen und volatilen Komponenten. Stabil sind die Verträge zwischen Systemteilen – die Ports, also die Abstraktionen oder Schnittstellen (in statisch typisierten Sprachen wären das Interfaces). Volatil sind jene Teile, die wir bewusst häufig ändern wollen: Business-Logik und Infrastrukturcode. Seine Regel: „Ports sollten selten geändert werden und keine Abhängigkeiten haben.“

Dieser Punkt ergänzt DIP und CCP: Wenn sowohl Kern als auch Adapter von stabilen, unabhängigen Ports abhängen, bleibt der Änderungsaufwand lokal. Die Verträge sind der Fixpunkt, um den sich Details drehen.

Kontrollfluss konkret: Vom Klick zum Vertrag zur Integration

Wimmer zeichnet den Weg einer Benutzerinteraktion nach – ein guter Rahmen, um die Rollen sauber zu trennen:

  • Ein UI-Adapter fängt die Interaktion ab (z. B. ein Button-Klick) und ruft einen Eingangsport auf.
  • Der Eingangsport nimmt einen „Command“ oder eine „Query“ entgegen und übergibt damit die Absicht an den Anwendungskern.
  • Der Kern führt Geschäftsregeln aus, validiert, berechnet – ohne Wissen darüber, wie Daten gespeichert oder transportiert werden.
  • Benötigt der Kern externe Hilfe (Persistence, externe Dienste), ruft er einen Ausgangsport auf.
  • Ein getriebener Adapter implementiert den Ausgangsport und erledigt die konkrete Integration (z. B. Netzwerk- oder Datenbankzugriff), ohne dass der Kern ihn kennen muss.

Diese Choreografie wird durch den Grundsatz konsistent: Abhängigkeiten zeigen nach innen; Details hängen an Abstraktionen, nicht umgekehrt.

Vergleich zur Schichtenarchitektur: Wann ändern sich Dinge?

Wimmer macht die Auswirkungen anhand der Änderungsausbreitung klar. In einer Schichtenarchitektur kann eine Änderung im Datenlayer nach oben „bluten“ – weil Business-Logik davon abhängt. Ändert sich dann die Business-Logik, kann auch die UI betroffen sein. Kumulativ steigt die Änderungsanfälligkeit oben. In seinen Worten: „In einer Schichtenarchitektur haben die oberen Schichten immer mehr Gründe zur Änderung als die unteren Schichten.“

Die Hexagonale Architektur kontert das mit stabilen Ports und invertierten Abhängigkeiten: Adapterwechsel (z. B. eine neue Persistenztechnologie) soll den Kern unberührt lassen. Ebenso soll eine Business-Änderung nicht die UI oder eine externe Integration erzwingen – solange die Ports stabil bleiben.

Praktische Leitplanken: So setzt man die Ideen um

Auch wenn Wimmer keine Codebeispiele zeigt, lassen sich aus seinen Aussagen klare Handlungsanweisungen ableiten:

  • Eingangsports definieren: Der Anwendungskern bietet explizite Input Ports an, die „Commands und Queries“ entgegennehmen. Das ist die API des Kerns für treibende Adapter (z. B. UI).
  • Ausgangsports definieren: Für jede benötigte externe Fähigkeit (z. B. Persistenz, externe Systeme) definiert der Kern Output Ports. Diese spiegeln, was der Kern braucht – nicht, wie ein konkretes System das löst.
  • Adapter implementieren Details: Treibende (primäre) Adapter initiieren Aufrufe an Input Ports; getriebene (sekundäre) Adapter implementieren Output Ports. Beide hängen von Ports ab.
  • Abhängigkeiten nach innen ausrichten: Keine Abhängigkeiten vom Kern zu einem Adapter. Adapter kennen Ports; Ports kennen weder Kernel noch Adapter.
  • Ports stabil halten: „Ports sollten selten geändert werden und keine Abhängigkeiten haben.“ Jede zusätzliche Kopplung erhöht die Gefahr von Änderungskaskaden.

Diese Leitplanken setzen DIP und CCP praktisch um.

Missverständnisse vermeiden: Was Hexagonal nicht ist

Obwohl Wimmer sich auf die Kernprinzipien konzentriert, impliziert sein Vergleich ein paar häufige Missverständnisse, die sich vermeiden lassen:

  • Hexagonale Architektur ist keine bloße Schichtenarchitektur mit einem anderen Diagramm. Entscheidend ist die Abhängigkeitsrichtung, nicht die Anzahl der Ringe oder die Form des Bildes.
  • Ports sind keine technischen Protokolle oder Gateways, sondern Abstraktionen/Verträge. Wie die konkrete Integration aussieht, ist Sache der Adapter.
  • Primär vs. Sekundär beschreibt die Flussrichtung (treibend vs. getrieben), nicht eine Hierarchie der Wichtigkeit. Beide sind Details außerhalb des Kerns.

Alle drei Punkte leiten sich direkt aus der Gegenüberstellung und der von Wimmer betonten Abhängigkeitsumkehr ab.

Zitate und prägnante Formulierungen zum Merken

Wimmer hat mehrere Formulierungen benutzt, die als gedankliche Anker taugen:

  • „Teile dein Softwaresystem in eine Innen- und Außenwelt.“
  • „Adapter, die unsere Anwendung antreiben, nennen wir treibende oder primäre Adapter; die anderen sind getriebene oder sekundäre Adapter.“
  • „Input Ports akzeptieren Commands und Queries; Output Ports verbinden den Kern mit externen Systemen.“
  • „In der hexagonalen Architektur zeigen alle Abhängigkeiten der äußeren Schichten auf den Anwendungskern.“
  • Zum DIP: „High-Level-Module sollten nicht von Low-Level-Modulen abhängen … beide sollten von Abstraktionen abhängen“ sowie „Abstraktionen sollten nicht von Details abhängen, Details sollten von Abstraktionen abhängen.“
  • Zum CCP: „Du solltest Dinge zusammenbringen, die sich zur gleichen Zeit und aus den gleichen Gründen ändern, und trennen, was sich zu unterschiedlichen Zeiten oder aus unterschiedlichen Gründen ändert.“
  • „Ports sollten selten geändert werden und keine Abhängigkeiten haben.“

Diese Aussagen fassen den Kern zusammen: Stabilität durch Verträge, Schutz vor Kopplung durch Abhängigkeitsumkehr.

Auswirkungen auf den Alltag: Was ändert sich für Teams?

Auch ohne konkrete Tool- oder Framework-Tipps ist die Implikation klar: Architekturentscheidungen sind auch Designentscheidungen über Änderbarkeit. Wer die Hexagonale Architektur konsequent lebt, strukturiert sein Codebase rund um Verträge (Ports), anstatt technische Details (Adapter) zum Taktgeber zu machen. Damit folgt das System den Geschäftsbedürfnissen, nicht den Infrastrukturwechseln.

Praktisch heißt das:

  • Wenn die UI wechselt, bleiben die Input Ports stabil – die neue UI implementiert einen neuen treibenden Adapter.
  • Wenn die Datenbank oder ein externer Dienst wechselt, bleiben die Output Ports stabil – es entsteht ein neuer getriebener Adapter.
  • Wenn sich Business-Logik ändert, sind Ports der Puffer – so lange sich die externen Verträge nicht ändern müssen, bleiben Adapter unberührt.

Damit setzt man Wimmers Kernforderung um: „Änderungen in den Adaptern sollen den Kern nicht betreffen – und umgekehrt.“

Literaturhinweise aus dem Talk

Wimmer verweist auf Bücher von Robert C. Martin und Tom Homburg „über Clean Architecture“ sowie auf Blogartikel, die er als Referenzen genutzt hat. Wer tiefer einsteigen will, findet dort die Prinzipien (SRP, DIP, CCP) ausführlich hergeleitet und in den Architekturkontext übersetzt.

Schluss: Einladen zum Austausch

Zum Ende lädt Wimmer ausdrücklich zum Austausch über Softwaredesign ein – per Mail oder Twitter – und verweist darauf, dass Gespräche vielleicht bald auch „als Kolleginnen und Kollegen“ in ihren Büros in „Linz, Halenberg oder Wien“ stattfinden könnten. Der Talk bleibt bewusst kompakt; die Botschaft ist dafür umso klarer und für Engineering-Teams unmittelbar nutzbar.

Kompakte Takeaways für die Umsetzung

  • Trenne konsequent Innen (Anwendungskern) und Außen (Adapter). Der Kern definiert Ports; Adapter implementieren Details.
  • Richte alle Abhängigkeiten nach innen aus. Adapter hängen von Ports ab, nicht umgekehrt.
  • Halte Ports stabil und abhängigkeitsfrei. Sie sind die Verträge deines Systems.
  • Nutze Input Ports für „Commands und Queries“, Output Ports für externe Bedürfnisse.
  • Vermeide Änderungskaskaden, indem du CCP und DIP befolgst. Fasse Zusammengehöriges zusammen, trenne Unterschiedliches.
  • Beurteile jede Kopplung nach ihrer Änderungsrichtung: Details sollten Abstraktionen folgen, nicht diktieren.

Mit diesen Leitlinien wird die Hexagonale Architektur zu mehr als einem Diagramm: zu einer praktischen Strategie, die Wartbarkeit und Änderbarkeit in den Mittelpunkt stellt – genau so, wie es Wimmer in „Hexagonal Architecture“ von Thomas Wimmer (G+D Netcetera) pointiert vermittelt hat.