Hexagonal Architecture, also known as "Ports and Adapters Architecture", is a model for creating decoupled and easy-to-maintain systems, based on separating the responsibilities of the business core from technical details (technical details are considered everything external to the business... such as the database, user interface, web services).
It was proposed by Alistair Cockburn in 2005 as a set of ideas, patterns, a software design philosophy, and gradually gained popularity (today it is a widely used architecture in microservices).
# Why Hexagonal?
The term "hexagonal" has to do with the idea that the business logic is at the center of the application and that each side represents an input/output port of the application, and a polygonal shape expresses this principle better than a circle.
These ports are the entry or exit points for external details, mechanisms that interact with our system; they are the communication abstractions (interfaces).
Each of these ports is assigned one or more adapters, the concrete implementations, e.g., queries to insert into a MySQL database. This is more flexible than a traditional layered model, where interaction is usually linear and one-way.
# Motivation
One of the major problems of software systems is the inclusion of business logic in the source code of the user interface, which results in:
-
The system cannot be tested with automated test suites because part of the logic depends on visual details.
-
It becomes impossible to switch from human usage to automated execution.
-
When changing technologies (UI or DB), a large part of the system has to be recoded.
Hexagonal architecture proposes focusing on these issues, facilitating development, maintenance, and testing. It should be independent of devices and databases, allowing for the adaptation of new external details without recoding use cases.
# The 3 Key Concepts
Domain
The heart of the application. Contains pure business logic, independent of any external technology.
Ports
Abstractions (interfaces) that define how the outside world interacts with the domain (Primary) and vice-versa (Secondary).
Adapters
Components that implement the ports, translating between the domain and external technologies (API, DB, etc.).
# Graphically
We see an application with two active ports and several adapters. The application can be driven in the same way by automated tests, a human being, or a remote API. On the data side, it can be configured to use real DBs or mock replacements without changing the core.
# Implementation
When implementing it, the structure is logically organized to separate contracts from implementations:
-
domain/: System entities (Order, Item).
-
application/: Application logic and orchestration (OrderService).
-
port/: Communication interfaces (OrderRepository).
-
adapters/: Concrete implementations (MemoryOrderRepository).
# Java Code
Domain: Order.java
package restaurant.domain;
public class Order {
private Item item;
private int quantity;
public Order(Item item, int quantity) {
this.item = item;
this.quantity = quantity;
}
}
Port: OrderRepository.java
package restaurant.port;
import restaurant.domain.Order;
public interface OrderRepository {
void saveOrder(Order order);
}
Adapter: MemoryOrderRepository.java
package restaurant.adapters;
import restaurant.domain.Order;
import restaurant.port.OrderRepository;
public class MemoryOrderRepository implements OrderRepository {
@Override
public void saveOrder(Order order) {
// Implementation for saving in memory
}
}
# Considerations
-
warning
Additional Complexity
Adds more classes and interfaces compared to simple models.
-
warning
Learning Curve
Requires a good understanding of the separation between ports and adapters.
# Real Benefits
-
verified
Adaptability
Easy replacement of adapters (UI, DB) without touching the business core.
-
verified
Testability
Allows for testing business logic in an isolated and pure way.
# Amazon's Vision
Amazon proposes a clear structure for scalable systems; you can check their full guide here: Amazon Hexagonal Architecture.
# In Summary
Hexagonal architecture maintains a clear focus on separating business logic from implementation details, leading to cleaner, more maintainable, and evolutionary systems.