Hexagonal Architecture, also known as Ports and Adapters, was introduced by Alistair Cockburn in 2005. Cockburn developed this concept to solve the problem of tight coupling between application logic and external dependencies (like databases, UI frameworks, and APIs). His main goal was to make systems more maintainable, testable, and adaptable by clearly separating core business logic from infrastructure concerns.
Hexagonal Architecture shares similarities with other architectural patterns designed to promote separation of concerns and modularity.
1️⃣ Layered Architecture (N-Tier Architecture)
2️⃣ Clean Architecture (by Robert C. Martin - Uncle Bob)
3️⃣ Onion Architecture (by Jeffrey Palermo)
Why is it Called Hexagonal Architecture?
The term Hexagonal Architecture comes from the hexagon shape used to visually represent the core system and its interactions with the external world.
🔷 Why a Hexagon?
The hexagon shape is a metaphor to visually represent the system’s core and its interactions.
Unlike a rectangle or circle, a hexagon does not imply a hierarchical structure (like traditional N-tier architecture).
It has multiple connection points (ports) where you can easily plug in different adapters, like a UI, database, or external APIs.
The number six isn't important, it simply provides enough sides for a clean and organized representation.
🔌 Ports: The Entry Points to Your Business Logic
In Hexagonal Architecture, ports represent interfaces that define the use cases or functionalities of the system. They specify what the application can do (e.g., add a product to the cart, remove a product, calculate the total), but not how it's done. Ports are the entry points to your core business logic.
public interface CartService {
void addProduct(Product product);
void removeProduct(String productId);
double calculateTotal();
Cart getCart();
}
In this example, CartService
is a primary port that defines the use cases for managing a shopping cart.
🔄 Adapters: Bridging Your Core Logic and the Outside World
Adapters are the implementations that interact with external systems and convert data between the outside world and the core business logic. There are two types of adapters in Hexagonal Architecture:
Primary Adapters: These handle input from external sources, such as user requests, UI, or API calls. They interact with the primary ports (use cases) of the system. For example, a REST controller that receives HTTP requests and delegates the actions to a service (like CartServiceImpl
).
Example of a primary adapter (controller)
@RestController
@RequestMapping("/cart")
public class CartController {
private final CartService cartService;
@Autowired
public CartController(CartService cartService) {
this.cartService = cartService;
}
@PostMapping("/add")
public void addProduct(@RequestBody Product product) {
cartService.addProduct(product);
}
}
CartController
acts as a primary adapter because it handles HTTP requests (external input) and delegates them to the CartService (the primary port).
Secondary Adapters: These handle output to external systems, such as databases, message queues, or APIs. They implement the secondary ports, which are interfaces for data persistence or external integrations.
Example of a secondary adapter (repository)
public class InMemoryCartRepository implements CartRepository {
private Cart cart = new Cart();
@Override
public void save(Cart cart) {
this.cart = cart;
}
@Override
public Cart get() {
return cart;
}
}
Primary Adapters ➡ Think of them as input handlers (Controllers, CLI, API Gateways) that take external requests and pass them into the system.
Secondary Adapters ➡ Think of them as output handlers (Repositories, API clients, message brokers) that take results from the system and pass them to the outside world.
An Example Package Structure in Java
com.company.cart
│── domain
│ ├── model
│ │ ├── Product.java
│ │ ├── Cart.java
│ ├── repository
│ │ ├── CartRepository.java
│── application
│ ├── service
│ │ ├── CartService.java
│── infrastructure
│ ├── persistence
│ │ ├── InMemoryCartRepository.java
│ ├── controller
│ │ ├── CartController.java
🏗️ How Do These Layers Interact?
When we need to interact with an infrastructure service from an application service, we follow the Dependency Inversion Principle. This principle suggests that rather than directly depending on concrete implementations, we inject the necessary dependencies through the constructor of the class. This approach promotes loose coupling and makes the system more flexible and easier to test.
⚖️ Ports vs. Adapters: Understanding the Difference
Ports are interfaces that define what the system should do. They represent the use cases of the application (e.g., CartService
).
Adapters are the implementations of those ports, responsible for managing the interaction with the outside world (like HTTP requests in the case of primary adapters, or database interactions in the case of secondary adapters).
Does the Implementation of a Primary Port Need to Be a Primary Adapter?
No. The implementation of a primary port (such as CartServiceImpl
) does not have to be a primary adapter. While primary ports define the use cases, their implementation is simply the business logic that satisfies those use cases. The primary adapter (like a controller) is the one that handles the external interaction (e.g., receiving requests, calling the service methods).
CartService
is a primary port (interface).
CartServiceImpl
is the implementation of the primary port, but it is not an adapter.
CartController
is a primary adapter, as it handles HTTP requests and delegates to the CartService (the primary port).
Conclusion
In Hexagonal Architecture, ports define what the system does (use cases), while adapters define how the system interacts with the outside world. The implementation of a port does not have to be an adapter itself; rather, it's the business logic that fulfills the requirements set by the port. Adapters, on the other hand, are responsible for connecting the external world to the core logic via the ports.
This separation makes the system easier to maintain, test, and adapt to different external technologies.
What are your thoughts on Hexagonal Architecture? Have you used it in your projects? Let’s discuss in the comments! 👇💬
Top comments (0)