DDD
- Integrando Bounded Contexts
![]() |
Neste artigo vou apresentar os padrões de relacionamentos do DDD usados para definir os relacionamentos e dependências entre os Bounded Context para gerar o Context Map. |
Fazer a integração
dos Bounded Contexts (BCs) é um dos pontos mais delicados do
Domain-Driven Design (DDD), porque cada contexto é um “mundo fechado”
com seu próprio modelo e linguagem ubíqua. Integrá-los exige cuidado para não
criar um grande acoplamento entre eles.

Existem diferentes padrões de integração de Contextos Delimitados, descritos por Eric Evans e também detalhados por Vaughn Vernon no Implementing Domain-Driven Design.
Os Bounded contexts ou Contextos Delimitados definem um limite lógico de um domínio de negócio onde uma Linguagem Ubíqua consistente é usada. Embora os bounded contexts evoluam independentemente, eles ainda precisam colaborar para criar um sistema que gere valor para as empresas.
Antes de
apresentar os padrões de relacionamentos temos que entender os alguns termos
usados na nomenclatura:
Upstream/Downstream: (descrevem
a direção da dependência)
- Quem fornece uma linguagem/contrato é Upstream;
- Quem consome é Downstream;
- Mudanças no Upstream afetam o Downstream;
- Upstream é o contexto “Fornecedor" (que dita as regras)
- Downstream é o
contexto “Consumidor" (que se adapta).
Customer-Supplier :
- Downstream (Customer ou Consumidor)
- Upstream (Supplier ou Fornecedor)
Para os exemplos usados no artigo vamos considerar um sistema de vendas onde um Cliente navega por um Catálogo , faz um Pedido e recebe a entrega. Temos assim 3 Bounded Contexts :
1- Gestão de Pedidos - Com Pedido, ItemPedido
(PrecoUnitario), Pagamento, EnderecoEntrega (snapshot)
2- Gestão de Catálogo - Produto (Preco) e Categoria
3- Gestão de Clientes - Cliente, Endereco
Assim, o DDD define vários padrões para descrever como os Bounded Contexts se conectam. Esses padrões são representados no mapa e ajudam a classificar as relações. Vejamos a seguir a definição para cada um destes padrões.
Partnership (Parceria)
Neste modelo, a integração entre os bounded contexts é feita na hora. Se uma
equipe decidir modificar sua API, ela informa as outras equipes, que farão as
alterações necessárias. Sem drama ou complicações. Nesse cenário, nenhuma equipe
dita a linguagem ubíqua usada; elas cooperam e encontram a solução mais
adequada. As equipes também trabalham juntas para resolver rapidamente qualquer
conflito de integração que possa surgir.
Este padrão funciona melhor para
equipes maduras que se comunicam bem. Por outro lado, equipes distribuídas em
grandes áreas geográficas podem achar essa abordagem desafiadora, pois a
comunicação e a sincronização são mais complexas e demoradas.
Exemplo: Relação entre BC Pedidos e Pagamentos
No nosso
sistema de vendas, uma simulação de parceria ocorreria se os BCs de Pedidos e
Pagamento (se fossem separados) fossem desenvolvidos por equipes que
compartilham o mesmo código, cronograma e metas.
Por exemplo, a classe
Pagamento seria gerenciada de forma mútua, com as duas equipes se reunindo
constantemente para garantir que as alterações de uma não quebrem a outra. É uma
parceria de alto risco, mas também de alta coordenação. É o padrão mais "forte"
de relacionamento.
Shared Kernel
(Núcleo Compartilhado)
Na vida real, há muitas situações
em que alguns modelos são usados em vários bounded contexts. Quando isso
acontece, você tem duas opções: duplicação ou compartilhamento.
Usando o
modelo de compartilhamento, você cria componentes que são utilizados por
múltiplos bounded contexts. Quando o núcleo compartilhado é modificado, isso
afeta todos os bounded contexts que dependem dele, criando um forte acoplamento.
Há algumas coisas que você pode fazer para mitigar essa desvantagem:
- Mantenha o núcleo compartilhado pequeno, o menor possível.
- Idealmente,
apenas as estruturas de dados compartilhadas entre os bounded contexts devem ser
mantidas no núcleo compartilhado.
- Use a Integração Contínua — cada vez que
o núcleo compartilhado muda, os bounded contexts também precisam ser atualizados
e verificados quanto à conformidade.
Embora este modelo crie acoplamento,
ainda é uma ferramenta valiosa, especialmente quando o custo da duplicação
excede o custo da integração. Se você observar que o núcleo compartilhado muda
com frequência e precisa gerenciar problemas de integração, talvez seja hora de
considerar a duplicação.
Exemplo: Relação entre BC Pedidos e Clientes
Imagine que
Pedidos e Clientes precisam trabalhar com a mesma definição de ClienteId.
O
contexto de Pedidos precisa saber qual cliente fez um pedido.
O contexto de
Clientes é quem mantém os dados detalhados do cliente.
As duas equipes
decidem compartilhar uma classe comum contendo a definição de um ClienteId que
seria compartilhada entre ambas.
Isso, no entanto, é um risco. Se uma
equipe precisar mudar a forma como o ClienteId é tratado, ela pode
acidentalmente quebrar a outra equipe, o que torna esse padrão de alta
manutenção e risco.
Supplier-Consumer
(Fornecedor-Consumidor)
Há muitas
situações em que um bounded context fornece dados ou serviços a outro. Chamamos
o contexto que fornece dados/serviços de fornecedor ou bounded context upstream.
Aquele que depende desses dados/serviços é chamado de consumidor ou bounded
context downstream. Quando isso acontece, um dos bounded contexts geralmente é
mais importante da perspectiva de negócio.
Se o fornecedor for mais
importante (sua equipe tiver mais poder de decisão), a equipe que o possui
ditará o contrato de integração. É uma abordagem de "aceitar ou deixar". O
bounded context do fornecedor define o contrato de integração, e os consumidores
devem se adaptar. Nesse cenário, você pode escolher o modelo Conformist ou o
modelo ACL.
Exemplo: Imaginem que o BC de Pedidos (Customer/Cliente)
precisa de dados do BC de Clientes ( Supplier/Fornecedor).
Nessa
relação, a equipe do BC Pedidos negocia com a equipe de Clientes para que o que
eles precisam seja fornecido.
É uma relação de dependência saudável,
onde o Supplier/Fornecedor – Clientes - se compromete a atender as necessidades
do Customer/Cliente - Pedidos
Conformist (Conformista)
Se a equipe downstream puder aceitar e se adaptar ao modelo da equipe
upstream, seu relacionamento é chamado de conformista.
Você pode se
perguntar por que uma equipe abriria mão do controle e da autonomia para outra?
Se o contrato de integração fornecido pela equipe upstream aderir a um padrão
reconhecido pela indústria ou se for bom o suficiente para a equipe downstream,
essa pode ser uma escolha pragmática. O ego é algo perigoso no desenvolvimento
de software; você precisa saber quando deixá-lo de lado.
Exemplo: Neste caso, imagine que o nosso BC de Pedidos precisa
dos dados de produtos do BC de Catálogo.
A equipe de Catálogo é a 'dona'
daquele modelo, e ele é muito grande e bem definido.
A equipe de
Pedidos(Consumidor), em vez de negociar ou tentar mudar o modelo de Catálogo
(Fornecedor) , simplesmente decide se Conformar a ele.
O Contexto de
Pedidos aceita a Linguagem Ubíqua e a estrutura do Catálogo, se adaptando. É uma
escolha pragmática.
Anti-Corruption
Layer (ACL - Camada Anticorrupção)
Quando o bounded
context downstream é um subdomínio principal (vital para o negócio), a
abordagem conformista não funciona, mesmo que a balança de poder ainda penda
para a equipe upstream.
Nesse caso, a equipe downstream se recusa a se
conformar. Ela não pode ditar o contrato de integração, mas pode se desacoplar
dele. Ela pode traduzir o contrato de integração criado pela equipe fornecedora
em algo significativo e válido para ela. Essa camada de abstração protege seu
bounded context da interferência externa e permite que seu modelo de domínio
evolua sem depender de fatores externos.
Simplificando, uma camada
anticorrupção (ACL) é apenas um intermediário que fica entre o contrato de
integração externo e o modelo de domínio interno do bounded context do
consumidor. Seu propósito é proteger a lógica de negócio do ruído externo e
manter as coisas válidas e consistentes.
Exemplo: A relação entre o BC de Pedidos e o Gateway de
Pagamento
O Gateway de Pagamento é um sistema externo que não
controlamos. Ele tem um modelo de dados próprio, com termos como "transaction
ID", "auth code" e "response code".
Para não poluir nosso modelo de
domínio de Pedidos, criamos uma ACL que traduz esses conceitos para os nossos
próprios, como Pagamento e StatusPagamento. Isso nos permite trocar o Gateway de
Pagamento no futuro sem precisar refatorar todo o nosso BC de Pedidos.
Open-Host Service (OHS - Serviço de Host
Aberto)
Este modelo de integração
aborda casos em que o equilíbrio de poder favorece os consumidores. O fornecedor
desacopla sua lógica de implementação de sua API pública para melhor atender aos
consumidores. É o oposto da situação do ACL.
A interface pública do
fornecedor não precisa se conformar com sua linguagem ubíqua. Em vez disso, o
contrato de integração é construído para servir melhor os bounded contexts
downstream.
É comum que serviços upstream exponham múltiplas versões do
contrato de integração. Isso permite que os consumidores escolham o contrato que
melhor se adapta às suas necessidades e migrem gradualmente para versões mais
recentes.
Exemplo: Relação entre BC Catálogo e o BC Pedidos , Estoque e
Marketing
O BC de Catálogo é a fonte da verdade sobre todos os produtos
da nossa empresa. Ele não serve apenas o BC de Pedidos, mas também pode servir
outros sistemas, como um sistema de Gerenciamento de Estoque ou um aplicativo de
visualização para a equipe de Marketing.
Em vez de a equipe de Catálogo
negociar três APIs diferentes (uma para Pedidos, uma para Estoque e uma para
Marketing), ela decide implementar o OHS e cria uma única API pública e bem
documentada que permite a todos os outros BCs consultar informações de produt
Published Language (Linguagem Publicada):
É uma estratégia onde um BC Upstream se compromete a expor um formato
de dados ou um protocolo de comunicação estável e bem documentado. Isso facilita
a integração para múltiplos BCs Downstream, que podem consumir essa linguagem
com confiança
Exemplo: Relação entre BC Clientes e BC
Pedidos
O BC de Clientes decide publicar um conjunto de eventos de
domínio, como ClienteCriado ou
ClienteEnderecoAtualizado, usando um formato de dados estável (por
exemplo, um schema JSON versionado).
O BC de Pedidos pode, então,
se inscrever nesses eventos para manter seus dados de endereço de entrega
atualizados. Isso permite que múltiplos BCs se integrem ao BC Clientes sem a
necessidade de negociações ponto a ponto.
O BC Clientes é a fonte da
verdade e o provedor de uma "linguagem" confiável para todos.
Separate Ways (Caminhos Separados)
Às vezes, o custo de integrar bounded contexts excede o tempo que
leva para duplicar componentes. Se for esse o caso, a duplicação é uma escolha
pragmática. Duplicar componentes, mesmo que possam ser os mesmos para múltiplos
bounded contexts, também é viável se a comunicação eficaz entre as equipes não
for possível. Usando essa abordagem, as equipes podem evoluir seus bounded
contexts de forma independente.
Exemplo: Relação entre BC Pedidos e BC RH
.
Imagine que a
empresa tem um sistema de RH para gerenciar a folha de pagamento e os benefícios
dos funcionários. Esse sistema tem seu próprio domínio de "Funcionários"
e "Salários". A equipe de Vendas (e nosso BC de Pedidos) não precisa de
nenhuma informação desse sistema.
O modelo de funcionário do RH é
completamente irrelevante para o nosso sistema de vendas. Portanto, o
relacionamento entre o BC de Pedidos e o BC de RH pode ser definido como
Separate Ways pois eles operam em domínios completamente separados e não há
necessidade de comunicação.
Conclusão
Espero ter
convencido você de que não existe um modelo de integração certo ou errado entre
os bounded contexts. Cada abordagem tem prós e contras e é adequada para um
cenário específico.
Também estou ciente de que minha apresentação desses
modelos de integração não é um aprofundamento, mas um bom ponto de partida,
especialmente se você é um novo praticante de DDD.
Cabe destacar que a integração de Bounded Contexts não é sobre tecnologia, mas sobre relacionamento entre equipes e domínios. A tecnologia (eventos, APIs, ACL) vem depois, para implementar o padrão de relacionamento escolhido.
No meu canal no youtube estou publicando uma série sobre o DDD.
E estamos conversados...
"Bendito o Deus e Pai de nosso Senhor Jesus Cristo, o qual nos abençoou com
todas as bênçãos espirituais nos lugares celestiais em Cristo;"
Efésios 1:3
Referências:
NET - Unit of Work - Padrão Unidade de ...