Slide 1

Slide 1 text

Copyright © 2025, HappyCoders.eu Sven Woltmann Hexagonal Architecture: Robust Software With Interfaces Instead of Layers

Slide 2

Slide 2 text

Copyright © 2025, HappyCoders.eu What is Software Architecture?

Slide 3

Slide 3 text

Copyright © 2025, HappyCoders.eu “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.” What Is the Goal of Software Architecture?

Slide 4

Slide 4 text

Copyright © 2025, HappyCoders.eu A good architecture makes it possible to change software during its lifetime with as little effort as possible. “To keep software soft.” — Robert C. Martin What Is the Goal of Software Architecture?

Slide 5

Slide 5 text

Copyright © 2025, HappyCoders.eu Presentation Layer Business Layer Data Layer Client Hibernate REST API Layered Architecture

Slide 6

Slide 6 text

Copyright © 2025, HappyCoders.eu Time Effort

Slide 7

Slide 7 text

Copyright © 2025, HappyCoders.eu Hexagonal Architecture https://alistair.cockburn.us/hexagonal-architecture/

Slide 8

Slide 8 text

Copyright © 2025, HappyCoders.eu Goals 1. 2. 3. Isolation from controlling infrastructure Isolation from controlled infrastructure Modernization of infrastructure without adapting the business logic Business logic @

Slide 9

Slide 9 text

Copyright © 2025, HappyCoders.eu Adapters Core ? ? ? ? ? ? ? Model Business logic Port Port Port Port

Slide 10

Slide 10 text

Copyright © 2025, HappyCoders.eu Core Model Business logic Port Port Port Port

Slide 11

Slide 11 text

Copyright © 2025, HappyCoders.eu Core Model Business logic Port Port Port Port

Slide 12

Slide 12 text

Copyright © 2025, HappyCoders.eu Core Model Business logic Port Port Port Port

Slide 13

Slide 13 text

Copyright © 2025, HappyCoders.eu Core Model Business logic Port Port Ports Port Port

Slide 14

Slide 14 text

Copyright © 2025, HappyCoders.eu Adapters Core Model Business logic Persistence Port Sending Port Registration Port Web UI REST API JPA SMTP

Slide 15

Slide 15 text

Copyright © 2025, HappyCoders.eu Registration Port Copyright © 2025, HappyCoders.eu name=Sven&email= [email protected] Submit Web UI Adapter registerPort.registerUser( "Sven", "[email protected]"); { "name": "Sven", "email": "… " } REST API Adapter Fill out

Slide 16

Slide 16 text

Copyright © 2025, HappyCoders.eu Copyright © 2024, HappyCoders.eu Persistence Port JPA Adapter INSERT INTO User (name, email, registrationDate) VALUES ('Sven', '[email protected]', now()); persistencePort .saveUser(user); Copyright © 2025, HappyCoders.eu

Slide 17

Slide 17 text

Copyright © 2025, HappyCoders.eu Adapters Core Model Business logic Persistence Port Sending Port Registration Port Web UI REST API JPA SMTP Primary / Driving Secondary / Driven

Slide 18

Slide 18 text

Copyright © 2025, HappyCoders.eu RegisterUserService +registerUser() UserRestController +registerUser() RESTEasy JpaAdapter +saveUser() Hibernate Copyright © 2025, HappyCoders.eu Module “Application” Module “Controllers” «interface» RegisterUserPort +registerUser() Direction of call

Slide 19

Slide 19 text

Copyright © 2025, HappyCoders.eu Dependency Inversion Principle SOLID

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

Copyright © 2025, HappyCoders.eu Adapters Core Port Port Port Web UI REST API JPA SMTP Dependency Dependency

Slide 24

Slide 24 text

Copyright © 2025, HappyCoders.eu Mapping

Slide 25

Slide 25 text

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; // ... }

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Copyright © 2025, HappyCoders.eu Two-Way Mapping

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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; // ... }

Slide 32

Slide 32 text

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(); } // ... }

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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 loadUser(long userId) { Optional jpaUser = repository.findById(userId); return jpaUser.map(mapper::toUser); }

Slide 36

Slide 36 text

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 loadUser(long userId) { Optional jpaUser = repository.findById(userId); return jpaUser.map(mapper::toUser); }

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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; // ... }

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

Copyright © 2025, HappyCoders.eu Testability

Slide 43

Slide 43 text

Copyright © 2025, HappyCoders.eu Core (subject under test) Port Port Port Port Adapter test double Test Method calls ✓ ✓

Slide 44

Slide 44 text

Copyright © 2025, HappyCoders.eu Test Method calls REST Adapter (subject under test) REST Assured HTTP Port test double Copyright © 2025, HappyCoders.eu ✓ ✓

Slide 45

Slide 45 text

Copyright © 2025, HappyCoders.eu JPA Adapter (subject under test) Test Testcontainer Database SQL ✓ ✓

Slide 46

Slide 46 text

Copyright © 2025, HappyCoders.eu Adapters Core Web UI REST API JPA SMTP Port Port Port

Slide 47

Slide 47 text

Copyright © 2025, HappyCoders.eu Hexagonale Architektur vs. „Ports & Adapters“

Slide 48

Slide 48 text

Copyright © 2025, HappyCoders.eu Hexagonale Architektur = „Ports & Adapters“

Slide 49

Slide 49 text

Copyright © 2025, HappyCoders.eu Adapters Web UI REST API JPA SMTP Core Port Port Port

Slide 50

Slide 50 text

Copyright © 2025, HappyCoders.eu Adapters Web UI REST API JPA SMTP Core Port Port Port

Slide 51

Slide 51 text

Copyright © 2025, HappyCoders.eu Adapters Web UI REST API JPA SMTP Core Port Port Port

Slide 52

Slide 52 text

Copyright © 2025, HappyCoders.eu Adapters Web UI REST API JPA SMTP Core Port Port Port

Slide 53

Slide 53 text

Copyright © 2025, HappyCoders.eu Adapters Web UI REST API JPA SMTP Core Port Port Port Dependency Dependency

Slide 54

Slide 54 text

Copyright © 2025, HappyCoders.eu A good architecture makes it possible to change software during its lifetime with as little effort as possible. What Is the Goal of Software Architecture?

Slide 55

Slide 55 text

Copyright © 2025, HappyCoders.eu Goal #1: Changeability

Slide 56

Slide 56 text

Copyright © 2025, HappyCoders.eu Adapters Web UI REST API JPA SMTP Core Model Business logic Port Port Port

Slide 57

Slide 57 text

Copyright © 2025, HappyCoders.eu Adapters Web UI REST API JPA SMTP Core Model Business logic Port Port Port

Slide 58

Slide 58 text

Copyright © 2025, HappyCoders.eu Adapters Web UI REST API JPA SMTP Core Model Business logic Port Port Port

Slide 59

Slide 59 text

Copyright © 2025, HappyCoders.eu Persistence Port JPA JPA Adapter Hibernate Copyright © 2025, HappyCoders.eu

Slide 60

Slide 60 text

Copyright © 2025, HappyCoders.eu Core Model Business logic Port Port Port

Slide 61

Slide 61 text

Copyright © 2025, HappyCoders.eu Goal #2: Loose Coupling

Slide 62

Slide 62 text

Copyright © 2025, HappyCoders.eu Adapter Modules Persistenz Port Module “Application” Registration Port Web UI REST API Persistence Port JPA

Slide 63

Slide 63 text

Copyright © 2025, HappyCoders.eu Adapter Modules Persistenz Port Module “Application” Web UI REST API Persistence Port JPA Registration Port

Slide 64

Slide 64 text

Copyright © 2025, HappyCoders.eu Adapter Modules Persistenz Port Web UI REST API JPA Module “Application” Persistence Port Registration Port

Slide 65

Slide 65 text

Copyright © 2025, HappyCoders.eu Adapter Modules Persistenz Port Module “Application” Web UI REST API Persistence Port JPA Registration Port

Slide 66

Slide 66 text

Copyright © 2025, HappyCoders.eu Adapter Modules Persistenz Port Modul “Application” Web UI REST API Persistenz Port JPA Register Port

Slide 67

Slide 67 text

Copyright © 2025, HappyCoders.eu

Slide 68

Slide 68 text

Copyright © 2025, HappyCoders.eu Goal #3: Independent Development

Slide 69

Slide 69 text

Copyright © 2025, HappyCoders.eu Adapters Persistenz Port Port Port Core REST API Web UI JPA

Slide 70

Slide 70 text

Copyright © 2025, HappyCoders.eu Goal #4: Independent Testability

Slide 71

Slide 71 text

Copyright © 2025, HappyCoders.eu Core Port Port Port Port Test Test double Test REST Adapter REST Assured Port test double Test Test- containers database JPA Adapter

Slide 72

Slide 72 text

Copyright © 2025, HappyCoders.eu Hexagonal Architecture ✔ Changeability ✔ Loose Coupling ✔ Independent Development ✔ Independent Testability

Slide 73

Slide 73 text

Copyright © 2025, HappyCoders.eu

Slide 74

Slide 74 text

Copyright © 2025, HappyCoders.eu End

Slide 75

Slide 75 text

Copyright © 2025, HappyCoders.eu Links https://youtube.com/c/happycoders https://x.com/svenwoltmann https://www.happycoders.eu/ https://linkedin.com/in/sven-woltmann/ [email protected] https://bsky.app/profile/sven.woltmann