Entendendo Domain-Driven Design
Tags: ddd, strategicpatterns
Published: 2020-03-13 01:24:22

---
title: Entendendo Domain-Driven Design
published: true
tags: ddd, strategic patterns
series: ddd
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/4srgyd0z4j6707etn5sd.jpg
---

Um dos principais conceitos que aprendi e mudou a forma como escrevo software foi Domain-Driven Design. Ele me trouxe outra visão de como abordar problemas, como criar soluções mais alinhadas com a área de negócio e com um melhor design. Neste artigo irei revisá-lo e compartilhar o meu conhecimento sobre os seus conceitos.

# Overview

## O que é, onde aplicar e benefícios

Domain-Driven Design (DDD) é uma metodologia de desenvolvimento de software. Originou-se em 2003 por Eric Evans em seu conhecido livro _Domain-Driven Design: Tackling Complexity in the Heart of Software_.

Ele é, acima de tudo, uma metodologia que habilita o desenvolvimento de software de alta complexidade de negócio de maneira efetiva. Através da sua filosofia, práticas e patterns, DDD nos permite gerar valor, reduzir custos e facilitar a evolução de aplicações que poderiam facilmente terminar de maneira trágica. Ele nos apresenta maneiras de modelar essas aplicações de tal forma que fique muito próxima à área de problema que estamos resolvendo, isso habilita a equipe técnica a desenvolver tais sistemas de maneira consistente e saudável.

## O que não é, onde evitar e malefícios

Devemos ter ciência que quando falamos exclusivamente de arquitetura de software ou design patterns (Repositories, Entities, Services, Factories, etc) não estamos falando sobre DDD necessariamente. A parte prática com _Building Blocks_ e Design de Arquitetura são importantes também, sem dúvida, porém elas não se sustentam sozinhas e não são o ponto central do DDD, estão lá simplesmente para nos auxiliar. Podemos ter um sistema que implementa todos os design patterns sugeridos, mas não atende o negócio. Por outro lado podemos ter um design mais simplista, mas que esteja totalmente alinhado ao domínio. DDD não exige que nenhum design pattern seja implementado, a única coisa exigida é que nosso domínio esteja isolado do restante da aplicação para que possamos focar nas regras de negócio e não misturar esses conceitos com problemas técnicos, além disso, DDD não está restrito somente ao paradigma de programação orientada a objetos. Concluímos então que **não existe receita de bolo ou template padrão para implementá-lo**.

Não devemos considerar DDD em aplicações onde não há complexidade de negócio. Tais aplicações não iriam se beneficiar do que nos é apresentado. DDD somente traria complexidade desnecessária e dificuldade em sua execução. Também devemos evitar seu uso onde não temos pessoas qualificadas para aplicar o conhecimento e as práticas requeridas, nem onde não temos contato direto com pessoas de negócio.

# Problem Space

Quando falamos de _Problem Space_ estamos nos referindo a área de negócio na qual o cliente está inserido e o que nosso software pretende resolver. Aqui aprendemos a gerenciar o problema e a destila-lo a fim de reduzir a sua complexidade.

![Problem Space](https://dev-to-uploads.s3.amazonaws.com/i/q9aa24sp7rs72eakd6a3.png)

## Domain

O domínio é realidade do negócio, se refere a área de conhecimento e atividade na qual a organização e as pessoas estão inseridas. Envolve todas as regras, comportamentos, processos e entendimentos que lá habitam. Domínio é onde as pessoas de negócio vivem e na qual nós, desenvolvedores, não temos interferência.

![Domain](https://dev-to-uploads.s3.amazonaws.com/i/oiw26yf4vqmj6irjrxs9.png)

## Subdomains

![Subdomains](https://dev-to-uploads.s3.amazonaws.com/i/h8vbu3rec37s8091pig0.png)

Subdomain se dá no processo de decompor o nosso domínio em três categorias:

### Core

É o que gera maior valor, o motivo da organização existir, o diferencial entre os seus concorrentes, é onde os 20% geram 80% dos resultados. O _Core Domain_ é onde se deve gastar maior parte do tempo e recursos. Onde os desenvolvedores mais experientes devem trabalhar e onde devemos criar o design mais robusto.

Em um projeto de e-commerce, por exemplo, o _Core Domain_ pode ser **Sales**. Isso não quer dizer que todos os e-commerces possuem o mesmo Core. Se um e-commerce se propõe a fazer entregas em até 24 horas, o _Core Domain_ será **Shipping**, se outro e-commerce se destaca por ser o mais barato entre a concorrência, seu _Core Domain_ será **Pricing**, então tenha em mente que os _subdomains_ serão diferentes de empresa para empresa. Nosso papel aqui é mapear a realidade do negócio existente, não tentar encaixar modelos preconcebidos nele.

### Supporting

Ele é o que habilita o _Core Domain_ exercer seu papel, sem ele a organização não iria funcionar e ele precisa de um certo nível de customização, porém não possui vantagem competitiva. Ele é importante, mas não devemos gastar mais esforços do que o necessário. Aqui feito é bem feito!

Olhando nosso exemplo, os items em amarelo são áreas que sem elas o sistema não iria funcionar. Não conseguimos vender um produto sem um meio de pagamento, sem estoque no armazém, sem uma boa logística, etc. Todas essas áreas servem de auxílio para que o _Core_ funcione adequadamente.

### Generic

Não são de maior preocupação e não possui relação exclusiva com nosso _Core Domain_. Caso seja criada uma solução interna devemos fazer com que ela simplesmente funcione, nada mais, provavelmente delegar para desenvolvedores menos experientes. Outra alternativa seria contratar uma solução de terceiros.

As nossas caixinhas em vermelho representam o que é genérico para nós. Como o nosso foco é a venda temos que deixar algumas coisas de lado. Aceitamos que existem soluções de recomendações muito melhores do que podemos criar, podemos contratar uma dessas soluções através de SaaS. Também não é nosso foco customizar a experiência de cada cliente, só precisamos de alguns dados básicos - uma API com alguns métodos CRUD resolverá o nosso problema.

# Solution Space

_Solution Space_ se refere ao **como** iremos resolver o _Problem Space_. Envolve práticas e patterns a fim de criar uma solução efetiva.

![Solution Space](https://dev-to-uploads.s3.amazonaws.com/i/0yjugtht71246mklkqrv.png)

## Domain Models

O que é exatamente um "Modelo"? Segundo o [Dicionário Criativo](https://dicionariocriativo.com.br/significado/modelo) temos a seguinte definição:

> Representação abstrata de um fenômeno, capaz de captar as características formais ou funcionais do objeto de estudo.

Podemos entender então que um modelo nada mais é do que uma visão/imagem que temos de um conceito. Trazendo para nosso cenário seria criar abstrações que representam nosso domínio em um determinado contexto. Ao fazer isso poderemos discutir com mais propriedade os termos e obter das pessoas de negócio conceitos subentendidos. Ele é fruto da colaboração. Sua maior utilidade se dá no entendimento compartilhado das regras e processos. Em resumo, _Domain Model_ é a implementação de uma solução para o _Domain_.

![Domain Model](https://dev-to-uploads.s3.amazonaws.com/i/adti64xjhobxtxt5kao2.png)

### Analysis Model

Durante as reuniões irão surgir ideias que podemos traduzir para diagramas (UML), onde desenvolvedores e pessoas de negócio possam entender e colaborar sobre os processos discutidos, estes são conhecidos como _analysis model_. Eles não são focados no aspecto técnico e não devem ter detalhes de implementação.

### Code Model

_Code Model_ é a implementação dos _Analysis Model_. Eles são criados utilizando os conceitos aprendidos no modelo anterior. Todo o _Code Model_ deve servir apenas e exclusivamente ao nosso domínio, não devemos utilizar aqui nomes de patterns como Repository, Factory, Service, Manager, etc - isso somente iria gerar ruído na comunicação. Ao invés disso devemos utilizar a _Ubiquitous Language_ na implementação.

### Model-Driven Design

É o processo de sincronização entre o _analysis model_ com _code model_. Em um cenário ideal ambos são traduzíveis de 1:1, para isso precisamos de uma implementação livre de detalhes técnicos e um _analysis model_ que não seja tão abstrato. Durante esse processo precisamos analisar se os jargões foram modelados de forma explícita para garantir que os mesmo termos usados nas discussões estejam na implementação. Durante a implementação do _code model_ a equipe técnica poderá identificar falhas de conceitos e regras, isso permite trazer novas reflexões durante reuniões e refinar o processo de maneira iterativa, o que levará na atualização do _analysis model_ inicial. Desta forma isso gera um processo de melhoria contínua na qual _analysis model_ e _code model_ se retroalimentam.

## Strategic Patterns

Os _Strategic Patterns_ nos ajudam a destilar o _Problem Space_ e arquitetar a aplicação guiada pelo domínio.

### Ubiquitous Language

Entende-se como onipresente aquilo que está em todos os lugares. Para conseguirmos ter uma comunicação efetiva com pessoas de domínio é essencial falarmos a mesma língua. Ubiquitous Language é criada entre a colaboração da equipe técnica e pessoas de negócio, ela deve ser falada e escrita durante conversas, desenhos e implementações. Ela é dividida entre os _Bounded Context_. Esta linguagem é um artefato vivo, terá evoluções e refinamentos. É importante deixá-la de forma explícita para que todos entendam os seus termos, talvez manter um glossário ou outra documentação em que todos tenham acesso.

#### Inglês ou Português?

É prática comum, até recomendável, que nosso código seja escrito em inglês, porém isso entra em conflito com a _Ubiquitous Language_. Quando estamos trabalhando com domínio complexo devemos deixar nosso código com o idioma falado para não perder a relação com as pessoas de negócio.

### Bounded Context

Após identificar nossos _subdomains_ e ter uma linguagem compartilhada com pessoas de negócio iremos perceber que os termos utilizados tendem a ter mais de um significado para pessoas/processos/áreas diferentes. Um **Product** para o contexto **Sales** significa uma coisa e para o contexto **Shipping** outra. Ao invés de tentar criar um modelo único, aka [God Object](https://en.wikipedia.org/wiki/God_object), a ideia do _Bounded Context_ é criar divisões entre essa linguagem, onde cada um tem o seu modelo que representa uma abstração do problema, isso impede que os conceitos se misturem e que nosso software acabe se tornando um [BBoM](https://thedomaindrivendesign.io/big-ball-of-mud/).

![Contexts](https://dev-to-uploads.s3.amazonaws.com/i/ij5our7tyg51k1czrlfk.png)

Um _Subdomain_ é algo abstrato/conceitual no qual podemos apenas discutir. Um _Bounded Context_, por outro lado, é um artefato que traduz esses conceitos para o software. Em um mundo perfeito todos nossos Subdomains seriam traduzíveis para um _Bounded Context_ correspondente, infelizmente a realidade pode não ser tão generosa em alguns casos. Podemos ter N _Bounded Contexts_ para satisfazer um _Subdomain_, o que ira guiar a divisão neste caso é a _Ubiqutious Language_. Devemos ficar atentos somente quando um _Bounded Context_ tende a atender mais de um _Subdomain_, isso fere o [_Single Responsibility Principle_](https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html), pois um _B.C._ terá mais de um motivo para ser alterado.

Seguindo os _Subdomains_ propostos, vamos pensar na organização do projeto. Dentro de __Customer__ podemos ter um _Bounded Context_ chamado __User__ que irá tratar do Nome, Endereços, Formas de Pagamento, Avatar, etc; e outro _Bounded Context_ de __Account__ contendo E-mail, Password, Roles, Claims, etc. E em __Sales__ temos __Orders__, __Pricing__ e __ShoppingCart__, para os demais acredito que um __Bounded Context__ para cada irá servir.

```
App
  ├── Billing
  ├── Catalog
  ├── Customers
  │ ├── Account
  │ └── User
  ├── Sales
  │ ├── Orders
  │ ├── Pricing
  │ └── ShoppingCart
  ├── Shipping
  └── Warehouse
```

Tome cuidado para não dividir os _Bounded Contexts_ pelos dados e reuso, infelizmente nos como desenvolvedores temos esse hábito. É um erro pensar em _Bounded Context_ desta forma, isso levará a inconsistências no modelo e ao longo prazo pode acabar comprometendo a evolução do sistema. _Bounded Context_ é meio difícil de entender no começo, estude bem antes de implementar!

> Bounded Context geralmente é recomendado como a primeira linha de divisão em aplicações microservices.

### Context Maps

Dado o cenário onde você já identificou e separou os contextos da sua aplicação, agora é hora de entender como eles se comunicam. _Context Maps_ nos ajudam a entender melhor a barreira entre os _Bounded Context_ e visualizar como eles interagem entre si. Há alguns patterns para a comunicação entre os contextos de maneira eficiente, porém irie comentar apenas dos dois principais:

#### SharedKernel

Haverá cenários em que teremos, dentro de um _Subdomain_, modelos e regras que se aplicam em mais de um _Bounded Context_, a fim de evitar duplicidade e não criamos acoplamento podemos ter uma camada que contém o que é comum entre os _Bounded Contexts_ envolvidos.

![SharedKernel](https://dev-to-uploads.s3.amazonaws.com/i/9g20nv6lzmq5v25h2axw.png)

Podemos exemplificar criando uma camada **Core** em **Sales**, ela pode ter o modelo base de _Product_.

```
App/Sales
├── Core
├── Orders
├── Pricing
└── ShoppingCart
```

#### Anticorruption Layer

Quando estamos criando um _Bounded Context_ seguindo a _Ubiquios Language_ não queremos contaminá-lo com models externas, ou ainda pior, criar acoplamento com partes legadas do sistema. Neste cenário podemos criar uma camada intermediária entre o _Bounded Context_ e suas dependências. Através de uma interface definida nele, podemos implementar nesta nova camada e traduzir o retorno de chamadas de outros _Bounded Contexts_ para o nosso. Desta forma conseguimos utilizar recursos externos de forma transparente e sem acoplamento.

![AntiCorruption-Layer](https://dev-to-uploads.s3.amazonaws.com/i/42fcjnnuaxe6cpv67ovg.png)

Em **Billing** temos uma camada chamada _Integration_ que será responsável por obter dados de _Customer_, que está dentro do Bounded Context **User**. Ela também será responsável pela comunicação com a API de pagamentos externa.

```
App/Billing
├── src
│ ├── Domain
│ └── Integration
└── tests
```

# Highlights

## Colaboração

É fundamental para o entendimento do domínio que desenvolvedores e pessoas de negócio trabalhem juntas. Somente com a colaboração e entrevistas constantes podemos extrair os conceitos mais complexos e entender fluxos de negócio de maneira esmiuçada.

## Foque no Core-Business

Nem toda parte da nossa aplicação tem a mesma relevância. DDD nos permite enxergar com mais clareza o problema que estamos resolvendo e entendendo melhor o que gera valor, devemos então direcionar nossos esforços para os processos que realmente impactam o negócio, aumentando assim a chance de sucesso do nosso software.

## Evolução constante

Não importa o quão experiente você seja, não há como mapear e ter um design perfeito de início. O processo para destilar o domínio e criar modelos que o representam é iterativo. Além do que conceitos podem e vão mudar, novas necessidades irão surgir e precisamos ficar atentos para alinhar nosso design com o negócio. Podemos ter um sistema 1:1 no começo, porém se não darmos continuidade nas práticas e processos do DDD em alguns meses estaremos defasados. DDD necessita de manutenção constante!

# Conclusão

Neste artigo tentei ilustrar com exemplos didáticos o que seria a abordagem do DDD em um software que pretende resolver um domínio complexo. Tenha em mente que devido a sua natureza, nenhum artigo, livro ou curso irá te passar a experiência real do DDD, pois isso envolve trabalhar com pessoas de negócio, distilar e refinar o domínio, colaboração, entre outros. Aprender sobre DDD não é como aprender uma linguagem ou framework novo, envolve muita soft-skill e recursos do dia-a-dia. Os problemas de negócio aqui apresentados são pensados para ilustrar possíveis situações que podem acontecer, porém, somente em um domínio real você irá notar as nuances do DDD e o absorver com mais clareza. Recomendo continuar estudando e, caso tenha a oportunidade, começar a pratica-lo com outros desenvolvedores mais experientes.

Irei falar mais sobre DDD nos próximos artigos onde abordarei os **Tactical Patterns** e **Architecture Patterns**.

# Referências

- [Patterns, Principles, and Practices of Domain-Driven Design](https://www.amazon.com.br/dp/B00XLYUA0W/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
- [Domain-Driven Design: Tackling Complexity in the Heart of Software](https://www.amazon.com.br/dp/B00794TAUG/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
- [The Domain Driven Design](https://thedomaindrivendesign.io/)
- [DDD (Domain Driven Design) aplicado ao e-commerce - Nelson Senna](https://www.youtube.com/watch?v=TOtA40H2MUs)
- [Strategic Domain-Driven Design](https://vaadin.com/learn/tutorials/ddd/strategic_domain_driven_design)