In the context of Hexagonal Architecture (also known as Ports and Adapters Architecture), Ports are abstract interfaces that define the contract for communication between the application's core business logic (the "hexagon") and the external world. They act as the well-defined boundaries or "entry and exit points" through which the application interacts with various external actors and technologies.
The primary purpose of Ports is to:
- Decouple the Core: Ensure that the application's core business logic remains completely independent of external technologies, frameworks, or infrastructure details.
- Define Contracts: Clearly specify what the application can do (driving ports) and what external capabilities it needs (driven ports), without dictating how these operations are performed.
- Enable Testability: Allow the core business logic to be tested in isolation by providing mock or stub implementations of the ports, eliminating the need for real external systems during testing.
- Promote Flexibility: Facilitate the easy swapping of external technologies by simply replacing the adapter that implements a given port, without affecting the core.
There are two main types of ports, categorized by the direction of interaction:
-
Driving Ports (Primary Ports / Inbound Ports):
- Role: These interfaces are defined by the application core and are implemented by the core itself. They represent the application's API or the operations that external actors can invoke to drive the application's behavior.
- Analogy: Think of these as the "sockets" on the hexagon that external systems "plug into" to initiate actions.
- Example:
Here,
// Defined within the application core interface PlaceOrderUseCase { void execute(OrderRequest request); }PlaceOrderUseCaseis a driving port. Any external system (e.g., a web UI, a message queue listener) that wants to place an order will interact with an implementation of this interface.
-
Driven Ports (Secondary Ports / Outbound Ports):
- Role: These interfaces are also defined by the application core, but they are implemented by external adapters. They represent the capabilities that the application core needs from external systems to fulfill its business logic. The application core drives these ports to interact with external resources.
- Analogy: These are the "plugs" on the hexagon that the application core uses to connect to external services.
- Example:
Here,
// Defined within the application core interface OrderRepository { void save(Order order); Optional<Order> findById(OrderId id); }OrderRepositoryis a driven port. The application core needs to save and retrieve orders, but it doesn't care how (e.g., SQL database, NoSQL database, in-memory). It just defines the contract for these operations.
Ports define what can be done or what is needed, while Adapters provide the concrete how. An adapter is a specific implementation of a port, translating between the technology-agnostic interface of the port and the technology-specific details of an external system. This clear separation is fundamental to the flexibility and testability offered by Hexagonal Architecture.