Existem dois tipos de complexidade em um sistema:
- Complexidade de negócio: as regras que dão valor ao software.
- Complexidade técnica: frameworks, bancos, filas, protocolos.
A arquitetura hexagonal, proposta por Alistair Cockburn em 2005 com o nome Ports and Adapters, separa as duas. Com isso, frameworks e dependências podem ser substituídos ou atualizados sem interferir nas regras de negócio.
- Domínio: as regras de negócio. Não importa nada de framework, banco ou HTTP.
- Portas: interfaces definidas pelo domínio. As de entrada dizem o que o sistema faz (casos de uso); as de saída, o que ele precisa do mundo (salvar um pedido, enviar um e-mail).
- Adapters: as implementações técnicas que se ligam às portas: um controller REST, um repositório Postgres, um cliente de e-mail.
A regra que sustenta tudo: as dependências apontam para dentro. O domínio não conhece os adapters; os adapters conhecem o domínio.
// porta de saída, definida pelo domíniotype OrderRepository interface { Save(order Order) error}
// caso de uso: só conhece a portafunc CreateOrder(repo OrderRepository, items []Item) (Order, error) { order := NewOrder(items) // regras de negócio return order, repo.Save(order)}Em produção, repo é o adapter do Postgres; nos testes, uma versão em memória, sem subir banco nenhum.
Por que vale a pena
- Crescimento sustentável: o software continua fácil de mudar com o tempo.
- O software precisa se pagar ao longo do tempo, e trocar uma tecnologia não deveria exigir reescrever o negócio.
- O software deve ser desenhado por você, e não pelo framework.
- As peças precisam se encaixar e, eventualmente, ser substituídas.
O custo é mais estrutura (interfaces e mapeamentos) do que um CRUD simples precisa. Vale quando há regra de negócio de verdade.
Veja também: Fundamentos de arquitetura.
- Para se aprofundar: Hexagonal architecture, de Alistair Cockburn