Um pouco sobre Domain Driven Design
Thiago Henrique
Posted on June 13, 2021
Entender o Domain Driven Design a primeira vista parece ser confuso, principalmente quando você traz consigo alguns PRÉ-conceitos sobre tal tema. A meta desse post é tentar, ainda que de forma geral, visto que o assunto pode ser muito mais complexo do que parece, abrir o caminho para seu entendimento de forma eficiente.
Gostaria de começar dizendo que o DDD não é uma receita para desenvolver softwares em camadas e também não é um padrão arquitetural. O DDD é uma abordagem de modelagem de software que segue um conjunto de práticas com o objetivo de facilitar a implementação de regras complexas ou processos de negócios que tratamos como domínio.
Mesmo não sendo um padrão arquitetural, ele afeta como as decisões arquiteturais são tomadas. O DDD é muito mais sobre a forma de pensar, desenhar e desenvolver aplicações que tem como objetivo implementar o melhor design possível baseado em modelos que refletem a competência da organização.
Essa abordagem tem como precursor Eric Evans, autor do livro “Domain-Driven Design – Atacando as Complexidades no Coração do Software” (o livro azul) publicado em 2003. Evans mostra como um conjunto de best practices de desenvolvimento, boas estratégias de negócio e uma equipe alinhada podem ser benéficos para que um projeto com uma grande complexidade possa ter sucesso.
Outras grandes referências sobre o DDD são as obras de Vaughn Vernon que trazem uma leitura menos densa, usam de uma linguagem mais acessível e demonstram aplicações práticas sobre a abordagem. Ainda estou no processo de leitura, mas acredito que hoje ainda são o que há de mais completo sobre o tema.
Complexidade do Software = Complexidade do domínio x Complexidade técnica acidental
Com um pouco de vivência no processo de desenvolvimento de software é possível perceber que nem tudo sai como o esperado. O entendimento de um negócio é algo dinâmico e que precisa ser um processo contínuo. Dificilmente a primeira versão de uma especificação funcional é a que soluciona adequadamente o problema.
Lá trás, talvez o mais comum seria o arquiteto de software pensar em uma arquitetura robusta e demasiadamente detalhada para atender à necessidade do negócio especialmente quando a especificação é construída. Começando, por exemplo, pela camada de banco de dados, definição de componentes para atender a integrações com serviços externos como envio de e-mail, etc.
Porém o conhecimento do negócio possui necessidades que não conseguimos ver no começo. O projeto cresce. O entendimento do negócio cresce. As necessidades mudam.
As mudanças serão necessárias pois ao decorrer do tempo as necessidades do usuário mudam e uma aplicação criada para tal domínio precisa atendê-las e não as necessidades de meses atrás. Com isso, os desenvolvedores podem encontrar dificuldades em implementar as mudanças dentro de um padrão imposto inicialmente. Isso gera complexidade técnica acidental. O código muitas vezes fica mais complexo do que deveria porque precisa seguir certos padrões imposto anteriormente. À medida que o sistema vai crescendo, a complexidade técnica acidental fica maior do que a própria complexidade do negócio. O resultado disso é o que o DDD chama de Big Ball of Mud. O software fica tão complexo que dar manutenção e evolui-lo se torna uma dor de cabeça.
O DDD entra nessa história justamente para trazer a tona que o entendimento do domínio do negócio é um processo crescente, que necessita da cooperação e comunicação da equipe como um todo. Ao invés do modelo tradicional, em que a comunicação ocorre em apenas algumas etapas do projeto, temos um fluxo de comunicação contínua e colaborativa, por meio de uma única linguagem. O DDD nos instrui a começar mais simples e ir evoluindo a medida que o negócio também evolui.
Domínio
Uma palavra chave no DDD, inclusive já mencionei ela várias vezes até o momento, e importantíssima para que compreendamos suas diretrizes é entender o que representa o domínio.
Poderíamos defini-lo como tudo que compreende o software e faz com que ele funcione. O espaço problema que a equipe está inserida. O principal assunto do seu projeto.
E o processo de modelar o domínio é algo semelhante a um documentário sobre a vida de uma pessoa. Não se registra cada passo, cada acontecimento e detalhe em uma biografia, e sim nos pontos importantes para que a mensagem desejada seja bem compreendida. Da mesma forma, quando falamos em projetos de software, devemos colocar o esforço necessário no que a aplicação precisa para funcionar.
Para fazer uma analogia, podemos lembrar de um jogo bem conhecido, o Banco Imobiliário. Podemos imaginar que ele é um modelo de algo bem mais abrangente e complexo, o mercado imobiliário (domínio).
Design estratégico x Design tático
O DDD nos fornece o design estratégico e design tático como ferramentas para suportar as atividades de modelagem e design do domínio de uma aplicação. E para melhor compreendermos, trago uma definição feita pelo autor Vaughn Vernon:
"Design estratégico é como fazer o rascunho antes de entrar nos detalhes da implementação. Destaca o que é estrategicamente importante para o seu negócio, como dividir o trabalho por importância e como fazer integrações da melhor maneira."
O design estratégico é como esse rascunho, enquanto o design tático é implementação, o detalhamento. O autor ainda diz sobre design estratégico:
“DDD é primariamente sobre modelar uma linguagem ubíqua em contexto delimitado” — Vaughn Vernon
Contexto delimitado é uma barreira semântica onde todos os componentes do modelo terão um significado específico. Já a Linguagem Ubíqua fornece as palavras que existirá nesse contexto. Ubíqua porque ela vai estar implementada no código do software. Entrarei nos detalhes desses itens a seguir.
Os pilares do Design Estratégico
Linguagem Ubíqua
Quando se estuda DDD pode ficar até cansando em falar na linguagem ubíqua. Acontece que ela é essencial para fortalecer os laços entre os especialistas do negócio e o time de desenvolvimento.
Ao aplicá-la, termos estritamente técnicos são substituídos por termos que o usuário compreenda. Essa linguagem universal, como também é conhecida, fica mais próxima da área de negócio do que dos desenvolvedores e ao mesmo tempo que é utilizada entre todos os membros do time (incluindo os Domain Experts), também é implementada como código fonte. É essencial que a Linguagem Ubíqua seja rigorosa e precisa. Uma vez definida, deve ser utilizada até o fim.
Talvez um bom exercício para saber se você está conseguindo utilizar a esse princípio do DDD da maneira correta seria extrair um diagrama de classe e mostrar a um especialista e mostrar para o usuário. Ao fazer isso, ele conseguiria entender e validar o modelo de negócio? Se sim, está próximo do DDD.
Bounded Contexts
Serve para sinalizar até aonde vai a responsabilidade de cada parte do sistema. Cada contexto possui suas responsabilidades claramente definidas (Pagamento, assinatura, frete).
Um ponto importante é que cada contexto pode ter sua própria abordagem de arquitetura (camadas de aplicação, persistência, infraestrutura e etc) inclusive sua própria linguagem ubíqua. Se você trabalha em departamento de vendas, por exemplo, um cliente pode ser alguém que faz ordem de serviço.
Mas para alguém do setor de Marketing pode ser o consumidor de propagandas etc. Isso acontece poque entidades com mesmo nome podem ser encontradas em contexto diferentes.
A utilização de histórias e levantamento do escopo do projeto com o domain expert auxilia no processo de delimitação dos contextos e isso deve ser feito de uma forma mais efetiva possível.
O Vernon Vernon dá uma dica para quando você está em reuniões com pessoas de negócio e elas tem visões diferentes sobre o domínio e precisa-se delimitar os contextos que serão utilizados no projeto. Segundo o autor, quando isso acontece, ou todo mundo tem razão e deve separar os domínios ou a pessoa responsável não está no momento.
Existem algumas referências descrevendo que perguntaram ao Eric Evans se ele pudesse modificar algo no seu livro, o que seria. Ele respondeu que começaria falando primeiro ou focaria mais em Bounded Contexts devido a sua complexidade e importância para a abordagem do DDD.
Em uma fase mais avançada no projeto de uma aplicação, cada Contexto precisa ser transformado em código. Um insight interessante que essa estratégia pode trazer é que normalmente cada contexto definido pode ser transformado em um microsserviço.
Context Maps
O mapa de contexto nada mais é do que um documento, uma imagem, um rascunho anexado na parede, qualquer coisa que facilite o entendimento dos contextos da aplicação.
Pilares do Design Tático
Em linhas gerais iremos falar de padrões de desenvolvimento e estruturação de aplicações cujo domínio é o principal foco. As ferramentas de design tático do DDD se preocupam com os detalhes da implementação. Geralmente trata dos componentes dentro de um contexto delimitado. Ao contrário do design estratégico, espera-se que o design tático
sofra mudanças durante o desenvolvimento do produto
Value Objects
Value Objects é uma coleção de atributos que são imutáveis. Isso significa que normalmente não possuem métodos seters e a entrada dos valores se dá através do construtor. Além disso, possui uma tipagem forte ao invés de dados primitivos. O próprio VO deve conter sua regra de consistência e ele mesmo deve se validar.
Entidade
A principal diferença entre entidade e value object é que entidades possuem identidade. Ou seja, deve ser exclusiva para o objeto mapeado. Nela se encontram as principais lógicas de negócios, mas não fazem persistência. Entidades também possuem estados e comportamentos.
Aggregates
Podemos dizer que Aggregate é uma entidade com características diferentes. Ou ainda, um conjunto de entidades usadas e referenciadas juntas. Quando um dado é alterado essas entidades são tratadas como uma só.
Possui uma raiz de agregação (Aggregation Root) que é a entidade mais "forte" do conjunto e que mantém a integridade do objeto.
Na imagem abaixo, temos exemplos de agregações compostas por sua entidade raiz (azul), demais entidades (cinza) e alguns value objects (branco).
É importante dizer que quando a entidade está isolada, ela é sua própria raiz de agregação.
O Aggregation Root tem entre seus principais objetivos proteger/evitar o acesso direto aos objetos filhos e certificar que o estado desses objetos está sempre consistente.
Outro detalhe que vale mencionar é que deve existir apenas um repositório por agregação.
Na imagem acima, como podemos entender o limite dessas Cliente
e Endereço
? São entidades distintas ou devem compor uma agregação? Os limites de uma agregação são determinados pela regra de negócio. Então, para entender o limite entre as duas devemos nos perguntar se esse endereço serve pra outra coisa além de pertencer a um cliente. Caso não, deveria compor uma agregação que tem Cliente
como raiz.
Repositório
Os repositórios possuem acesso direto a camada de dados. Eles persistem os dados utilizando as entidades. Possui os métodos necessários para consultar, inserir, atualizar e excluir registros de uma fonte de dados.
Serviços de domínio
Os Domain Services trabalham com diversos fluxos de diversas entidades e agregações. Utilizam os repositórios como interface de acesso aos dados, consumem recursos da camada de infra como enviar e-mail, disparar eventos, entre outros. Basicamente fazem tudo o que o model não deve fazer.
Event storming
Apresentados todos esses conceitos é comum olhar tudo isso, entender, mas não conseguir traçar um plano claro sobre como colocá-lo em prática. Para isso existe uma técnica extremamente poderosa para esse fim, o Event Storming.
Se trata de um exercício para criação de modelos de domínios para design estratégico. É basicamente um whorkshop de Brain storming que engaja especialistas do domínio de negócios com desenvolvedores focando mais nos processos de negócio do que em abstrações técnicas (classes, entidades…).
Normalmente se colocam post-its em um quadro para indicar quais eventos de domínio acontecem, a quem interessa, quem provocou, tudo de forma ordenada numa linha de tempo para que se desenhe um caminho que o software irá percorrer. Isso pode clarificar muitas coisas para os membros da equipe.
Essa materialização visual pode ajudar ao desenvolvedor a ter noção do seu papel no contexto do domínio. Acredito que deve ser imprescindível codificar e saber em que ponto você está.
Considerações Finais
Uma provocação válida seria perguntar se vale a pena usar DDD pra tudo? A resposta que eu daria seria: Vale a pena pra quase tudo!
O DDD é voltado para domínios complexos, usá-lo implica em uma efetiva comunicação entre especialistas de negócio e especialistas técnicos, esforço dos devs em programar de forma que o código reflita o domínio. Se um desses pontos não se aplicar ao contexto em questão, provavelmente o DDD não serve para o cenário que você está lidando.
Espero que tenha ficado claro que o DDD não é nenhuma bala de prata, assim como o Clean Architecture que foi tema do meu post anterior, para resolver todos os problemas de um software. O importante é ter em mente que ao identificar que o domínio em questão é complexo, que existe a intenção de desenvolve-lo para que a representação do domínio seja clara até para os Domain Experts e mais, que o cliente está interessado em colaborar com o entendimento do domínio e validação da solução, provavelmente o DDD seja uma boa escolha como abordagem de desenvolvimento.
Tenho ciência que para explanar por completo essa "filosofia" de desenvolvimento de software seria necessário muito mais que esse post. Então espero ter atingido o objetivo de sumarizar os princípios do Domain Driven Design através desse compilado de informações e sirva, por que não, de insumo para discursões construtivas sobre esse tema riquíssimo.
Referências
Domain-Driven Design: uma visão geral — Eriksen Costa
DDD: Boas Práticas na escrita e validação de Entidades de Domínio - Eduardo Pires
Aprenda DDD (Domain Driven Design) do jeito certo - Full Cycle
Course #1 Mastering the art of Microservices Architecture - Alpha Code
Posted on June 13, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.