Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hexagonale Architektur: Robuste Software dank S...

Hexagonale Architektur: Robuste Software dank Schnittstellen statt Schichten

Wir alle kennen diese Situation: Je älter und größer eine Anwendung wird, desto aufwendiger und teurer wird es, sie zu erweitern und zu warten. Die verbreitete Schichtenarchitektur ist als Lösungsansatz unzureichend: Direkte und indirekte Abhängigkeiten aller Schichten zur Datenbank und anderen Infrastrukturkomponenten führen oft zu einer Aufweichung der Schichtengrenzen und einer Verflechtung von technischem und fachlichem Code.

Hexagonale Architektur rückt die Geschäftslogik ins Zentrum, und technische Details werden als Adapter hinter Schnittstellen (Ports) isoliert. Fachlicher und technischer Code kann so unabhängig voneinander entwickelt und getestet werden.

Ausgehend von den Zielen einer Softwarearchitektur und einem kritischen Blick auf die Schichtenarchitektur, schauen wir uns die hexagonale Architektur im Detail an. Ihr erfahrt, wie die Dependency Rule sicherstellt, dass es keine Abhängigkeiten von fachlichem zu technischem Code gibt und wie der Anwendungskern trotzdem auf die Infrastruktur zugreifen kann. Erfüllt die hexagonale Architektur die Ziele einer Softwarearchitektur? Welche Herausforderungen bringt sie mit sich? Wie unterscheidet sie sich von Onion und Clean Architecture, und welche Synergien ergeben sich im Zusammenspiel mit Microservices und Domain-Driven Design?

Mit neuem Wissen gerüstet, könnt ihr die Qualität und Lebensdauer eurer Softwareprojekte steigern und in Zukunft schneller auf neue Anforderungen reagieren.

Avatar for Sven Woltmann

Sven Woltmann

April 07, 2024
Tweet

More Decks by Sven Woltmann

Other Decks in Programming

Transcript

  1. Copyright © 2025, HappyCoders.eu Was ist das Ziel von Softwarearchitektur?

    “The goal of a software architecture is to minimize the human resources required to build and maintain the required system.” “If that effort is low, and stays low throughout the lifetime of the system, the design is good.”
  2. Copyright © 2025, HappyCoders.eu „Das Ziel einer Software-Architektur ist es,

    den Personalaufwand für die Erstellung und Wartung des gewünschten Systems zu minimieren.” Was ist das Ziel von Softwarearchitektur?
  3. Copyright © 2025, HappyCoders.eu Eine gute Architektur erlaubt es, Software

    während ihrer Lebensdauer mit möglichst geringem, gleichbleibendem Aufwand zu ändern. “To keep software soft.” — Robert C. Martin Was ist das Ziel von Softwarearchitektur?
  4. Copyright © 2025, HappyCoders.eu Ziele 1. 2. 3. Isolierung von

    steuernder Infrastruktur Isolierung von gesteuerter Infrastruktur Modernisierung von Infrastruktur ohne Anpassung der Geschäftslogik Geschäfts- logik @
  5. Copyright © 2025, HappyCoders.eu Adapter Kern ? ? ? ?

    ? ? ? Modell Geschäftslogik Port Port Port Port
  6. Copyright © 2025, HappyCoders.eu Register Port Copyright © 2025, HappyCoders.eu

    name=Sven&email= [email protected] Absenden Web UI Adapter registerPort.registerUser( "Sven", "[email protected]"); { "name": "Sven", "email": "… " } REST API Adapter Ausfüllen
  7. Copyright © 2025, HappyCoders.eu Copyright © 2024, HappyCoders.eu Persistenz Port

    JPA Adapter INSERT INTO User (name, email, registrationDate) VALUES ('Sven', '[email protected]', now()); persistencePort .saveUser(user); Copyright © 2025, HappyCoders.eu
  8. Copyright © 2025, HappyCoders.eu Adapter Kern Modell Geschäftslogik Persistenz Port

    Versand Port Register Port Web UI REST API JPA SMTP Primary / Driving Secondary / Driven
  9. Copyright © 2025, HappyCoders.eu RegisterUserService +registerUser() UserRestController +registerUser() RESTEasy JpaAdapter

    +saveUser() Hibernate Copyright © 2025, HappyCoders.eu Modul “Application” Modul “Controllers” «interface» RegisterUserPort +registerUser() Aufrufrichtung
  10. Copyright © 2025, HappyCoders.eu Copyright © 2025, HappyCoders.eu «interface» RegisterUserPort

    +registerUser() UserRestController +registerUser() RESTEasy Hibernate RegisterUserService +registerUser() JpaAdapter +saveUser() «interface» PersistencePort +saveUser() Aufrufrichtung D ependency
  11. Copyright © 2025, HappyCoders.eu Copyright © 2025, HappyCoders.eu «interface» RegisterUserPort

    +registerUser() UserRestController +registerUser() RESTEasy Hibernate RegisterUserService +registerUser() JpaAdapter +saveUser() «interface» PersistencePort +saveUser() D ependency
  12. Copyright © 2025, HappyCoders.eu Copyright © 2025, HappyCoders.eu «interface» RegisterUserPort

    +registerUser() UserRestController +registerUser() RESTEasy Hibernate RegisterUserService +registerUser() JpaAdapter +saveUser() «interface» PersistencePort +saveUser() “Dependency” “Rule” Dependency D ependency
  13. Copyright © 2025, HappyCoders.eu Adapter Kern Port Port Port Web

    UI REST API JPA SMTP Dependency Dependency
  14. Copyright © 2025, HappyCoders.eu import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id;

    import java.time.LocalDateTime; @Entity public class User { @Id private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private String email; @Column(nullable = false) private Instant registeredAt; // ... }
  15. Copyright © 2025, HappyCoders.eu Copyright © 2025, HappyCoders.eu «interface» RegisterUserPort

    +registerUser() UserRestController +registerUser() RESTEasy Hibernate RegisterUserService +registerUser() JpaAdapter +saveUser() «interface» PersistencePort +saveUser()
  16. Copyright © 2025, HappyCoders.eu Hibernate RegisterUserService +registerUser() JpaAdapter + saveUser()

    «interface» PersistencePort +saveUser() Copyright © 2025, HappyCoders.eu JpaUser User
  17. Copyright © 2025, HappyCoders.eu import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id;

    import java.time.Instant; @Entity public class JpaUser { @Id private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private String email; @Column(nullable = false) private Instant registeredAt; // ... }
  18. Copyright © 2025, HappyCoders.eu import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id;

    import java.time.Instant; @Entity public class JpaUser { @Id private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private String email; @Column(nullable = false) private Instant registeredAt; // ... } import java.time.Instant; public class User { private Long id; private String name; private String email; private Instant registeredAt; public User(String name, String email) { verifyName(name); verifyEmail(email); this.name = name; this.email = email; this.registeredAt = Instant.now(); } // ... }
  19. Copyright © 2025, HappyCoders.eu Hibernate RegisterUserService +registerUser() JpaAdapter + saveUser()

    «interface» PersistencePort +saveUser() Copyright © 2025, HappyCoders.eu JpaUser User Mapping
  20. Copyright © 2025, HappyCoders.eu Hibernate RegisterUserService +registerUser() JpaAdapter + saveUser()

    «interface» PersistencePort +saveUser() Copyright © 2025, HappyCoders.eu JpaUser User Mapping + loadUser()
  21. Copyright © 2025, HappyCoders.eu public class JpaAdapter implements PersistencePort {

    @Override @Transactional public void saveUser(User user) { JpaUser jpaUser = mapper.toJpaUser(user); repository.save(jpaUser); } } @Override @Transactional public Optional<User> loadUser(long userId) { Optional<JpaUser> jpaUser = repository.findById(userId); return jpaUser.map(mapper::toUser); }
  22. Copyright © 2025, HappyCoders.eu public class JpaAdapter implements PersistencePort {

    @Override @Transactional public void saveUser(User user) { JpaUser jpaUser = mapper.toJpaUser(user); repository.save(jpaUser); } } @Override @Transactional public Optional<User> loadUser(long userId) { Optional<JpaUser> jpaUser = repository.findById(userId); return jpaUser.map(mapper::toUser); }
  23. Copyright © 2025, HappyCoders.eu Copyright © 2025, HappyCoders.eu «interface» RegisterUserPort

    +registerUser() UserRestController +registerUser() RESTEasy Hibernate RegisterUserService +registerUser() JpaAdapter +saveUser() «interface» PersistencePort +saveUser()
  24. Copyright © 2025, HappyCoders.eu import com.fasterxml.jackson.annotation.JsonFormat; import java.time.Instant; public class

    UserDto { private Long id; private String name; private String email; @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'") private Instant registeredAt; // ... }
  25. Copyright © 2025, HappyCoders.eu «interface» RegisterUserPort +registerUser() UserRestController + registerUser()

    RESTEasy RegisterUserService +registerUser() Copyright © 2025, HappyCoders.eu User UserDto Jackson Mapping
  26. Copyright © 2025, HappyCoders.eu «interface» RegisterUserPort +registerUser() UserRestController + registerUser()

    RESTEasy RegisterUserService +registerUser() Copyright © 2025, HappyCoders.eu User UserDto Jackson Mapping + getUser()
  27. Copyright © 2025, HappyCoders.eu Kern (subject under test) Port Port

    Port Port Adapter Test Double Test Method Calls ✓ ✓
  28. Copyright © 2025, HappyCoders.eu Test Method Calls REST-Adapter (subject under

    test) REST Assured HTTP Port Test Double Copyright © 2025, HappyCoders.eu ✓ ✓
  29. Copyright © 2025, HappyCoders.eu Adapter Web UI REST API JPA

    SMTP Kern Port Port Port Dependency Dependency
  30. Copyright © 2025, HappyCoders.eu Eine gute Architektur erlaubt es, Software

    während ihrer Lebensdauer mit möglichst geringem, gleichbleibendem Aufwand zu ändern. Was ist das Ziel von Softwarearchitektur?
  31. Copyright © 2025, HappyCoders.eu Adapter Web UI REST API JPA

    SMTP Kern Modell Geschäftslogik Port Port Port
  32. Copyright © 2025, HappyCoders.eu Adapter Web UI REST API JPA

    SMTP Kern Modell Geschäftslogik Port Port Port
  33. Copyright © 2025, HappyCoders.eu Adapter Web UI REST API JPA

    SMTP Kern Modell Geschäftslogik Port Port Port
  34. Copyright © 2025, HappyCoders.eu Adapter Modules Persistenz Port Web UI

    REST API JPA Modul “Application” Persistenz Port Register Port
  35. Copyright © 2025, HappyCoders.eu Kern Port Port Port Port Test

    Test Double Test REST-Adapter REST Assured Port Test Double Test Test- container Database JPA-Adapter
  36. Copyright © 2025, HappyCoders.eu Hexagonale Architektur ✔ Änderbarkeit ✔ Lose

    Kopplung ✔ Unabhängige Entwicklung ✔ Unabhängige Testbarkeit