---
id: architectural-styles-map
domain: architecture
agents: [architect]
when: "ao decidir a forma estrutural de um projeto (camadas, fronteiras, organização)"
---

# Mapa de estilos arquiteturais — escolher a forma estrutural sem cargo-cult

## O problema

A decisão de forma estrutural quase nunca é tomada por critério — é tomada por hábito ("foi o que usei no
último projeto"), por moda ("todo mundo faz Clean + CQRS + Event Sourcing") ou por medo ("melhor sobrar
camada do que faltar"). O resultado tem cara reconhecível e é o equivalente arquitetural do "look de IA":

1. **Clean/Onion/Hexagonal aplicado a um CRUD de 4 tabelas** — 5 projetos na solution, mappers de DTO para
   entidade para DTO, e a "regra de dependência" defendida com unhas e dentes num sistema que nunca terá
   uma segunda implementação de repositório.
2. **CQRS com bancos de leitura e escrita separados** num domínio onde leitura e escrita têm o mesmo
   modelo e a mesma carga. A própria fonte tem um artigo chamado *"CQRS is not a general purpose style of
   architecture"* exatamente por causa disso.
3. **Event Sourcing "porque dá auditoria"** num sistema que só precisava de uma coluna `updated_at` e uma
   tabela de log. Append-only log, versionamento de evento, projeções e *eventual consistency* — três
   problemas novos para resolver um que não existia.
4. **Layered/N-tier chamado de "arquitetura"** quando na verdade é uma `Controller → Service → Repository`
   anêmica: a camada de domínio não tem comportamento, só getters/setters (o *anemic domain model*, listado
   como anti-padrão na própria fonte).
5. **Bounded contexts demais** — cada agregado virou um "microsserviço" antes de existir uma única regra de
   negócio estável. Fronteira de contexto sem *context mapping*, então tudo acopla via banco compartilhado.
6. **Zero documentação de decisão** — ninguém sabe *por que* o sistema é Hexagonal e não Layered. Sem ADR,
   a decisão não tem rastro; seis meses depois alguém "simplifica" e quebra a fronteira de propósito.

A regra-mãe: **estilo arquitetural é resposta a uma força concreta (taxa de mudança, número de
integrações, criticidade, assimetria leitura/escrita), não um default.** Se você não consegue nomear a
força que justifica a camada, a camada é custo sem retorno. Estrutura existe para *isolar o que muda por
razões diferentes* — não para parecer sofisticada.

> Fonte de referência (curadoria real): `mehdihadeli/awesome-software-architecture`
> (`awesome-architecture.com`) — seções *Architectural Styles* (Clean, Hexagonal, Onion, Layered, Vertical
> Slice, Modular Monolith), *Domain Driven Design* (strategic/tactical), *CQRS*, *Event Sourcing*,
> *Architecture Documentation* (C4, ADR, arc42).

## Os princípios / o conhecimento

### 1. A família "regra de dependência" — Clean, Hexagonal, Onion são a MESMA ideia com nomes diferentes

Os três compartilham um único princípio: **dependências apontam para dentro, em direção ao domínio; o
domínio não conhece infraestrutura.** Isso é a aplicação do *Dependency Inversion Principle* (listado em
*architectural-design-principles* na fonte) na escala de toda a aplicação. A diferença entre eles é
*vocabulário e ênfase*, não mecânica.

| Estilo | Autor / origem | A regra de dependência (exata) | Vocabulário próprio | Ênfase distintiva |
|---|---|---|---|---|
| **Layered / N-tier** | Clássico (Fowler, PoEAA) | Cada camada depende **da de baixo** (UI → App → Domínio → Dados). Dependência desce. | Presentation, Business, Data Access | Simplicidade; mas o domínio acaba dependendo do banco |
| **Hexagonal (Ports & Adapters)** | Alistair Cockburn (2005) | O núcleo define **ports** (interfaces); **adapters** externos dependem do núcleo, nunca o contrário. Simétrico: driving (entrada) e driven (saída). | Port, Adapter, driving/driven side | Testabilidade: troca-se qualquer adapter (DB, UI, fila) sem tocar no núcleo |
| **Onion** | Jeffrey Palermo (2008) | Camadas **concêntricas**; dependência aponta para o centro. Centro = Domain Model; fora = Infra/UI. | Domain Model → Domain Services → App Services → Infra | Domínio no centro absoluto; infraestrutura é a casca mais externa |
| **Clean** | Robert C. Martin / "Uncle Bob" (2012) | **The Dependency Rule:** "source code dependencies can only point inwards". Entities → Use Cases → Interface Adapters → Frameworks & Drivers. | Entities, Use Cases, Interface Adapters, Frameworks | Síntese de Onion + Hexagonal + DDD; nomeia explicitamente *Use Cases* como anel próprio |

**Como decidir entre eles** (não confunda "diferente" com "melhor"):

| Sua situação | Estilo indicado | Por quê |
|---|---|---|
| CRUD simples, pouca regra, time pequeno | **Layered** (ou Vertical Slice) | A inversão completa é custo sem retorno; descer a dependência é honesto e barato |
| Muitos pontos de I/O (DB + filas + APIs externas + UI) que mudam independentemente | **Hexagonal** | Ports/adapters isolam cada integração; cada uma vira um adapter trocável |
| Domínio rico, regras no centro, quero proteger o modelo de qualquer tecnologia | **Onion** ou **Clean** | Domínio no centro, infra na casca; *persistence ignorance* garantida |
| Quero um nome de camada explícito para "o que o sistema faz" (orquestração de caso de uso) | **Clean** | É o único que dá ao anel de *Use Cases* status de primeira classe |
| Feature-oriented, quero minimizar acoplamento horizontal entre camadas | **Vertical Slice** | Corta por funcionalidade, não por camada técnica; cada slice é coeso ponta a ponta |

> Pragmatismo: para a maioria dos sistemas de negócio, **Hexagonal e Clean convergem na prática**. Escolha
> um vocabulário e seja consistente. O erro caro não é escolher "errado" entre eles — é aplicar qualquer
> um dos três a um problema que era Layered.

### 2. DDD não é um estilo de camada — é tático **e** estratégico, e você quase sempre quer o estratégico primeiro

A fonte separa DDD em dois blocos, e essa separação é a decisão mais subestimada:

| | DDD **Tático** | DDD **Estratégico** |
|---|---|---|
| Pergunta que responde | "Como modelo *dentro* de uma fronteira?" | "*Onde* ficam as fronteiras?" |
| Artefatos (da fonte) | Entities, **Value Objects**, **Aggregates** (aggregation), Domain Services, Application Services, Domain Events, Repositories, Rich Domain Model | **Bounded Contexts**, **Context Mapping**, Ubiquitous Language, Core/Supporting/Generic **Subdomains**, Strategic Design Patterns |
| Quando aplicar | Quando o domínio tem invariantes e comportamento (não é CRUD) | Quando o sistema cobre múltiplas áreas de negócio que evoluem em ritmos diferentes |
| Erro comum | *Anemic Domain Model* — entidade sem comportamento, só getters/setters (anti-padrão na fonte) | Fatiar em microsserviços por agregado, sem *context mapping*, criando acoplamento por banco compartilhado |

**Sequência correta:** estratégico **antes** de tático. Primeiro descubra os *bounded contexts* (onde a
linguagem ubíqua muda de significado é onde a fronteira está), depois aplique o modelo tático *dentro* de
cada contexto. Decidir Aggregates antes de saber o Core Domain é otimizar a parte errada.

**Quando NÃO fazer DDD tático:** se o domínio é genérico (autenticação, notificação, billing de
prateleira) ou é CRUD puro, o modelo rico é over-engineering. Use *Transaction Script* (também listado na
fonte como design pattern) — é honesto para lógica procedural simples.

Mapeamento de aggregate ↔ estilo: o **Aggregate** é a fronteira de consistência *transacional*; o
**Bounded Context** é a fronteira de *modelo/linguagem* (e candidato a fronteira de deploy/serviço). Não
confunda os dois — um contexto contém vários agregados.

### 3. CQRS e Event Sourcing — dois eixos independentes, ambos com alto custo de entrada

O erro número um é tratá-los como pacote ("Clean + CQRS + ES"). São **decisões ortogonais**: dá para ter
CQRS sem Event Sourcing, Event Sourcing sem CQRS separado, e a maioria dos sistemas não quer nenhum dos
dois.

**CQRS** = separar o modelo de *escrita* (commands) do modelo de *leitura* (queries). É a aplicação do
princípio **CQS** (Command Query Separation, listado na fonte) na escala de arquitetura. Pode ser leve (dois
modelos, um banco) ou pesado (dois bancos, sincronizados por eventos).

| Use CQRS quando… | NÃO use CQRS quando… |
|---|---|
| Leitura e escrita têm **modelos genuinamente diferentes** (escrita normalizada, leitura em projeções desnormalizadas) | Leitura e escrita compartilham o mesmo modelo — separar é duplicação pura |
| Assimetria de carga forte (ex.: 100x mais leitura que escrita) que justifica escalar os lados separadamente | Carga simétrica e modesta — um modelo único escala bem |
| Domínio complexo onde a lógica de escrita se beneficia de não carregar concern de leitura | CRUD; a própria fonte: *"CQRS is not a general purpose style of architecture"* |
| Já existe Event Sourcing (projeções de leitura caem naturalmente) | Time pequeno sem experiência — *eventual consistency* entre os lados é armadilha sutil |

**Event Sourcing** = persistir o estado como uma **sequência imutável de eventos** (append-only log), não
como snapshot do estado atual. Reconstrói qualquer estado passado por replay.

| Use Event Sourcing quando… | NÃO use Event Sourcing quando… |
|---|---|
| **Auditoria/compliance** exige histórico completo e imutável de cada mudança | Um `updated_at` + tabela de log resolve a auditoria que você realmente precisa |
| Você precisa de **queries temporais** (estado em qualquer ponto no tempo) | Você só precisa do estado atual e consistência imediata |
| Domínio rico onde o *evento* é a verdade do negócio (financeiro, logística, jogos) | CRUD simples — ES introduz versionamento de evento, projeções e *eventual consistency* sem retorno |
| Forense/debug: replay do log reproduz o caminho até o bug | Time sem maturidade para lidar com migração de schema de eventos antigos |

**Sinal de over-engineering (qualquer um destes = pare):** o domínio é CRUD; não há requisito de auditoria
temporal nem de histórico; a leitura e a escrita têm o mesmo modelo; o time nunca operou *eventual
consistency* em produção. Nesses casos, Layered + um modelo de domínio honesto entrega mais valor com
ordens de magnitude menos risco.

### 4. Documentar a decisão — C4 (a forma) + ADR (o porquê)

Estrutura sem documentação de decisão apodrece: a próxima pessoa não sabe *por que* a fronteira existe e a
quebra "simplificando". A fonte (*Architecture Documentation*) aponta o par canônico:

| Ferramenta | O que captura | Granularidade | Quando produzir |
|---|---|---|---|
| **C4 Model** (Simon Brown) | A **forma** do sistema em 4 níveis: **Context** (sistema + atores) → **Container** (apps/serviços/bancos) → **Component** (dentro de um container) → **Code** (raro, gerado) | Do macro ao micro; pare no nível que agrega valor (geralmente Context + Container) | No design inicial e quando a topologia muda |
| **ADR** (Architecture Decision Record, Michael Nygard) | O **porquê** de cada decisão: contexto, decisão, alternativas, consequências. "A LOG that answers WHY" | Uma decisão por arquivo, numerado, imutável (decisões revogadas viram "superseded") | Toda decisão estrutural com trade-off (escolha de estilo, fronteira, CQRS sim/não) |
| **arc42** | Template guarda-chuva de documentação (a fonte: *"the template for software architecture documentation"*) | Documento vivo do sistema | Quando se quer um doc de arquitetura completo e padronizado |

Regra prática: **C4 mostra o que você construiu; ADR explica por que não construiu de outro jeito.** Os dois
juntos. Diagrama sem ADR vira desenho bonito sem rastro de decisão; ADR sem C4 vira prosa sem mapa.
Mantenha ambos versionados junto do código (*Architecture as Code*, citado na fonte).

## Checklist — "esta forma estrutural é justificada ou é cargo-cult?"

Antes de fechar a decisão de estilo, responda. Qualquer "sim" da coluna errada é um tell a corrigir:

- [ ] Consigo **nomear a força concreta** (taxa de mudança, número de integrações, criticidade, assimetria
      leitura/escrita) que justifica cada camada/fronteira que estou adicionando?
- [ ] Estou aplicando Clean/Onion/Hexagonal a um **CRUD simples**? (Se sim → Layered ou Vertical Slice.)
- [ ] Defini os **bounded contexts** (estratégico) **antes** de detalhar Aggregates/Value Objects (tático)?
- [ ] Meu modelo de domínio tem **comportamento**, ou é anêmico (só getters/setters)?
- [ ] Estou adotando **CQRS** sem que leitura e escrita tenham modelos genuinamente diferentes ou
      assimetria de carga real?
- [ ] Estou adotando **Event Sourcing** sem requisito real de auditoria temporal / histórico imutável?
- [ ] O time **já operou** *eventual consistency* em produção, se estou indo para CQRS pesado ou ES?
- [ ] Cada agregado virou microsserviço **antes** de ter *context mapping* definido? (Se sim → recue.)
- [ ] Existe um **ADR** registrando *por que* este estilo e não os alternativos?
- [ ] Existe um **C4** (ao menos Context + Container) mostrando a forma para quem chega depois?
- [ ] Se eu remover esta camada/separação, **algo concreto quebra** — ou só fica "menos sofisticado"?

## Tabela de decisão — "use o estilo X quando o sistema tem a característica Y"

| Característica do sistema (Y) | Estilo / decisão (X) | Evite |
|---|---|---|
| CRUD, poucas regras, time pequeno, baixa criticidade | **Layered / N-tier** ou **Vertical Slice** | Clean/Onion/Hexagonal, CQRS, ES |
| Feature-oriented, quer coesão ponta a ponta por funcionalidade | **Vertical Slice Architecture** | Camadas horizontais espessas |
| Muitos I/O independentes (DB + filas + APIs + UI) que trocam separadamente | **Hexagonal (Ports & Adapters)** | Layered (acopla domínio ao DB) |
| Domínio rico, modelo precisa ser protegido de qualquer tecnologia | **Onion** ou **Clean** | Anemic domain model |
| Preciso de status explícito para "casos de uso" / orquestração | **Clean Architecture** | — |
| Sistema cobre várias áreas de negócio em ritmos diferentes | **DDD estratégico**: bounded contexts + context mapping | Microsserviço por agregado sem mapping |
| Dentro de uma fronteira com invariantes e comportamento | **DDD tático**: Aggregates, Value Objects, Domain Events, Repositories | Transaction script com regra espalhada |
| Lógica procedural simples, domínio genérico (auth, notificação) | **Transaction Script** | DDD tático completo |
| Leitura e escrita com modelos diferentes OU assimetria de carga forte | **CQRS** (leve: 1 banco; pesado: 2 bancos só se a escala exigir) | CQRS em CRUD simétrico |
| Auditoria/compliance com histórico imutável + queries temporais | **Event Sourcing** (+ projeções; geralmente com CQRS) | ES "pela auditoria" quando log+timestamp basta |
| Só precisa do estado atual, consistência imediata | **Snapshot/estado** (persistência tradicional) | Event Sourcing |
| Múltiplos contextos mas ainda sem regra estável / time pequeno | **Modular Monolith** (módulos com fronteira interna) | Microsserviços prematuros |
| Qualquer decisão estrutural com trade-off | **Registrar um ADR** + diagrama **C4** (Context + Container) | Decisão sem rastro |

> Princípio de fechamento: **comece no estilo mais simples que respeita as forças do sistema e evolua sob
> pressão real.** É barato promover Layered → Hexagonal quando as integrações crescerem; é caro desmontar
> Event Sourcing aplicado cedo demais. A sofisticação correta é a que você consegue justificar num ADR — o
> resto é o "look de IA" da arquitetura.
