Domain-Driven Design, Os building blocks | PARTE 3: Domain, Subdomains e Bounded Contexts

Maicon Heck
8 min readMar 18, 2021

--

👉 This article is also available in English on my blog

Na segunda parte dessa série de artigos sobre Domain-Driven Design, começamos a modelar o domínio de um sistema de automação de marketing. Criamos nossa primeira Entity e Value Objects, e vimos 4 erros comuns na criação destes, e como resolvê-los.

Criamos um código orientado a objetos, amplamente testado, e mais importante, refletindo a linguagem do domínio.

No final, acredito que ficou claro o motivo pelo qual é fundamental esquecer o modelo ER enquanto estivemos modelando o domínio, e a consequência de não fazê-lo.

Se você não leu, comece por lá, pois esse artigo é uma continuação do anterior:

Domain-Driven Design, Os building blocks | Parte 02: Entities e Value Objects

Objetos de valor (Value Objects), são objetos que representam um aspecto descritivo do domínio, mas ao contrário das entidades eles não têm identidade…

⚠️ Eu já falei sobre a diferença entre Domínio e Modelo de Domínio aqui. Se você não lembra, releia essa parte agora, porque isso deve estar claro para prosseguirmos com o entendimento dos próximos itens.

Hoje demonstrarei mais dois blocos de construção fundamentais do DDD: Subdomínios (Subdomains) e Contextos Delimitados (Bounded Contexts)

Subdomains

😕 Um ponto que muitas vezes gera confusão, e consequentemente um erro grande de modelagem, é achar que o Modelo de Domínio (Domain Model) deve ser um modelo único, que contemple todo o Domínio da organização. ✔️ Mas na verdade, quando estamos usando DDD, fazemos exatamente o contrário, ou seja, pensamos em uma única área do negócio de cada vez.

VERNON (2013)

Dessa forma, para organizar e entender o Domínio no qual estamos inseridos, devemos decompô-lo em Subdomínios, que geralmente refletem a estrutura organizacional do negócio. Por exemplo, vendas, estoque, remessa, contabilidade, etc.

Sabemos que o Domínio (Domain) corresponde ao universo inteiro do negócio, ou seja, o Domínio é o que uma organização faz, e o mundo em que ela o faz. Por outro lado, quando queremos nos referir a apenas uma área do negócio, a chamamos de Subdomínio (Subdomain).

Core Domain

É o Subdomínio mais importante, é aquele que justifica a existência da organização. Por exemplo, se a organização é uma fábrica de calçados, a área mais importante é a produção e venda de calçados. Esse Subdomínio que representa o coração do negócio, chama-se Core Domain. 💰

Generic Subdomains

Além do Core Domain, sabemos que existem outras áreas necessárias que fazem com que uma organização funcione. Essas áreas servem para apoiar o Core Domain na sua função. No caso da nossa fábrica de calçados, é necessário uma logística para distribuir os produtos, um RH para contratar funcionários capacitados, uma contabilidade para gerir o patrimônio, entre outras áreas. Dentro do DDD, chamamos essas áreas de Subdomínios genéricos.

Perceba que o Core Domain depende do tipo da organização. Se ao invés de uma fábrica de calçados, nossa organização fosse uma empresa de RH, o Core Domain possivelmente seria o R&S.

Porém, isso são apenas exemplos. Na vida real, tome cuidado para não fazer pressupostos antes de conhecer bem o Domínio! Se a fábrica de calçados do nosso exemplo, possuir um método de entrega super eficiente, que lhe confere um diferencial competitivo, certamente o seu processo de entrega faz parte do seu Core Domain, pois trata-se de uma estratégia importante para o negócio. 🎯

🤔 Fui só eu ou você também pensou na Amazon agora?

Bounded Contexts

💡 Contextos Delimitados (Bounded Contexts) é um dos design patterns mais difíceis de ser entendido no DDD, mas certamente é um dos mais importantes (mais importante do que ele é a Linguagem Ubíqua, e você já vai entender porquê).

Por isso vamos, passo-a-passo, explicar o que é, onde está, e para que ele serve, nesse conjunto de peças que compõem o DDD.

No Domínio / Subdomínios estão os problemas que nós queremos resolver (lembre-se que para resolvê-los nós criamos Modelos de Domínio (Domain Models)).

E é aqui que entra o papel dos Contextos Delimitados (Bounded Contexts): Enquanto que os Subdomínios delimitam o Domínio, os Contextos Delimitados delimitam os Modelos de Domínio.

💡 Colocando de outra forma: Para modelarmos um Subdomínio, a fim de resolver um problema através do nosso software, é necessário que criemos um ou mais modelos desse Subdomínio. E para organizarmos esses modelos, de acordo com a sua Linguagem Ubíqua, usamos Contextos Delimitados.

Portanto, os Subdomínios estão no campo do problema, e os Contextos Delimitados no campo da solução.

Se for necessário, podemos ter mais de um Contexto Delimitado para um Subdomínio (que é o que ocorre no nosso Marketing Subdomain):

Domain, Marketing Subdomain e Bounded Contexts

E conforme o Vernon, “…é uma meta desejável alinhar subdomínios um a um com contextos limitados.”

Agora vejamos o modelo de domínio de um varejo on-line, que o Vernon usa para demonstrar o que ocorre quando o DDD não é aplicado corretamente, resultando em poucos Contextos Delimitados responsáveis por muitas funções de negócio:

Domínio de um varejo on-line — VERNON (2013)

Na figura acima temos dois Contextos Delimitados: e-Commerce e Inventory. Perceba que o Contexto Delimitado e-Commerce, contêm os Subdomínios Product Catalog, Orders, Invoicing e Shipping.

Esses Subdomínios estão interagindo entre sí, mas não há uma divisão clara entre eles — estão todos fundidos nesse Contexto Delimitado gigante chamado e-Commerce.

Por outro lado, o Contexto Delimitado Inventory contêm apenas um Subdomínio, que é uma meta desejável.

Obs.: External Forecasting é um sistema externo que está fora do modelo de domínio.

É por isso que a Linguagem Ubíqua é o mais importante do DDD. Pois se você não entendê-la logo no início da modelagem, vai modelar errado, pois não saberá quais são, nem o que contemplam os seus Contextos Delimitados.

Voltando ao nosso domínio de automação de marketing

Depois de analisar detalhadamente o problema junto com a especialista de domínio, eu percebi que o nosso modelo deveria ser dividido em dois Bounded Contexts: Capturar Leads Context e Executar Campanha Context:

Domain, Marketing Subdomain e Bounded Contexts

💡 Observação: Como vimos anteriormente, no domínio de uma organização existem vários subdomínios. Nesta imagem eu estou representando apenas o subdomínio de marketing (especificamente, automação de marketing), pois é com ele que estamos trabalhando agora. Lembre-se: “…pensamos em uma única área do negócio de cada vez”.

O círculo mais externo representa o Domínio completo. Dentro dele temos o Subdomínio de marketing, que possuí os Bounded Contexts: Capturar Leads Context e Executar Campanha Context. Estes, por sua vez, contém os modelos (Domain Models).

💡 Perceba o papel dos Bounded Contexts, criando uma fronteira conceitual que delimita o contexto da Linguagem Ubíqua (eu falei bastante sobre a linguagem ubíqua no aqui, se você não leu, confira agora).

Observe que existem conceitos diferentes entre eles (como Ações e Componentes), mas também existem conceitos compartilhados (como Leads). Porém, embora os dois Bounded Contexts compartilhem o conceito de Leads, eles tem dados e comportamentos diferentes entre si.

O agregado Leads é duplicado entre os Bounded Contexts, porque ele tem um significado diferente em cada um deles. É perfeitamente normal que façamos isso quando encontramos conceitos compartilhados, mas que tem significados (propriedades e métodos) diferentes.

Um erro bastante comum seria fazer o contrário. Ou seja, não dividir Leads, mantendo todas as propriedades e métodos na mesma classe, apesar deles não terem relação nenhuma.

Muitas vezes encontramos esse tipo de classe que, desprezando o Principio de Responsabilidade Única, visa contemplar todos os problemas do mundo, e se torna impossível de manter (code smell: God Class). 🤬😤

Muitas vezes esse tipo de classe acaba sendo movida para o Shared Kernel (vamos falar sobre ele ainda), na tentativa de deixar explicito a intenção de usá-la de forma comum entre outros Bounded Contexts. Mas quando você abre classes assim, pela quantidade de linhas e pela falta de uma interface pública bem definida, fica claro que ela deveria ter sido dividida, pois está com excesso de responsabilidade. 🤬😤

A imagem abaixo é uma representação desse problema:

Domain, Marketing Subdomain e Bounded Contexts (compartilhando erroneamente o Lead no Shared Kernel)

Perceba que nessa versão, Leads foi movido para o Shared Kernel, com a intenção de ser reutilizado entre os Bounded Contexts Capturar Leads Context e Executar Campanha Context. No entanto, como Leads tem uma linguagem diferente em cada um desses contextos, acabamos criando uma classe Lead com excesso de responsabilidades e que não reflete a linguagem do Subdomínio no qual está inserida. 💩

Ou seja, quando estamos usando Leads no contexto Executar Campanha Context há métodos e propriedades que não servem para nada (e que na verdade acabam estragando o design, pois nos obrigam a criar uma interface pública que contemple tudo).

Veja abaixo a classe Lead, conforme foi criada no artigo anterior. Ela está longe de estar finalizada, mas já serve bem para exemplificar o Capturar Leads Context:

A última versão da classe Lead (até agora)

Por outro lado, no Executar Campanha Context precisamos apenas do E-mail, do Nome, e dos Segmentos do Lead. Além disso, nesse contexto não podemos atualizar o Lead nem adicionar novos Segmentos a ele:

Lead em Executar Campanha Context

Vernon se refere a esse problema como Big Ball of Mud (a grande bola de lama). Que de fato, é um bom nome para descrever o resultado que se obtém desse tipo de modelagem all-in-one!

Big Ball of Mud

Conclusão

Você apreendeu que o Modelo de Domínio não é um modelo único, e compreendeu a importância de organizarmos o nosso Domínio em Subdomínios e Contextos Delimitados.

Acredito que ficou claro a diferença entre Domínio, Subdomínios e Contextos Delimitados, e para que serve cada um deles.

Dentro dos Subdomínios, você entendeu que o mais importante é o Core Domain.

E sobretudo, eu espero que você tenha percebido a importância crucial de investir tempo em descobrir e refinar a Linguagem Ubíqua, dado o papel fundamental que ela tem na modelagem.

E não se engane: Linguagem Ubíqua parece simples, mas nas aplicações complexas que temos que lidar no nosso dia-a-dia, somado ao fato de que temos que interagir com pessoas de diferentes áreas, que usam termos diferentes para se referir as mesmas coisas... é bastante trabalho.

Se você ficou com alguma dúvida, não deixe de perguntar usando a seção de comentários abaixo:

Referências

Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. 2004.

Vernon, Vaughn. Implementing Domain-Driven Design. 2013.

Maicon Heck
.NET Senior Developer | Software Craftsman | Domain-Driven Design practitioner

blog | github | linkedin | twitter

--

--

Maicon Heck

I'm a software crafter. Through DDD I crafted dozens of rich, extensible, testable, and long-lived business domain models.