Hexagonale Architektur (Ports & Adapters)

Hexagonale Architektur (Ports & Adapters)

25. Oktober 2025 Allgemein 0

Aufbau & Vorteile einfach erklärt

hexagon

Wartbar, testbar, langlebig: Die Struktur deiner Software entscheidet über alles. Genau deshalb ist die Hexagonale Architektur — auch bekannt als Ports and Adapters — so einflussreich in der modernen Entwicklung.

Doch auf welcher Ebene der Gesamtarchitektur siedeln wir dieses Konzept eigentlich an? Und wie sieht das konkret im Code aus?

1. Wo steht die Hexagonale Architektur? (Ebene der Komponenten- und Modulararchitektur)

Um die Hexagonale Architektur richtig einzuordnen, wirf einen Blick auf die verschiedenen Architektur-Ebenen, wie sie im folgenden Schaubild dargestellt sind:

architekturebenen

Wie du siehst, befindet sich die Hexagonale Architektur klar auf der Ebene der Komponenten-/Modulararchitektur.

  • Frage dieser Ebene: Wie sind die Bausteine eines Systems intern strukturiert?
  • Ziel: Wartbarkeit, Testbarkeit, klare Verantwortlichkeiten.

Das bedeutet: Die Hexagonale Architektur beschäftigt sich nicht damit, ob du Microservices oder einen Monolithen baust (Systemebene), und auch nicht damit, wie deine Services kommunizieren (Integrationsebene). Sie regelt ausschließlich, wie der Code innerhalb eines einzelnen Moduls oder einer Komponente organisiert ist. Sie sorgt dafür, dass dein Fachwissen (die Geschäftslogik) vom Rest der Welt isoliert wird.

Das Herzstück: Ports and Adapters

Die Grundidee ist einfach: Trenn die Geschäftslogik von der Infrastruktur.

Stell dir die Anwendung wie einen Hexagon (sechsseitiges Polygon) vor. Dieses Sechseck ist der Anwendungskern. Alles, was die Kernlogik zum Funktionieren benötigt, geschieht über klar definierte Schnittstellen — die sogenannten Ports. Die Infrastruktur (Datenbanken, Web-APIs, Message-Queues) wird über Adapter angeschlossen.

 

Ports (Schnittstellen)

Ein Port ist eine Schnittstelle (Interface), die definiert, was die Außenwelt vom Kern erwartet (Driving Port) oder was der Kern von der Außenwelt erwartet (Driven Port).

  • Driving Port (Inbound): Die API, über die Benutzer mit der Anwendung interagieren. Definiert im Kern. Beispiel: UserService Interface mit der Methode createUser(UserCommand).
  • Driven Port (Outbound): Die API, über die der Kern mit der Infrastruktur interagiert. Definiert im Kern. Beispiel: UserRepository Interface mit der Methode save(User).
 

Adapters (Implementierungen)

Adapter sind die Implementierungen, die diese Ports mit der jeweiligen Technologie verbinden.

  • Driving Adapter: Implementiert den Driving Port. Er übersetzt externe Aufrufe (z.B. HTTP-Requests) in Aufrufe des Kerns. Beispiel: Ein UserController (REST-Controller), der den UserService aufruft.
  • Driven Adapter: Implementiert den Driven Port. Er übersetzt die Anfragen des Kerns (z.B. save(User)) in Infrastruktur-spezifische Aufrufe (z.B. SQL-Befehle oder MongoDB-Transaktionen). Beispiel: Eine JpaUserRepository oder MongoUserRepository.
Die goldene Regel: Die Abhängigkeitsrichtung zeigt immer Richtung Kern. Der Kern kennt die Adapter nicht, nur die Ports.
 

2.1 Inversion of Control: Der Schlüssel zur austauschbaren Infrastruktur

Der entscheidende Mechanismus, der diese Trennung ermöglicht, ist die Inversion of Control (IoC), genauer gesagt, das Dependency Inversion Principle (DIP).

 

Das Problem ohne IoC: Normalerweise würde der Kern direkt eine konkrete Implementierung kennen und nutzen:

 // Schlecht: Der Kern ist von der Infrastruktur abhängig

public class OrderServiceImpl {
    // Konkrete Abhängigkeit!
    private JpaOrderRepository repository = new JpaOrderRepository(); 
    // ...
}

Die Lösung mit IoC/DIP: Der Kern definiert nur die Schnittstelle (den Port), während die Infrastruktur die Implementierung (den Adapter) bereitstellt. Der Kern bekommt die konkrete Implementierung von einem externen Mechanismus, dem IoC Container (z.B. Spring oder CDI), injiziert.

// Gut: Der Kern ist nur vom Interface (Port) abhängig

public class OrderServiceImpl implements OrderService {

// Dependency Injection (IoC)

private OrderRepository repository; // Abhängig vom Port-Interface

 

public OrderServiceImpl(OrderRepository repository) {

this.repository = repository;

}

}

Durch diese Abhängigkeitsinversion ist der Kern nicht mehr von der Technologie des Adapters abhängig. Die Infrastrukturschicht (der Adapter) ist es, die vom Kern abhängt, da sie dessen Port-Interface implementieren muss.

Der Clou beim Austausch:

Wenn du die Datenbank wechseln möchtest, musst du nur den Infrastruktur-Adapter austauschen:

  • Alte Konfiguration: OrderRepository wird mit JpaOrderRepository verbunden.
  • Neue Konfiguration: Wir erstellen einen neuen Adapter, z.B. MongoOrderRepository, und konfigurieren den IoC Container so, dass er nun diesen neuen Adapter an den OrderService übergibt.

Der gesamte Code im Kern (OrderServiceImpl) bleibt dabei unverändert, was die Wartung und Evolution des Systems erheblich vereinfacht.

3. Umsetzung in einer Java Package Struktur

In einer typischen Java-Anwendung führt dieses Muster zu einer klaren, viergeteilten Paketstruktur. Nehmen wir als Beispiel eine Anwendung zur Verwaltung von Kundenaufträgen:

package struktur
tabelle2

Fazit: Die Vorteile der Isolation

Die Hexagonale Architektur ist der Königsweg zu wartbarer Software, da sie Isolation schafft:

  • Leichtere Testbarkeit: Der gesamte Kern (domain und application) kann ohne jegliche Datenbank- oder Netzwerkkonfiguration getestet werden. Wir müssen lediglich die Interfaces in ports.out durch Mock-Objekte ersetzen.
  • Technologiewechsel: Wenn du von MySQL auf PostgreSQL oder von REST auf gRPC wechseln musst, änderst du nur die entsprechenden Adapter in adapter.out oder adapter.in. Der Anwendungskern bleibt unberührt.
  • Klarheit: Die Verantwortung ist klar verteilt: Der Kern weiß, was getan werden muss, die Adapter wissen, wie es technisch umgesetzt wird.

Indem du diese Trennung konsequent durchsetzt, stellst du sicher, dass dein wertvollstes Gut — deine Geschäftslogik — immer sauber, testbar und vom schnelllebigen Infrastruktur-Lärm entkoppelt bleibt.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert