⌬ CERBERUS / THE WORKSHOPSOFTWARE ARCHITECTURE LAB · V0.4
CERBERUS_02 / EXPERIMENTO 002 / PYTHON · PORTS & ADAPTERS

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.

Hipótese de pesquisa: separar domínio, aplicação e adaptadores e fazer as dependências apontarem para o núcleo permite substituir infraestrutura sem modificar entidades e casos de uso. O experimento testa substituibilidade, não comprova ganhos universais de desempenho ou manutenibilidade.

01 — Três modelos, uma mesma investigação

PerspectivaPergunta centralDecisão observável
Arquitetura em camadasQuem é responsável por cada operação?Domínio, aplicação e infraestrutura possuem papéis distintos.
Clean ArchitecturePara onde apontam as dependências do código?Políticas internas não importam detalhes externos.
HexagonalComo 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

  1. Execute os testes de domínio com entradas válidas e inválidas: identificador do evento, nome e quantidade entre 1 e 6 lugares.
  2. Rode a mesma suíte de contrato nos adaptadores de memória e SQLite. Reabra o SQLite para verificar persistência entre conexões.
  3. Substitua a entrada CLI pelo controlador JSON. Ele simula a borda HTTP, mas não inicia um servidor.
  4. Rode a análise estrutural de imports para conferir a regra do núcleo: nenhum import de infraestrutura.
  5. 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

O banco SQLite é apenas local; as consultas utilizam parâmetros vinculados. Não há autenticação, autorização, gestão de capacidade total, idempotência, proteção de dados pessoais ou garantia de concorrência. Portanto, não é um sistema de reservas pronto para produção.

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 →

← VOLTAR AO ROADMAP   LABORATÓRIO 01 ↗