If you are familiar with the layers architectural pattern, it is only a small step to the even nicer hexagonal pattern. Here is an example of how you can do it.
This document will show that a hexagonal architecture can be viewed as an extension to the layered architecture pattern. It adds a neater separation of your own business logic and interfaces (aka. ports) to the outside world. Since it is an extension to the layers pattern it is only a small step to the hexagonal pattern for those already familiar with the layers pattern.
It is recommended to be familiar with both patterns before reading on (see References below for more on that).
In the layered pattern the service layer module is kind of a bucket for all we cannot put in either the presentation or the access layer. The service layer usually also depends on the access layer compile time, making it harder to replace it with another access layer implementation runtime. Now this can be avoided still using the layers pattern, using the hexagonal pattern this comes more natural.
The example below illustrates that the Ports module defines all inbound and outbound ports. All business logic is encapsulated in the Core module. Ports + Core do not depend on any other module, not even the DrivenAdapters module. Instead, the DrivenPorts in it defines the outbound interfaces it requires, implemented by the DrivenAdapters module, which can be runtime injected. The separation of concerns is neatly reflected in the module structure.
Consider the following system:
The hexagonal architecture now prescribes you should use the following components:
Mapping to Layers
To illustrate the link with the layers pattern we can now use the diagram above to map the hexagonal packages onto layers:
DrivingAdapters → Presentation layer
Ports + Core → Service layer
DrivenAdapters → Access layer
To enforce dependency directions use a separate Maven/Gradle module for each package. That works because Maven/Gradle do not allow circular dependencies. Alternatively you could also enforce these rules with tools like ArchUnit or Spring Modulith.
Modules and Code Packages
Now the following Maven/Gradle module and code packages could be used.
org.myorg.mysystem.adapters.driving.api1 org.myorg.mysystem.adapters.driving.api2 org.myorg.mysystem.adapters.driving.api5 org.myorg.mysystem.adapters.driving.api1.model org.myorg.mysystem.adapters.driving.api2.model org.myorg.mysystem.adapters.driving.api5.model
org.myorg.mysystem.ports org.myorg.mysystem.ports.api3 org.myorg.mysystem.ports.api4 org.myorg.mysystem.ports.api6 org.myorg.mysystem.ports.service org.myorg.mysystem.ports.api3.model org.myorg.mysystem.ports.api4.model org.myorg.mysystem.ports.api6.model org.myorg.mysystem.ports.service.model
org.myorg.mysystem.adapters.driven.api3 org.myorg.mysystem.adapters.driven.api4 org.myorg.mysystem.adapters.driven.api6 org.myorg.mysystem.adapters.driven.api3.model org.myorg.mysystem.adapters.driven.api4.model org.myorg.mysystem.adapters.driven.api6.model