DDD costuma chegar às equipes acompanhado de um vocabulário intimidador: agregado, contexto delimitado, linguagem ubíqua. Só que a ideia central é bem mais pé no chão. Se o software resolve um problema de negócio, o código deveria falar sobre esse problema — não escondê-lo atrás de controllers genéricos e métodos chamados process.
Isso não quer dizer transformar todo CRUD em tratado acadêmico. Há partes do sistema em que cadastrar, listar e remover é exatamente o necessário. DDD começa a valer o esforço quando existem regras, exceções e decisões que não cabem bem nessa simplicidade.
Comece pela conversa
Antes de pensar em classes, tento descobrir o que realmente acontece. Quem pode cancelar um agendamento? Em que momento uma cobrança passa a existir? Dois termos parecidos representam a mesma coisa? Exemplos concretos quase sempre ensinam mais que uma especificação cheia de substantivos.
É nessa conversa que o modelo aparece. E ele muda. Se a equipe descobre amanhã que “aprovação” possui três sentidos diferentes, renomear e separar conceitos é avanço, não retrabalho.
As peças têm funções diferentes
Entidade, value object e agregado não são enfeites arquiteturais. São ferramentas para colocar uma regra no lugar em que ela pode ser protegida.
- Entidade: tem identidade e controla suas mudanças.
- Value object: representa um valor válido, como dinheiro ou período.
- Agregado: define o que precisa permanecer consistente na mesma transação.
- Serviço de aplicação: coordena o caso de uso sem decidir a regra por conta própria.
O teste mais útil é simples: consigo criar um estado que o negócio considera impossível? Se sim, o modelo ainda está deixando trabalho demais para quem o chama.
Um modelo não precisa servir à empresa inteira
“Cliente” pode significar uma pessoa para o suporte e uma conta faturável para o financeiro. Forçar os dois sentidos em uma classe universal produz campos opcionais, condicionais e discussões intermináveis. O Bounded Context permite assumir que cada modelo vale dentro de uma fronteira.
E fronteira não é sinônimo de microsserviço. Um monólito modular costuma ser um ótimo começo. Chamadas de rede não consertam limites mal compreendidos; só tornam a confusão mais cara.
O que funcionou em produtos reais
Na ANIMAPS, módulos em Nest.js ajudaram a manter capacidades diferentes sem espalhar decisões pelo projeto inteiro. Na KasbHealth, o cuidado precisa ser ainda maior: permissões e fluxos clínicos não podem virar um conjunto de atualizações genéricas de status.
Nos dois casos, o ganho veio menos de aplicar um catálogo de padrões e mais de manter regras perto dos nomes e dados que lhes dão sentido.
Se o time sabe explicar o fluxo com as mesmas palavras que encontra no código, o DDD já está fazendo um trabalho importante.
DDD na medida certa
Eu começaria por um fluxo que concentra dúvidas ou regressões. Descreveria cenários, protegeria as invariantes com testes e criaria a menor fronteira útil. Só depois avaliaria repositórios específicos, eventos de domínio ou separações mais profundas.
Complexidade acidental também pode nascer de uma tentativa bem-intencionada de “fazer DDD”. Se uma abstração exige mais explicação que a regra, talvez seja cedo para ela.
Conclusão
Domain-Driven Design é, no fundo, uma forma de levar o negócio a sério dentro do código. Ele ajuda quando torna decisões visíveis, estados inválidos difíceis e conversas mais precisas. O resto é ferramenta — e ferramenta boa é a que resolve a pressão real do sistema.