Arquitetura Hexagonal
Definição
A Arquitetura Hexagonal (também conhecida como Ports and Adapters) é um estilo arquitetural que busca isolar o núcleo da aplicação — onde estão as regras de negócio — de detalhes externos como interfaces gráficas, bancos de dados e APIs.
O objetivo é tornar o sistema mais independente, permitindo que qualquer interação com o mundo externo (como entrada de dados ou persistência) seja feita por meio de portas (ports) e adaptadores (adapters).
Por que é importante
Essa arquitetura facilita a manutenção, os testes e a evolução do sistema, pois a lógica central da aplicação não depende diretamente de detalhes de infraestrutura.
Isso permite, por exemplo, trocar um banco de dados, mudar a interface (de web para CLI) ou adicionar novos canais (como mensageria) sem impactar o núcleo da aplicação.
Estrutura típica
A aplicação é organizada em três partes principais:
- Núcleo (Domínio): contém as regras de negócio e casos de uso. É a parte mais estável e independente do sistema.
- Portas (Ports): interfaces que definem como o domínio se comunica com o mundo externo (entrada e saída).
- Adaptadores (Adapters): implementações concretas das portas — por exemplo, controladores HTTP, gateways de banco de dados ou serviços externos.
A principal regra da arquitetura hexagonal é que as dependências apontam para dentro — ou seja, o núcleo da aplicação nunca conhece as implementações externas.
[ Interface Web / CLI / Teste ]
↓
[ Porta de Entrada ]
↓
[ Núcleo ]
↑
[ Porta de Saída ]
↑
[ Banco / APIs / Mensageria ]
As portas e adaptadores podem ser substituídos ou estendidos sem alterar o núcleo da aplicação.
Exemplo prático (em Python)
Vamos simular uma aplicação que envia notificações. O núcleo define um caso de uso e uma porta de saída (Notificador
), enquanto os adaptadores implementam essa porta usando diferentes meios (e-mail ou SMS):
# Núcleo (caso de uso + porta)
from abc import ABC, abstractmethod
# Porta de saída
class Notificador(ABC):
@abstractmethod
def enviar(self, mensagem):
pass
class ServicoDeAlerta:
def __init__(self, notificador: Notificador):
self.notificador = notificador
def alerta(self):
self.notificador.enviar("Atenção: algo importante ocorreu!")
Agora criamos adaptadores que implementam a porta:
# Adaptadores externos
class EmailNotificador(Notificador):
def enviar(self, mensagem):
print(f"[E-mail] {mensagem}")
class SMSNotificador(Notificador):
def enviar(self, mensagem):
print(f"[SMS] {mensagem}")
E no ponto de entrada da aplicação (controlador, CLI, etc), conectamos o adaptador à porta:
# Composição no nível da interface externa
notificador = EmailNotificador() # ou SMSNotificador()
servico = ServicoDeAlerta(notificador)
servico.alerta()
O núcleo da aplicação (ServicoDeAlerta
) não depende de qual canal será usado — ele depende apenas da interface Notificador
. Esse é o princípio da Arquitetura Hexagonal em prática.
Comparação com arquitetura em camadas
Enquanto a arquitetura em camadas costuma ter dependências direcionadas de cima para baixo (por exemplo, a camada de aplicação acessa diretamente a camada de dados), a arquitetura hexagonal inverte essas dependências com o uso de interfaces.
Isso reforça a independência da lógica de negócio e permite que o domínio seja testado isoladamente.