Hexagonal Architecture: Ports and Adapters Pattern

Milad Fahmy
6 min readOct 13, 2024

--

Generated By AI

In software architecture, Hexagonal Architecture, also known as the Ports and Adapters pattern, has gained attention for promoting clean and maintainable systems. This architectural style was introduced by Alistair Cockburn in the early 2000s and is designed to make applications more flexible and adaptable to change. The key idea behind Hexagonal Architecture is to separate business logic from external systems (such as databases, user interfaces, and external APIs) to improve maintainability, testability, and scalability.

In this article, we’ll explore the concepts of Hexagonal Architecture in detail, including its structure, benefits, implementation, and how it compares to other architectural styles.

What is Hexagonal Architecture?

Hexagonal Architecture aims to isolate the core business logic of an application from its external dependencies. It visualizes the application as a hexagon, with the core business logic at the center. External systems (e.g., databases, web services, and user interfaces) interact with the business logic through “ports” and “adapters,” which act as mediators between the core logic and external systems.

The Core Concept:

  • Domain Logic (Core): At the heart of the hexagon is the domain logic, representing the pure business rules of the application.
  • Ports: These are abstractions or interfaces that define how the external systems should communicate with the core logic.
  • Adapters: Adapters are implementations of ports. They handle the actual communication between the external systems (e.g., databases, web APIs) and the business logic.

This architecture decouples the core domain from any particular technology, allowing for flexibility when switching or upgrading external components. The business logic remains untouched, regardless of changes in external systems.

Structure of Hexagonal Architecture:

  1. Core (Domain): The core contains entities, domain services, and business rules. It needs to learn about how the application is presented or stored.
  2. Ports: Ports define the interactions between the core and the outside world. They can be:
  • Inbound Ports (for incoming requests like HTTP requests or user inputs)
  • Outbound Ports (for outgoing actions like saving data to a database or calling external services)

3. Adapters: Adapters translate the data and requests from the external systems into something the core logic can understand and vice versa. Adapters can be:

  • Inbound Adapters (like controllers, which receive user input and convert it into a format the core can process)
  • Outbound Adapters (like repositories, which handle data storage and retrieval from databases)

Key Principles of Hexagonal Architecture

1. Independence from External Systems

Hexagonal Architecture promotes the separation of concerns by isolating the core business logic from external systems such as databases, APIs, and user interfaces. This way, you can swap or upgrade these external systems without affecting the core functionality.

2. Focus on Business Logic

By placing the domain at the core of the architecture, Hexagonal Architecture ensures that the primary focus is always on business rules rather than on infrastructure or technical concerns.

3. Testability

With external systems decoupled from the business logic, testing becomes significantly easier. The core can be tested in isolation using mocks for external services, ensuring that your tests are focused on business rules and logic.

4. Flexibility

Since the core logic only depends on ports (interfaces), the adapters can change or evolve without affecting the core. This flexibility allows for easier integration with new technologies or platforms over time.

Benefits of Hexagonal Architecture

  1. Modularity and Maintainability: By isolating business logic and decoupling it from external systems, Hexagonal Architecture promotes modularity. Each component can be developed and maintained independently, reducing the risk of introducing bugs when making changes.
  2. Simpler Testing: Hexagonal Architecture makes it easier to write unit tests for the core business logic since it eliminates the need for external dependencies like databases or web servers during testing. Instead, you can use mock objects or test doubles.
  3. Adaptability to Change: With the flexibility provided by ports and adapters, you can easily swap out or replace external systems (e.g., switching from one database to another) without affecting the core logic.
  4. Clear Separation of Concerns: By isolating the core business logic from the infrastructure layer, developers can focus on solving business problems instead of worrying about technical concerns like database schemas or third-party integrations.

Implementing Hexagonal Architecture

Let’s break down the process of implementing Hexagonal Architecture into three layers: Core (Domain), Ports, and Adapters.

1. Domain Layer (Core)

The domain layer contains the business logic and is the heart of the system. It consists of:

  • Entities: Objects that represent concepts in the business domain (e.g., Customer, Order).
  • Value Objects: Immutable objects that describe aspects of entities (e.g., Address, Money).
  • Domain Services: Logic that doesn’t naturally fit inside an entity or value object.
public class Order {
private final OrderId id;
private final List<Item> items;

public Order(OrderId id, List<Item> items) {
this.id = id;
this.items = items;
}

public void addItem(Item item) {
items.add(item);
}
}

2. Ports (Interfaces)

Ports are interfaces that define how the core communicates with the outside world. These can be inbound (for incoming requests) or outbound (for outgoing actions).

Example of an Inbound Port:

public interface OrderService {
void placeOrder(OrderDto orderDto);
}

Example of an Outbound Port:

public interface OrderRepository {
void save(Order order);
}

3. Adapters (Implementations)

Adapters implement the ports and manage communication with external systems. They can be HTTP controllers (for receiving requests), database repositories (for storing data), or third-party API clients (for external integrations).

Inbound Adapter (HTTP Controller):

@RestController
public class OrderController {
private final OrderService orderService;

public OrderController(OrderService orderService) {
this.orderService = orderService;
}

@PostMapping("/orders")
public void placeOrder(@RequestBody OrderDto orderDto) {
orderService.placeOrder(orderDto);
}
}

Outbound Adapter (Repository Implementation):

@Repository
public class JpaOrderRepository implements OrderRepository {
private final OrderJpaRepository jpaRepository;

public JpaOrderRepository(OrderJpaRepository jpaRepository) {
this.jpaRepository = jpaRepository;
}

@Override
public void save(Order order) {
jpaRepository.save(order);
}
}

Comparison with Other Architectural Styles

1. Layered Architecture

Layered architecture (also known as N-Tier architecture) organizes code into horizontal layers such as presentation, business, and data access layers. However, the dependencies between these layers are usually tightly coupled. Hexagonal Architecture offers greater flexibility because it allows external components to be easily replaced or modified without impacting the core domain logic.

2. Microservices Architecture

Hexagonal Architecture is particularly useful in microservices environments. Since each microservice can be designed with its

hexagonal structure, it promotes loose coupling between services and ensures that each microservice focuses on its business logic while keeping external dependencies manageable.

Real-World Use Cases

1. E-Commerce Platforms

An e-commerce platform, for example, can use Hexagonal Architecture to separate its core order-processing logic from external systems like payment gateways and shipping services. The core remains intact, even if the platform decides to switch payment providers or change the way orders are stored.

2. Financial Systems

In a banking system, Hexagonal Architecture allows the core business logic (e.g., processing transactions) to be isolated from external services like databases, authentication systems, or third-party credit-scoring services. This decoupling improves system stability and flexibility in response to changes in regulatory or financial practices.

Conclusion

Hexagonal Architecture (Ports and Adapters pattern) offers a powerful way to build flexible, maintainable, and testable software systems. By decoupling the business logic from external systems, it ensures that core domain logic remains the focal point of the application, while external components can be swapped, replaced, or updated with minimal impact.

This architecture not only enhances modularity but also makes applications more resilient to change and easier to test in isolation. For any developer or architect working in complex, evolving domains, Hexagonal Architecture provides an excellent blueprint for clean and adaptable system design.

References

  1. Cockburn, A. (2005). Hexagonal Architecture. alistairecockburn.com. A foundational introduction to Hexagonal Architecture by its creator, outlining the core principles and motivations behind the pattern.
  2. Evans, E. (2003). Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley. While not specific to Hexagonal Architecture, this book provides critical insights into separating domain logic from external concerns, a key principle in Hexagonal Architecture.
  3. Fowler, M. (2010). Patterns of Enterprise Application Architecture. Addison-Wesley. This book discusses architectural patterns, including Ports and Adapters, in enterprise software applications.
  4. Richards, M. (2015). Microservices vs. the Monolith. O’Reilly Media. A comparison of architectural styles with a discussion on Hexagonal Architecture as a way to structure microservices.
  5. Richardson, C. (2017). Microservices Patterns: With Examples in Java. Manning Publications. This book covers the use of Ports and Adapters in the context of microservices and decoupling services from external systems.
  6. Vernon, V. (2016). Implementing Domain-Driven Design. Addison-Wesley. A practical guide to applying Domain-Driven Design, which overlaps with Hexagonal Architecture in promoting clean separation of business logic and infrastructure.
  7. Hohpe, G., & Woolf, B. (2003). Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions. Addison-Wesley. This book provides insight into the use of ports and adapters in messaging and integration patterns, relevant for understanding Hexagonal Architecture.
  8. Khononov, V. (2021). Learning Domain-Driven Design. O’Reilly Media. A modern guide to implementing clean architectures in complex software domains, touching on how Ports and adapter patterns enhance system flexibility.

--

--

Milad Fahmy
Milad Fahmy

Written by Milad Fahmy

I’m a JS Champion, I wrote about software engineering. I’m currently developing various open-source projects (like: https://encrypt-rsa.js.org)

No responses yet