Senior
What do you know about port architecture and adapters?
sobes.tech AI
Answer from AI
Ports and adapters architecture, also known as Hexagonal Architecture, separates the application's domain logic (Core) from external dependencies (user interfaces, databases, external services).
Main concepts:
- Ports: Define interfaces through which the Core interacts with the outside world. Ports are of two types:
- Driving Ports: Used by external entities to invoke Core functionality (e.g., API interface).
- Driven Ports: Used by the Core to invoke functionality of external entities (e.g., repository interface for data access).
- Adapters: Implement ports, connecting the Core to specific external technologies or frameworks.
- Driving Adapters: Implement driving ports and transform incoming requests from the external environment into calls to the Core (e.g., REST controller).
- Driven Adapters: Implement driven ports and transform calls from the Core for interaction with the external environment (e.g., repository implementation for working with a specific database).
- Core (Domain): Contains the application's business logic. It is completely isolated from external details and interacts with them only through ports.
Advantages:
- Testability: Isolating the Core makes unit testing business logic easier without mocking complex external dependencies.
- Flexibility: Easily replace or add new external technologies (databases, frameworks) without changing the Core. Just write a new adapter for an existing port.
- Clean code: Promotes creating cleaner and more maintainable code, focusing the Core only on business rules.
- Separation of concerns: Clearly divides responsibility zones.
Connection with Frontend:
In Frontend, ports and adapters architecture applies to:
- Separating component business logic from data sources: The component interacts with a "port" (interface), which can be implemented by different "adapters" (fetching data from API, Local Storage, mock data, etc.).
- Handling external events: Incoming ports can represent UI event handlers, and adapters transform these events into calls to internal logic.
- Encapsulating interaction with external libraries: Adapters can wrap calls to third-party libraries (e.g., map libraries), providing the Core with a simple and stable interface.
Example in JavaScript (diagram):
// Example of an outgoing port (interface for data retrieval)
class DataGateway {
getData() {
throw new Error("Method getData must be implemented");
}
}
// Example of an outgoing adapter (API implementation of the port)
class ApiDataGateway extends DataGateway {
async getData() {
const response = await fetch('/api/data');
return response.json();
}
}
// Example of an incoming port (interface for business logic)
class BusinessLogicPort {
constructor(dataGateway) {
this.dataGateway = dataGateway;
}
async processData() {
throw new Error("Method processData must be implemented");
}
}
// Core example (business logic)
class MyBusinessLogic extends BusinessLogicPort {
async processData() {
const data = await this.dataGateway.getData();
// Data processing logic
console.log("Data processed:", data);
return data;
}
}
// Incoming adapter example (using logic in UI)
async function initApp() {
const apiGateway = new ApiDataGateway(); // Concrete adapter
const businessLogic = new MyBusinessLogic(apiGateway); // Core uses port
await businessLogic.processData(); // Incoming adapter calls Core
}
initApp();