Sobes.tech
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();