Hexagon Architecture
Published:
This article briefly explains the Hexagon Architecture (also known as Ports and Adapters Architecture), its components.
I. Ports and adapters architecture
Evolving from layered architecture

Layered architecture:
- Presentation layer: UI/Views
- Business layer: business logic
- Data access layer: database
- What is matter is the
Business Logiclayer -> is what makes theApplication - The top and bottom layers are simply entry/exit points to/from the
Application

Port
- Port: an
interfaceof an entry point and/or exit point with no knowledge of concreate implementation behind it,Applicationuses it
Adapter
- Adapter: A class that transforms (adapts) an interface into another.
- Example:
public interface A {
void doSomething();
}
public interface B {
void performAction();
}
public class BImpl implements B {
@Override
public void performAction() {
System.out.println("Action performed");
}
}
public class Adapter implements A {
private B b;
public Adapter(B b) { this.b = b; }
@Override
public void doSomething() {
// Transform the request if necessary
// Proxy the request to the inner object
b.performAction();
}
}
// Use cases
B bObject = new BImpl();
A adapter = new Adapter(bObject);
adapter.doSomething(); // This will call bObject.performAction()
Two types of adapters

Primary/Driving adapters:
- Role: Start actions within the
application. - Location: left side
- Function: Represent the User Interface (UI) or other entry points (like APIs).
- Dependency: These adapters depend on a port (an interface) and get injected with a concrete implementation of this port.
- Role: Start actions within the
Secondary/Driven adapters:
- Role: React to actions initiated by
primary adapters. - Location: right side
- Function: Represent connections to backend tools, databases, or external services.
- Dependency: These adapters are the concrete implementation of a port and get injected into the business logic, although the business logic only interacts with the interface.
- Role: React to actions initiated by
Port and adapter usage:

- On the Left Side (Primary Adapters):
- Port: An interface that defines a use case or business logic.
- Adapter: Depends on this port and gets injected with a concrete implementation of the port.
- Concrete Implementation: The actual use case logic that implements the port.
- Belonging: Both the port and its concrete implementation belong inside the application.
// PORT
public interface UseCase {
void execute();
}
// Concrete Implementation (Use Case):
public class SomeUseCase implements UseCase {
@Override
public void execute() {
// Business logic here
}
}
// Primary adapter - UI
public class UIAdapter {
private UseCase useCase;
public UIAdapter(UseCase useCase) {
this.useCase = useCase;
}
public void onUserAction() {
useCase.execute();
}
}
- On the Right Side (Secondary Adapters):
- Port: An interface that represents a dependency (e.g., a repository, a service).
- Adapter: The concrete implementation of this port.
- Concrete Implementation: An external tool or service wrapped to conform to the port interface.
- Belonging: The port belongs inside the application, but its concrete implementation is external.
// PORT (interface)
public interface Repository {
void save(Data data);
}
// Concrete Implementation (External Adapter):
public class ExternalRepository implements Repository {
@Override
public void save(Data data) {
// Interact with external database or service
}
}
// Usage in application
public class BusinessLogic {
private Repository repository;
public BusinessLogic(Repository repository) {
this.repository = repository;
}
public void performSave(Data data) {
repository.save(data);
}
}
II. Hexagonal Architecture integration
Fundamental blocks of the system

Application core= business logic, what the application does- It could use
user interface(web app, mobile, …), but shouldn’t depend on what UI triggers it
- It could use
- The flow:
1. User interface->2. Application core->3. Infrastructure–>2. Application core–>1. User interface
Tools

- Tools used by the application example:
- Tell application to do something: Web server or CLI console (delivery mechanisms)
- Is told by application to do something: database engine, search engine
Connecting to Application
Adapters= code units that connect the tools to theapplication core- Implementation that will allow the business logic to communicate with a specific tool and vice-versa.
- Primary adapter = adapters tell application to do something
- Secondary adapter = adapters are told by application to do something
Port
Adaptersare created to fit a specific entry point to theApplication core~ a Port.Port= an interface defines how the tool can (use/be used by) theapplication corePorts(Interfaces) belong inside the business logic and fit what application needs, whileAdaptersbelong outside.
Primary/Driving Adapters

- Wrap around a
Port, use port to tellApplication corewhat to do. - Or in other words, it transform a delivery mechanism into a method call in the Application core.
- Example:
- Controllers or Console Commands (UI)
Implementation of Port is injected into UI constructors
- A port can be a Service interface / Repository interface that UI requires.
- A port can also be a Command/Query Bus interface.
The concreate impl of Port is then injected and used in UI
Secondary/Driven Adapters

- Unlike the
Driver Adapters, who wrap around a port, theDriven Adaptersimplement a Port, an interface, and are then injected into theApplication Core, wherever the port is required - Example:
- Port = persistence interface that meets its needs. i.e:
interface dbAdapter -> save() - 2 adapters
MySQLAdapter implements dbAdapterandMongoDBAdapter implements dbAdapter
- Port = persistence interface that meets its needs. i.e:
// PORT
public interface PersistenceInterface {
void saveData(List<Data> data);
}
// Adapters
public class MySQLAdapter implements PersistenceInterface {
private MySQLDatabase mySQLDatabase;
public MySQLAdapter(MySQLDatabase mySQLDatabase) {
this.mySQLDatabase = mySQLDatabase;
}
@Override
public void saveData(List<Data> data) {
// Implementation to save data in MySQL
mySQLDatabase.save(data);
}
}
// Application Core
public class DataService {
private PersistenceInterface persistenceInterface;
public DataService(PersistenceInterface persistenceInterface) {
this.persistenceInterface = persistenceInterface;
}
public void processData(List<Data> data) {
// Some processing logic
persistenceInterface.saveData(data);
}
}
// switch vendors
public class AppConfig {
public PersistenceInterface persistenceInterface() {
// return new MySQLAdapter(new MySQLDatabase());
// return new PostgreSQLAdapter(new PostgreSQLDatabase());
return new MongoDBAdapter(new MongoDBDatabase());
}
public DataService dataService() {
return new DataService(persistenceInterface());
}
}
Inversion of Control
- Note:
- The adapters depend on a specific tool and a specific port (by implementing an interface).
- But business logic only depends on the port (interface), which is designed to fit the business logic needs, so it doesn’t depend on a specific adapter or tool.
Application Core organisation
Application layer

- The use cases are defined in Application core, and can be triggered in our Application Core by one or several UI

Leave a Comment