Senior
O que sabe sobre arquitetura de ports e adapters?
sobes.tech IA
Resposta da IA
A arquitetura de portas e adaptadores, também conhecida como Arquitetura Hexagonal (Hexagonal Architecture), separa a lógica do domínio da aplicação (Core) das dependências externas (interfaces de utilizador, bases de dados, serviços externos).
Conceitos principais:
- Portas: Definem as interfaces através das quais o Core interage com o mundo exterior. As portas são de dois tipos:
- Entrantes (Driving Ports): Utilizadas por entidades externas para invocar a funcionalidade do Core (por exemplo, interface API).
- Saídas (Driven Ports): Utilizadas pelo Core para invocar funcionalidades de entidades externas (por exemplo, interface de repositório para aceder a dados).
- Adaptadores: Implementam as portas, ligando o Core a tecnologias ou frameworks externos específicos.
- Entrantes (Driving Adapters): Implementam as portas entrantes e transformam as requisições externas em chamadas ao Core (por exemplo, controlador REST).
- Saídas (Driven Adapters): Implementam as portas saídas e transformam as chamadas do Core para interagir com o ambiente externo (por exemplo, implementação de repositório para trabalhar com uma base de dados específica).
- Core (Domínio): Contém a lógica de negócio da aplicação. Está completamente isolado dos detalhes externos e só interage com eles através de portas.
Vantagens:
- Testabilidade: O isolamento do Core facilita os testes unitários da lógica de negócio sem necessidade de simular dependências externas complexas.
- Flexibilidade: Permite substituir ou adicionar novas tecnologias externas (bases de dados, frameworks) sem modificar o Core. Basta escrever um novo adaptador para uma porta existente.
- Código limpo: Promove a criação de um código mais limpo e sustentável, focando apenas nas regras de negócio.
- Separação de responsabilidades: Divide claramente as áreas de responsabilidade.
Relação com o Frontend:
No frontend, a arquitetura de portas e adaptadores aplica-se para:
- Separar a lógica de negócio do componente das fontes de dados: O componente interage com um "porta" (interface), que pode ser implementado por diferentes "adaptadores" (que obtêm dados de API, armazenamento local, mocks, etc.).
- Gestão de eventos externos: As portas entrantes podem representar gestores de eventos da UI, e os adaptadores transformam esses eventos em chamadas à lógica interna.
- Encapsulamento da interação com bibliotecas externas: Os adaptadores podem envolver chamadas a bibliotecas de terceiros (por exemplo, biblioteca para trabalhar com mapas), fornecendo ao Core uma interface simples e estável.
Exemplo em JavaScript (esquema):
// Exemplo de porta saída (interface para obter dados)
class DataGateway {
getData() {
throw new Error("O método getData deve ser implementado");
}
}
// Exemplo de adaptador saída (implementação da porta para API)
class ApiDataGateway extends DataGateway {
async getData() {
const response = await fetch('/api/data');
return response.json();
}
}
// Exemplo de porta entrada (interface para lógica de negócio)
class BusinessLogicPort {
constructor(dataGateway) {
this.dataGateway = dataGateway;
}
async processData() {
throw new Error("O método processData deve ser implementado");
}
}
// Exemplo de Core (lógica de negócio)
class MyBusinessLogic extends BusinessLogicPort {
async processData() {
const data = await this.dataGateway.getData();
// Lógica de processamento de dados
console.log("Dados processados:", data);
return data;
}
}
// Exemplo de adaptador entrada (uso na UI)
async function initApp() {
const apiGateway = new ApiDataGateway(); // Adaptador concreto
const businessLogic = new MyBusinessLogic(apiGateway); // Core usa o port
await businessLogic.processData(); // Adaptador entrada chama o Core
}
initApp();