On Hexagonal Architecture notes
Introduction
Hexagonal Architecture, also known as Ports and Adapters pattern, is a design pattern used in software application development. It aims to create loosely coupled application components that can be easily connected to their software environment by means of ports and adapters. This makes the system easy to maintain, adaptable for future changes and independent of any external agency.
In the example of a Java with Spring-based platform, here’s are some concepts to map to:
-
Domain Model: This is the core of your application, where the business logic resides. In a Java application, these would be your POJOs (Plain Old Java Objects) that define the entities and value objects.
-
Ports: These are interfaces that define the expected behavior of your application. In a Spring application, these could be annotated as
@Service
or@Component
. There are two types of ports:- Primary or Driving ports: These are service interfaces that expose the use cases of your application. They’re “driven” by the application user (human or system).
- Secondary or Driven ports: These are usually repository interfaces that the application drives to perform operations on external systems like databases.
-
Adapters: These are the implementations of your ports. They adapt the technology-specific code to your business use cases. In a Spring application, these could be your
@Controller
classes (for incoming requests) and@Repository
or@Service
classes (for outgoing requests). -
Services: In a microservices architecture, each service could be a hexagon (i.e., it has its own ports and adapters). They communicate with each other through APIs.
Here’s a simple example in Java:
// Primary Port
@Service
public interface OrderService {
void placeOrder(Order order);
}
// Secondary Port
@Repository
public interface OrderRepository {
void save(Order order);
}
// Primary Adapter
@Controller
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping("/orders")
public void placeOrder(@RequestBody Order order) {
orderService.placeOrder(order);
}
}
// Secondary Adapter
@Service
public class JpaOrderRepository implements OrderRepository {
// implementation details...
}
In this example, OrderService
is a primary port, OrderRepository
is a secondary port, OrderController
is a primary adapter, and JpaOrderRepository
is a secondary adapter. The OrderController
and JpaOrderRepository
adapt the incoming HTTP request and the outgoing JPA operations to the OrderService
use case, respectively.
The key idea behind Hexagonal Architecture is to isolate the core logic of your application from the outside world (like UI, database, etc.). This allows you to independently develop, test, and evolve the core logic without being affected by changes to external components. It also makes your application more flexible and adaptable to future changes. For example, you can easily swap out a MySQL database for a NoSQL database without changing the core business logic. You just need to write a new adapter.