hexagonal-example
Implementation of a hexagonal architecture in Spring Boot.
Most of the information on how to design in this way are from the following books:
Get your hands dirty on clean architecture | Tom Hombergs
Clean Architecture: A Craftsman's Guide to Software Structure and Design | Robert C. Martin
Implementing Domain-Driven Design | Vernon Vaughn
How to run
To run this application you need to first run a
mvn clean
in the root directory of this project. This will download all required dependecies and bundle your project properly. It will also auto generate some mapping classes with the mapstruct plugin.
The database for this application is a mongo db. You either need to have one running on your system, or you can alternatively start the MongoDB in docker with the included docker-compose file.
docker-compose -f mongodb-docker-compose up
Docker / docker-compose need to be installed for this.
The application can then be started by running the main function in:
hexagonal-example\config\src\main\java\de\strasser\peter\hexagonal\HexagonalApplication.java
What does this application do
This app can register customers, add addresses to these customers and retrieve a list of all customers.
The supported usecases in the business layer can be inspected in the applicationmodule. Under application/src/main/java/de/strasser/peter/hexagonal/application/customer/port all the supported operations are clearly visible, which is a major selling point to structure your application in this way.
Application architecture
This application tries to follow the design princples as described in Clean Architecture. To achieve key characteristics of a good architecture (Single Responsibility, Flexibility, Testability, ... ), one very defining lession of Robert C. Martins book is that the business logik should be at the core of the system.
This diagram shows where dependencies in a system should point to achieve this. How to implement this however, feels very abstract.
Alistair Cockburn took this concept and definied hexagonal architecture. Alternatively this style is also known as the ports and adapters architecture. Perhaps more fitting, but certainly not as exciting sounding as a hexagon.
In the middle lives the Domain. This is where all the business logik is contained. Ideally this code is free of any framework specific annotations. This is especially great for unit testing your logik. No spring context, that has to boot, or any services that need to be mocked. Just plain normal Java, which is easy to understand and fast to execute.
Ecapsulating these Domain models are the Use Cases. These represent the features that our application provides. They receive commands and query / write the data to the adapters.
Between the Use Cases and the Adapters are the Ports. Especially the output ports are important to control the direction of dependencies. In Java these represent interfaces. The output adapters implement the output ports and therefore have to follow the contract, that the core of the application defines for them. The input adapters only interact with the input ports and never with the implementing serivces directly.
This clear separation of concerns greatly increases flexibiliy. If you wanted to switch from an SQL to NoSQL DB, you'd just have to rewrite your Persistence Adapter, but the rest of the application should not be affected by your change.
Advantages of separated models on each layer in this example
-
The customer response can easily exclude the (hashed) password without much effort. This seperates the concern in what way to display the data to the client.
-
The AddressType properties can be annotated with web specific annotiations to control serialization, without cluttering the domain.
-
The customer can be persisted different from the domain models structure. This way the concern on how to handle data persistence is independent from the business layer and can be handled by the persistence module.



