DDD: definindo bounded contexts corretamente
1. Fundamentos do Bounded Context no DDD
O Bounded Context é o conceito central do Domain-Driven Design que estabelece limites explícitos onde um modelo de domínio específico é válido e consistente. Dentro de cada contexto, a linguagem, as regras de negócio e as entidades têm significados precisos e não ambíguos.
Domínio, Subdomínio e Bounded Context não são sinônimos. O domínio é o problema central que o software resolve. Subdomínios são partes desse problema (core, supporting, generic). O Bounded Context é a solução técnica e organizacional que implementa um modelo para um subdomínio específico.
O Ubiquitous Language é a âncora que mantém o contexto coeso. Quando a equipe de negócio usa termos diferentes para a mesma ideia, ou o mesmo termo com significados diferentes, estamos diante de contextos distintos.
Exemplo: em um sistema bancário, "Conta" no contexto de Abertura de Conta significa "documentação e aprovação de crédito", enquanto no contexto de Transações significa "saldo disponível e extrato". São modelos diferentes para a mesma palavra.
// Contexto: Abertura de Conta
Classe Conta {
status: Pendente | Aprovada | Rejeitada
documentoCliente: CPF
analiseCredito: Score
}
// Contexto: Transações
Classe Conta {
saldo: Decimal
limite: Decimal
transacoes: List<Transacao>
}
2. Identificando os Limites: Estratégias Práticas
A fronteira de um Bounded Context se revela onde a linguagem muda. Se o time de vendas chama "Cliente" de "Lead" e o time de suporte chama de "Usuário", há dois contextos.
Mapeamento de fluxos de negócio ajuda a identificar onde eventos e comandos cruzam fronteiras. Quando um pedido gera uma cobrança, o evento "PedidoConfirmado" pertence ao contexto de Pedidos, enquanto "CobrançaEfetuada" pertence ao contexto de Pagamento.
Event Storming é a técnica mais eficaz para revelar contextos ocultos. Reúna especialistas de domínio e times técnicos em uma sala. Cole post-its laranja para eventos do domínio. Onde houver confusão sobre o significado de um evento, provavelmente há uma fronteira de contexto.
Fluxo identificado via Event Storming:
[ClienteAdicionaProduto] -> [CarrinhoAtualizado] -> [PedidoConfirmado]
↑ Contexto Catálogo ↑ Contexto Carrinho ↑ Contexto Pedidos
3. Relacionamentos entre Bounded Contexts
Contextos não vivem isolados. Eles se relacionam de formas específicas:
Customer/Supplier: um contexto fornece dados que outro consome. O contexto de Catálogo fornece preços para o contexto de Pedidos.
Conformist: um contexto aceita passivamente o modelo do outro para evitar complexidade. Útil quando o fornecedor é maduro e estável.
Anticorruption Layer (ACL): uma camada de tradução que protege o modelo do contexto consumidor das complexidades do fornecedor. Essencial quando integrações com sistemas legados são inevitáveis.
Shared Kernel: área compartilhada entre contextos. Risco alto de acoplamento, mas útil para entidades verdadeiramente compartilhadas.
Context Map do sistema bancário:
┌─────────────────┐ ACL ┌──────────────────┐
│ Contas a Pagar │◄────────────│ Sistema Legado │
│ (modelo limpo) │ │ (ERP antigo) │
└─────────────────┘ └──────────────────┘
│
│ Shared Kernel (Cliente)
▼
┌─────────────────┐
│ Cobrança │
└─────────────────┘
4. Erros Comuns na Definição de Contextos
Contextos muito grandes criam um monólito disfarçado. Um único contexto que abrange "todo o sistema de vendas" provavelmente esconde múltiplos subdomínios com linguagens diferentes.
Contextos muito pequenos geram microserviços artificiais. Separar "Validação de CPF" em um contexto próprio é excesso de granularidade. Validação de CPF é uma regra técnica, não um contexto de domínio.
Confundir subdomínio de suporte com contexto principal leva a investimento excessivo em áreas periféricas. O subdomínio de suporte "Notificação por Email" não precisa do mesmo rigor que o core "Processamento de Pedidos".
Ignorar a evolução é o erro mais custoso. Contextos mudam conforme o negócio muda. Um contexto que nunca é revisitado acumula dívida técnica e perde alinhamento com o domínio.
5. Bounded Context e Arquitetura de Software
Cada Bounded Context pode ser implementado como um hexágono na Arquitetura Hexagonal. O modelo de domínio fica no centro, protegido por portas e adaptadores. As fronteiras do hexágono correspondem exatamente aos limites do contexto.
Integração via Event-Driven respeita as fronteiras. Quando um evento cruza contextos, ele carrega apenas os dados necessários, não o modelo completo. O contexto receptor interpreta o evento conforme seu próprio modelo.
CQRS dentro de um contexto separa operações de leitura e escrita sem quebrar o limite. O comando "CriarPedido" e a query "ListarPedidosDoCliente" pertencem ao mesmo contexto, mesmo que usem bancos diferentes.
Arquitetura Hexagonal do Contexto Pedidos:
┌─────────────────────────────────────┐
│ Adaptadores Web / API │
│ ┌───────────────────────────────┐ │
│ │ Portas de Entrada │ │
│ │ ┌─────────────────────────┐ │ │
│ │ │ Domínio: Pedidos │ │ │
│ │ │ - Entidades │ │ │
│ │ │ - Regras de Negócio │ │ │
│ │ │ - Serviços de Domínio │ │ │
│ │ └─────────────────────────┘ │ │
│ │ Portas de Saída │ │
│ └───────────────────────────────┘ │
│ Adaptadores Banco / Eventos │
└─────────────────────────────────────┘
6. Exemplo Prático: E-commerce em Bounded Contexts
Um e-commerce típico pode ser dividido em:
- Catálogo: gerencia produtos, categorias, preços e estoque
- Carrinho: mantém itens temporários antes da compra
- Pedidos: processa confirmação, cancelamento e histórico
- Pagamento: gerencia transações financeiras e antifraude
- Logística: cuida de endereços, fretes e entregas
- Faturamento: emite notas fiscais e gerencia cobranças
Cada contexto tem seu próprio modelo de "Cliente" e "Produto":
// Contexto Catálogo
Cliente {
id: String
preferencias: List<Categoria>
historicoVisualizacao: List<Produto>
}
Produto {
sku: String
nome: String
preco: Decimal
categorias: List<Categoria>
estoque: Int
}
// Contexto Pedidos
Cliente {
id: String
enderecoEntrega: Endereco
pedidosAnteriores: List<Pedido>
}
Produto {
sku: String
quantidade: Int
precoUnitario: Decimal
}
Mapa de Contexto final:
Catálogo ──Evento: ProdutoAdicionado──► Carrinho ──Evento: PedidoConfirmado──► Pedidos
│ │
│ ACL │
▼ ▼
Pagamento ◄──Evento: CobrancaSolicitada─────────────────────────────── Pagamento
│
▼
Logística ◄──Evento: PagamentoConfirmado
A ACL entre Pagamento e Logística traduz o modelo de "Endereço de Cobrança" para "Endereço de Entrega", com regras diferentes de validação.
7. Manutenção e Evolução dos Contextos ao Longo do Tempo
Contextos precisam ser revisitados. Quando o negócio adiciona "Assinatura Mensal" ao e-commerce, o contexto de Pagamento pode precisar de um split: um contexto para "Pagamento Avulso" e outro para "Assinaturas".
Monitoramento de acoplamento é essencial. Se chamadas diretas entre contextos aumentam, ou se eventos carregam dados de outros contextos, há vazamento. Métricas como "número de adapters compartilhados" ou "tamanho médio dos eventos" ajudam a detectar.
Documentação viva mantém o Context Map atualizado. Ferramentas como Context Mapper ou diagramas versionados no repositório garantem que o mapa reflita a realidade. Toda mudança de fronteira deve atualizar o mapa.
Checklist de revisão semestral de contextos:
1. A linguagem ubíqua ainda é consistente dentro do contexto?
2. Novos fluxos de negócio exigem novos contextos?
3. Há acoplamento excessivo entre contextos existentes?
4. O tamanho do contexto ainda é adequado?
5. As integrações ainda seguem os padrões definidos?
A definição correta de Bounded Contexts não é um exercício único. É um processo contínuo de descoberta e refinamento, onde o alinhamento com o domínio de negócio dita as fronteiras, e a arquitetura segue essas fronteiras com disciplina.
Referências
- Domain-Driven Design: Tackling Complexity in the Heart of Software (Eric Evans) — Livro fundamental que introduziu o conceito de Bounded Context e seus padrões de integração.
- Vaughn Vernon - Implementing Domain-Driven Design — Guia prático com exemplos detalhados de implementação de Bounded Contexts em Java e C#.
- Event Storming: A Practical Guide (Alberto Brandolini) — Técnica de modelagem colaborativa que revela Bounded Contexts através de eventos de domínio.
- Martin Fowler - BoundedContext — Artigo clássico que explica o conceito com exemplos claros do mundo real.
- Context Mapper: Ferramenta para Modelagem de DDD — Ferramenta open source que gera Context Maps e código a partir de modelos de domínio.
- DDD Crew - Bounded Context Design Canvas — Template colaborativo para definir e documentar Bounded Contexts em workshops.