Camadas, Clean & Hexagonal
Uma pergunta simples conduz a investigação: é possível substituir o banco de dados e a interface de entrada sem modificar as regras de negócio? Vamos fazer essa troca de verdade, usando uma miniaplicação de reservas com Python e testes automatizados.
01 — Três modelos, uma mesma investigação
| Perspectiva | Pergunta central | Decisão observável |
|---|---|---|
| Arquitetura em camadas | Quem é responsável por cada operação? | Domínio, aplicação e infraestrutura possuem papéis distintos. |
| Clean Architecture | Para onde apontam as dependências do código? | Políticas internas não importam detalhes externos. |
| Hexagonal | Como substituir entradas e saídas? | Portas definidas no núcleo recebem diferentes adaptadores. |
São lentes complementares — não três padrões obrigatoriamente excludentes. DIP é a inversão de dependência em direção a abstrações; injeção de dependências é a entrega dos objetos concretos ao caso de uso.
02 — Mapa da arquitetura
O fluxo de execução pode ir da entrada até a persistência. O fluxo das dependências de código é diferente: adaptadores importam o núcleo, mas o núcleo não importa SQLite, CLI nem serviços HTTP.
03 — O mesmo caso de uso com dois bancos
class CreateReservation:
def __init__(self, repository: ReservationRepository,
id_generator: IdGenerator):
self._repository = repository
self._ids = id_generator
def execute(self, command):
booking = Reservation.create(
self._ids.new_id(),
command.event_code,
command.guest_name,
command.seats,
)
self._repository.add(booking)
return booking
O código acima é retirado do caso de uso do experimento, com o nome local booking simplificado para a página. O objeto recebido na porta pode ser InMemoryReservations ou SQLiteReservations — o método de aplicação permanece igual.
04 — O que construir e medir
- Execute os testes de domínio com entradas válidas e inválidas: identificador do evento, nome e quantidade entre 1 e 6 lugares.
- Rode a mesma suíte de contrato nos adaptadores de memória e SQLite. Reabra o SQLite para verificar persistência entre conexões.
- Substitua a entrada CLI pelo controlador JSON. Ele simula a borda HTTP, mas não inicia um servidor.
- Rode a análise estrutural de imports para conferir a regra do núcleo: nenhum import de infraestrutura.
- Registre qual arquivo precisou mudar em cada troca. Documente também os custos: mais contratos, composição e testes.
05 — Reproduzir na própria bancada
cd Cerberus/experiments/02-layers-clean-hexagonal
python -m pip install -e .
python -m unittest discover -s tests -v
python -m cerberus02.adapters.cli --backend sqlite \
--db ./demo.db create --event wolfcon2026 \
--guest Ada --seats 2
O CLI retorna um reservation_id, que pode ser consultado com o subcomando get apontando para o mesmo banco. Não há frontend que faça reservas nesta página; o projeto completo está no repositório.
06 — Segurança e limites
Os testes comprovam o contrato e a organização neste cenário pequeno; não são métricas de latência nem provas de que a arquitetura reduz custos em todo projeto. As decisões e os trade-offs estão registrados no ADR-0002.
VER CÓDIGO, TESTES E ADR →