DDD não é arquitetura em camadas

O DDD tornou-se um tema altamente debatido e naturalmente uma série de equívocos surgiram através dos diferentes entendimentos sobre o assunto.

Vou citar algumas perguntas / afirmações que venho observando faz alguns anos e são a minha principal motivação para escrever este post.

  • Como faço para persistir uma entidade com Entity Framework no DDD?
  • Como faço para popular um DropDownList seguindo o padrão DDD?
  • Iniciei um novo projeto em MVC + DDD na minha empresa e tenho uma dúvida.
  • Estou criando um back-end em WebAPI + DDD
  • Onde coloco uma camada de cache num projeto DDD?
  • Existe algum framework de DDD em .NET?

DDD não é arquitetura em camadas.

O DDD é uma abordagem de modelagem de software que segue um conjunto de práticas com objetivo de facilitar a implementação de complexas regras / processos de negócios que tratamos como domínio.

Domain Driven Design como o nome já diz é sobre design. Design guiado pelo domínio, ou seja, uma modelagem de software focada em resolver problemas na complexidade do negócio.

“Toda arquitetura é design, mas nem todo design é arquitetura” – Grady Booch

O DDD não é uma receita pronta sobre como desenvolver uma arquitetura baseada em Presentation, Services, Application, Domain e Infra.

DDD não é tecnologia.

O DDD não depende da tecnologia que você irá utilizar para fornecer sua aplicação seja ela ASP.NET MVC, WebAPI, SPA, Windows Forms ou etc.

O DDD não irá influenciar em diversas decisões:

  • Como preencher um controle na camada de apresentação
  • Como expor uma API REST
  • Qual tecnologia usar para persistir os dados
  • Como realizar o deploy da aplicação
  • Como modelar seu banco de dados
  • Como trabalhar com camadas de Infra (ex. Cache, Log, IoC)
  • Qualquer outra decisão de tecnologia.

Evite as gafes

Evite utilizar o termo DDD acompanhado de questões que não envolvem diretamente os conceitos do DDD, pois pode dar a entender que você não compreendeu sobre do que se trata o assunto.

Então do que se trata o DDD?

O DDD resgatou e catalogou uma série de boas práticas que foram ignoradas durante anos na maioria dos projetos e na minha opinião esta é a maior conquista do autor na concepção da sua ideia.

Eric Evans em seu livro aborda desde o primeiro capítulo a preocupação no entendimento do negócio, pois entender e destilar o negócio é o único meio de implementar o DDD em um projeto.

Não existe um modelo passo-a-passo de como implementar o DDD, mas podemos tentar criar um resumo básico:

Passo #1 – Entender o Negócio

Sem entender o negócio não tem como implementar o DDD. Em um projeto existem basicamente dois tipos de papéis, o Time de Desenvolvimento e os Domain Experts.
Os Domain Experts entendem do negócio e vão guiar o time de desenvolvimento no projeto tirando dúvidas, definindo regras e processos e nomeando os termos a serem utilizados.

Passo #2 – Extrair a Linguagem Ubíqua

A Linguagem Ubíqua é uma linguagem compartilhada e desenvolvida pela equipe de Domain Experts e de Desenvolvimento. A Linguagem Ubíqua é a linguagem do negócio dentro da empresa e todos devem fazer uso dela para expressar corretamente todos processos / intenções de negócio.

Existem diversas técnicas para extrair e catalogar a Linguagem Ubíqua, cabe ao time definir a melhor maneira de colaborar.

Passo #3 – Modelagem Estratégica

Extrair a Linguagem Ubíqua vai colaborar na visão e entendimento do negócio e como segregar seu domínio em partes menores e responsáveis.

DDD Context Map

Para documentar estas segregações responsáveis utilizamos o Mapa de Contextos (Context Map) que pode ser representado através de imagens e uma simples documentação do tipo de relacionamento entre os contextos.

Além de delimitar os contextos a modelagem estratégica engloba outros conceitos como  Sub-Domain, Shared Kernel, Customer/Supplier, Conformist, Anti-Corruption Layer, Separate Ways, Open Host Service e Published Language.

Cada contexto delimitado possui sua própria Linguagem Ubíqua, para entender melhor estes conceitos eu escrevi um artigo falando sobre os Bounded Contexts.

Nota: Eu acredito que não existe uma forma de implementar o DDD sem aplicar os conceitos da modelagem estratégica. Inclusive o próprio Eric Evans comentou que se ele fosse escrever seu livro nos dias de hoje ele teria começado pelo conceito de Bounded Contexts.

Passo #4 – Definir a Arquitetura

Tendo uma clara visão do Context Map é possível trabalhar na definição da arquitetura.

Cada contexto pode possuir uma arquitetura independente dos demais, não é necessário impor o mesmo estilo arquitetural para todos os contextos.

O DDD não prega a necessidade de uma arquitetura de 4 camadas (Presentation, Application, Domain e Infra). Pelo contrário, o arquiteto tem a liberdade de definir o melhor estilo arquitetural para atender a necessidade da aplicação, podendo utilizar modelos simples de 3 camadas como o Table Module Pattern.

Existem diversos estilos arquiteturais como a clássica Arquitetura CebolaArquitetura Hexagonal proposta pelo Vernon em seu livro Implementing Domain Driven Design ou até mesmo os populares Microservices. Alguns destes estilos inclusive podem fazer uso de patterns como CQRS, Event Sourcing, etc.

Um arquiteto deve conhecer os estilos e patterns arquiteturais e saber reconhecer onde e quando devem ser utilizados.

Passo #5 – Modelagem Tática

Quando o assunto é DDD a modelagem tática fica por conta do Domain Model Pattern que é uma abordagem de como escrever as classes que vão mapear os modelos do mundo real e implementar os comportamentos do negócio.

O Domain Model Pattern deve ser isolado dos detalhes da sua arquitetura como persistência e etc.

O Eric Evans não criou os patterns utilizados no Domain Model, apenas fez o uso correto deles criando então esta abordagem de modelagem tática que incluem os seguintes componentes:

  • Aggregate Object
    Uma entidade que é a raiz agregadora de um processo do domínio que envolve mais de uma entidade.
  • Domain Model
    Uma entidade do domínio, possui estados e comportamentos, lógica de negócio, getters e setters AdHoc, etc.
  • Value Object
    Um objeto que agrega valor às entidades, não possui identidade e é imutável.
  • Factory
    Classe responsável por construir adequadamente um objeto / entidade.
  • Domain Service
    Serviço do domínio que atende partes do negócio que não se encaixam em entidades específicas, trabalha com diversas entidades, realiza persistência através de repositórios e etc.
  • Application Service
    Serviço de aplicação que orquestra ações disparadas pela camada de apresentação e fornece DTOs para comunicação entre as demais camadas e para o consumo da camada de apresentação.
  • Repository
    Uma classe que realiza a persistência das entidades se comunicando diretamente com o meio de acesso aos dados, é utilizado apenas um repositório por agregação.
  • External Service
    Serviço externo que realiza a consulta/persistência de informações por meios diversos.

Se você trabalhou em todos os passos citados, parabéns! Você provavelmente está implementando o DDD. Fique a vontade para utilizar técnicas como TDD e BDD e sinta-se livre para escolher a plataforma da camada de apresentação ou como distribuir suas API’s etc. Afinal este não é o foco e nem uma exigência do DDD.

Quando devo utilizar o DDD?

Apesar de muitas pessoas afirmarem utilizar DDD apenas por possuir uma arquitetura em camadas isto não significa que realmente estejam usando o DDD, existem algumas interpretações como DDD-Lite que seria uma aplicação utilizando alguns conceitos encontrados no DDD porém ignorando muitos outros.

Uma analogia a este cenário seria um time de desenvolvimento dizer que utiliza Scrum como uma metodologia de desenvolvimento ágil quando somente faz uso de um quadro Kanban e ignora as práticas de sprints, cerimônias etc. Nós chamamos isto de ScrumBut.

Espero que tenha ficado claro até este ponto o que é realmente o DDD e os passos principais para implementá-lo. Para saber se você deve ou não implementar o DDD no seu projeto, disponibilizo abaixo um DDD Score Card extraído do livro Implementing Domain Driven Design.

A ideia é bem simples, a primeira coluna descreve seu projeto, em seguida o número de pontos que devem ser acumulados, a última coluna descreve algumas concepções.
Se no final a somatória dos pontos for igual ou maior que 7 considere seriamente em implementar o DDD em seu projeto.

Se seu Projeto… Pontos Pensamentos de Suporte
Se sua aplicação for completamente centrada em dados e se qualificar verdadeiramente para uma solução CRUD pura, em que cada operação é basicamente uma consulta simples de banco de dados para criar, ler, atualizar ou excluir, você não precisa do DDD. Sua equipe só precisa colocar um rosto
bonito em um editor de tabelas de banco de dados. Em outras palavras, se você puder confiar no fato de que os usuários irão inserir os dados diretamente em uma tabela, atualizá-los e, às vezes, excluí-los, você nem mesmo precisará de uma interface do usuário. Isso não é realista, mas é conceitualmente relevante. Se pudesse usar uma ferramenta simples de desenvolvimento de banco de dados para criar uma solução, você não desperdiçaria o tempo e dinheiro de sua empresa no DDD.
0 Isso parece óbvio, mas normalmente não é fácil determinar
simples versus complexo. Não é como se todas as aplicações que não são CRUD puras merecem o tempo e o esforço
do uso do DDD. Assim, talvez possamos sugerir outros indicadores para nos ajudar a traçar uma linha entre o que é complexo e o que não é …
Se seu sistema exigir apenas 30 ou menos operações de
negócio, ele provavelmente é bem simples. Isso significaria
que a aplicação não teria um total de mais de 30 histórias de usuário ou fluxos de caso de uso, com cada um desses fluxos tendo apenas uma lógica mínima de negócio. Se você puder desenvolver rápida e facilmente esse tipo de aplicação e não se importar com a falta de poder e controle em relação à complexidade e alteração, o sistema provavelmente não precisará usar o DDD.
1 Para ser claro, estou falando de 25 a 30 únicos métodos de negócio, não de 25 a 30 interfaces de serviço completas, cada uma com vários métodos. O último pode ser complexo.
Assim, digamos que, em algum lugar no intervalo entre 30 e 40 histórias de usuário ou fluxos de caso de uso, a complexidade poderia ser pior. Seu sistema pode estar entrando no território do DDD. 2 O risco é do comprador: Bem frequentemente a complexidade não é reconhecida rapidamente. Nós, desenvolvedores de software, somos realmente muito bons para subestimar a complexidade e o nível de esforços. Só porque talvez queiramos codificar uma aplicação em N camadas com diversos Patterns não significa que devemos. No longo prazo, essas aplicações poderiam prejudicar mais do que ajudar.
Mesmo que a aplicação não seja complexa agora, a complexidade dela aumentará? Você só pode saber isso ao certo depois que os usuários reais começam a trabalhar com ela, mas há um passo na coluna “Pensamentos de suporte” que pode ajudar a revelar a situação real.
Tenha cuidado aqui. Se houver absolutamente qualquer indício de que a aplicação tem complexidade mesmo moderada — este é um bom momento para ser paranoico —, isso pode ser uma indicação suficiente de que ela na verdade será mais do que moderadamente complexa. Incline-se em direção ao DDD.
3 Aqui vale a pena analisar os cenários de uso mais complexos com especialistas em domínio e ver aonde eles levam.Os especialistas em domínio:
#1 Já estão solicitando recursos mais complexos? Se sim, isso provavelmente é uma indicação de que a aplicação já é ou em breve se tornará excessivamente complexa para usar uma abordagem CRUD.#2 Estão entediados com os recursos ao ponto em que dificilmente vale a pena discuti-los? Provavelmente não é complexa.
Os recursos da aplicação serão alterados com frequência ao longo de alguns anos, e você não pode antecipar que as alterações serão simples. 4 O DDD pode ajudá-lo a gerenciar a complexidade da refatoração de seu modelo ao longo do tempo.
Você não entende o Domínio porque ele é novo. Na medida em que você e sua equipe sabem, ninguém fez isso antes. Isso provavelmente significa que ele é complexo ou, pelo menos, merece a devida diligência com análise analítica para determinar o nível de complexidade. 5 Você precisará trabalhar com Domain Experts e testar os modelos para fazer a coisa certa. Você certamente também pontuou em um ou mais dos critérios anteriores, portanto, use o DDD.

Ao finalizar este exercício você terá mais clareza para determinar se o DDD é viável ou não para o seu projeto. Lembre-se de tomar as decisões com foco na simplicidade, entrega e manutenção. Muitas vezes sofremos da vontade incontrolável de implementar todos os conceitos de nossos estudos, porém estamos colocando em risco o dinheiro da empresa e nossa própria carreira.

Erros comuns

Agora que está muito claro o que é o DDD e se ele é viável para seu projeto, gostaria de alertar sobre os erros mais comuns cometidos pela maioria dos desenvolvedores.

#1 – Permitir que o meio de persistência influencie diretamente nas entidades.

Quando utilizamos ORM’s para mapear o banco e nossas entidades muitas vezes somos obrigados a “infectar” nossos modelos com necessidades do ORM utilizado. Evite ao máximo tomar decisões que impactem em suas entidades e que no final servem apenas para atender as necessidades do meio de persistência.

 #2 – Não se envolver com os Domain Experts

Ignorar o conhecimento de negócio dos Domain Experts é uma falha grave, busque envolvê-los diretamente no projeto e nas decisões. Documentar alguns processos com BDD é uma ótima maneira de aproximar todos os envolvidos em uma conversa fluente e clara.

Se na sua empresa não existe o “Domain Expert” não tem problema, com certeza existe alguém que conheça bem do negócio, traga esta pessoa para participar ativamente no projeto.

#3 – Ignorar a Linguagem Ubíqua

A Linguagem Ubíqua é a linguagem do negócio, deixar de extraí-la e mapeá-la poderá acarretar em sérios problemas de comunicação que irão refletir diretamente no entendimento dos requisitos e no código fonte. Será um grande problema no futuro.

#4 – Não identificar os limites dos contextos

Pular a parte da modelagem estratégica é um dos maiores erros que se pode cometer ao implementar o DDD. Isto tornará sua aplicação extremamente complexa e monolítica, é o princípio de uma grande bola de lama (Big Ball of Mud).

#5 – Escrever entidades anêmicas

O uso de entidades anêmicas é sinal de uma grande falta de entendimento no comportamento de uma entidade, quebra o próprio conceito da OOP que diz que um objeto deve possuir estados e comportamentos. Uma entidade no mínimo deve saber se auto-validar para garantir sua consistência, logo não existem motivos para escrever entidades anêmicas.

#6 – Assumir que toda lógica é lógica de domínio 

Nem toda validação é responsabilidade do domínio. Por exemplo o tratamento de acesso e permissões de usuário, isto é responsabilidade da aplicação. Deixar todas as validações por conta do domínio também é uma falha, num cenário Web a camada de apresentação também pode realizar as validações necessárias para filtrar as requisições no servidor.

#7 – Focar demais na infra-estrutura

Implementar um projeto com DDD significa trabalhar com foco no negócio, iniciar o projeto pela modelagem do banco de dados e preocupando-se com os meios de persistência são erros que podem pode gerar impactos negativos nos seus modelos de domínio. A camada de infra-estrutura serve para suportar responsabilidades que não são do domínio, foque nas implementações de infra-estrutura conforme a necessidade surgir.

Resumindo

Implementar o DDD em seu projeto pode ser uma ótima decisão que proporcionará mais facilidades para atender aos complexos processos de negócio. Tornará a equipe mais colaborativa e focada no que é realmente mais importante.

Não se aventure no escuro! Antes de iniciar um projeto em DDD é necessário ter um bom conhecimento teórico e prático em todos os conceitos abordados neste artigo. Eu recomendo fortemente a leitura de livros, cursos e demais conteúdos que irão lhe preparar para que este desafio não se torne um grande desastre.

E por fim evite de utilizar o DDD como referência para arquitetura em camadas, agora você já sabe que não é disto que se trata o DDD.


Caso esteja interessado em conhecer mais sobre o DDD, Padrões de Arquitetura como CQRS, Event Sourcing e boas práticas de desenvolvimento não deixe de conferir a ementa do meu curso:

Vamos continuar a troca de experiências, deixe seu comentário abaixo. Se gostou e concorda com o artigo, compartilhe com seus colegas para transmitirmos o conhecimento para o máximo de pessoas possíveis.

28 pensou em “DDD não é arquitetura em camadas

  1. Eduardo,

    Muito bom artigo! Inclusive estamos num momento de início de utilização do DDD aqui na empresa e este artigo ajudou a elucidar alguns pontos.

    Abraços

  2. Agora gostei 🙂

    Já era hora de alguém da comunidade(formador de opiniões kkk) falar realmente que DDD não é separação de camadas.

    Hoje, muitos pensam que DDD é separar em N camadas e usar alguns patterns e pronto, é DDD kkkkk
    Os patterns (repository e service, mais falados) servem para AUXILIAR e TENTAR abstrair da melhor forma, mas não é obrigatório segui-los a risca para realmente estar utilizando DDD em algum projeto 🙂

  3. Olá Eduardo. Parabéns outro post muito rico e didático, mais um para a série de guia de referências.

  4. Eduardo, ótimo post, como sempre! Muito legal e clara a explicação sobre o que é o DDD. A planilha criada para verificar se o projeto se encaixa no modelo também foi muito bacana.
    Mas, vi um ponto que me chamou atenção:
    “Domain Service
    Serviço do domínio que atende partes do negócio que não se encaixam em entidades específicas, trabalha com diversas entidades, realiza persistência através de repositórios e etc.”
    Não é responsabilidade do DomainService (que é parte do domínio) realizar a persistência através de repositórios, seria responsabilidade do Application Service, correto?
    http://1.bp.blogspot.com/-f9QYYWLc1Uk/UoKzpDHYkkI/AAAAAAAACA4/OD1bq9MLYFY/s1600/DDD_png_pure.png

    • Tanto o Application Service ou Domain Service podem persistir as entidades, em um cenário que envolve regras com cross-aggregates (entidades) e persistência o ideal é um Domain Service.

  5. Muito bom artigo!
    Achei bem interessante essa classificação dos pontos, apresentou um caminho que muitas vezes não temos ao iniciar um projeto.

  6. Primeiramente gostaria de agradecer pelo post, foi muito bom mesmo obrigado!

    No entanto me bateu uma dúvida!
    Vou descrever um cenário! imagine um ERP(Fiscal, CRM, Contábil, Etc…) grande antigo com mais de 15 anos de desenvolvimento e uso feito construído encima de uma tecnologia antiga(logo enfrenta diversos problema), Beleza decide migra-lo inteiro para uma tecnologia mais atual ex: .NET C# mas ele pensa ‘bom já que vamos migrar vamos fazer melhor algumas coisas’, ai vem a pergunta, nesse pensamento dele de já querer fazer algumas coisas diferentes DDD pode ser uma opção?

    Obrigado!

  7. Excelente post, parabéns, bem esclarecedor…
    Quanto aos erros de ORM de DDD estou com uma dúvida num caso, imaginando um sistema deste tipo (pus um exemplo onde teoricamente um VO que para o negócio não teria importância, ele tem para o banco de dados por causa que serviria como referencia para outra tabela)

    Tabelas
    Pessoa – campos: idPessoa, Nome -> <>
    Celular – campos: idCelular, Numero -> <>
    Vigencia – campos: idVigencia, idPessoa, idCelular, dataInicio, dataFim -> <>
    A tabela Pessoa seria o cadastro de funcionário da empresa, suponhamos que tenha em torno de 10 mil registros A tabela Celular são dados de todos celulares que a empresa possui, suponhamos uns 3 mil registros

    A tabela Vigencia é a associativa de Pessoa X Celular, exemplo, o “Joao” está com o celular “11 91234-5678” na data inicial “01-01-2016” e a data final ficaria nula significando que ainda este celular está com ele, e este registro teria um “idVigencia” 1, que não é relativo ao negócio.

    Agora que estamos no dia 20/08/2016, ficamos sabendo que o “João” não é mais dono deste celular, e agora é a Maria. Então na tabela de “Vigencia” atualizaria a “data final” da vigencia do “João” para “31-07-2016” e criaria outro registro para a “Maria” com a “data inicia” em “01-08-2016”, assim diz que o celular “trocou” de dono

    Ligacao – campos: idLigacao, idVigencia, etc… -> <>
    Na tabela de ligações, temos ligações do mes 05, 06, 07 e 08 de 2016, onde este celular está com o João, então a FK do campo idVigencia da tabela de Ligação será o numero 1 neste caso, só que com a mudança da “Vigencia” do “João” o mês 08/2016 estaria com a FK errada e deveria ser reprocessada.

    Sendo assim, a “Vigencia” seria um Value Object ? (que também é minha duvida, pois poderia talvez ser um Entity, porém não vejo uma identidade no “idVigencia”, talvez no conjunto de campos)

    Caso for um a vigencia seria imutável e ao atualizar o “João” colocando a “data final” para “31-07-2016”, teria que descartar o objeto e criá-lo novamente, só que entra no problema em relação a FK “idVigencia” da tabela de “Ligação”

    Qual a melhor maneira de implementar isso com DDD? Pois afeta o modelo da dados

    Abraços

  8. Muito bom o artigo… Parabéns.

    Sou um entusiasta do DDD e estou utilizando para implementar um software que, por enquanto, ainda parece ser pequeno.

    Tenho uma dúvida: uso o spring-data-jpa. Segundo o livro do Vernon, há a necessidade de se implementar classes do tipo repositório. Porém, o Spring-data já implementa os repositórios como interfaces, tanto que chamo os métodos dos repositórios na camada de aplicação e de interface. Tenho nove tipos de repositórios (um para cada classe) e quadro agregados. Tenho que realmente manter o mapeamento de um para um com os agregados? Gostaria de sua opinião sobre o seguinte problema.

  9. Fiquei na dúvida ,no meu projeto Aspnet Web Application eu posso criar uma variável na minha controller.cs com uma referência da entidade mapeada da minha camada da dominio para receber o resultado de um serviço da minha camada de dominio ?

  10. Qual seria a melhor estratégia para internacionalizar um sistema na arquitetura DDD, sabendo-se que temos strings para internacionalizar presentes nas camadas:
    Presentation – Views
    Application – ViewModels nos DataAnnotation
    Domain – Validation e Specifications
    Levando em consideração que a camada Domain não deve conhecer nenhuma camada, seria descartado a possibilidade de criar um projeto de internacionalização em uma camada que permeie todas as outras?

Os comentários estão fechados.