DDD não é o que você esta pensando !!!
![]() |
Neste artigo veremos porque muita gente acha que esta usando DDD só porque criou camadas e organizou o código em pastas com nomes como Domain, Application, Infrastructure e API. |
Para não tornar o artigo longo e chato e vou assumir um cenário bem ingênuo mas que vai servir ao nosso propósito. Imagine que você tem a seguinte definição de classes em um sistema qualquer onde tem que tratar com Produto e Categoria:
Você vai encontrar este exemplo de código em 90% dos exemplos na internet definindo o relacionamento entre Produto e Categoria :
public class Categoria { public int Id { get; set; } public string Nome { get; set; } public virtual ICollection<Produto> Produtos { get; set; } } public class Produto { public int Id { get; set; } public string Nome { get; set; } public decimal Preco { get; set; } public int Estoque { get; set; } public int CategoriaId { get; set; } public virtual Categoria Categoria { get; set; } } |
No sistema foi adotada uma arquitetura em camadas com organização em pastas como : Domain, Application, Infrastructure e API. Até aqui tudo bem. O problema é você afirmar que esta usando a abordagem DDD neste sistema se baseando nisso.
Vamos por partes...
Resposta curta e honesta:
❌ Não. Esse modelo NÃO está correto sob a perspectiva de DDD.
✔ Ele está
correto sob a perspectiva de ORM / EF Core.
E isso é uma diferença
crítica.
Mas porque não é DDD ?
Vamos analisar o código com lupa :
❌ Problemas do ponto de vista do DDD
Entidades com setters públicos
Qualquer código pode quebrar invariantes
Temos um relacionamento bidirecional rico
Um agregado “enxerga” o outro por inteiro
Temos uma mistura de conceito de navegação com domínio
O domínio passa a existir para o ORM
Categoria e Produto estão acoplados fortemente
A Mudança em um impacta diretamente o outro
O Modelo é orientado à persistência
Não existe comportamento definido
Isso é o
que chamamos de modelo anêmico orientado a banco.
O erro conceitual mais importante aqui :
“Este código esta definindo duas
classes Categoria e Produto que possuem um relacionamento
muitos para muitos”
Mas na abordagem do DDD, a pergunta correta é:
Categoria e Produto pertencem ao mesmo Bounded Context ?
Porque :
Se pertencem ao MESMO contexto, NÃO existe ACL (Anti-Corruption
Layer)
Se pertencem a contextos
diferentes, NÃO pode existir relacionamento direto
Nota : ACL é um padrão de design crucial utilizado para servir como uma ponte de comunicação tradutora e isolante entre dois ou domínios que possuem modelos de domínio ou linguagens ubíquas diferentes
Cenário A — Categoria e Produto NO MESMO
Bounded Context
Exemplo: Gestão de
Catálogo
Nesse caso:
❌ NÃO existe ACL
❌ NÃO existe Published
Language (Padrão de integração utilizado para permitir a comunicação entre
diferentes
Contextos Delimitados)
❌ NÃO existe Snapshot (refere-se
a uma representação serializada do estado de um
Agregado (Aggregate) em um determinado momento no tempo)
Porque não há integração entre
contextos.
Modelagem DDD correta (simplificada)
public class Produto { public Guid Id { get; } public string Nome { get; private set; } public Money PrecoAtual { get; private set; } private readonly List<Categoria> _categorias = new(); public IReadOnlyCollection<Categoria> Categorias => _categorias; } public class Categoria { public Guid Id { get; } public string Nome { get; private set; } } |
Observe:
Sem navegação ORM
Sem bidirecionalidade
Sem dependência de infraestrutura
DDD não começa modelando
relacionamentos (1:N, N:N).
DDD começa
modelando responsabilidades e invariantes.
Cenário B — Produto e Categoria em CONTEXTOS
DIFERENTES
Aqui Produto e Categoria NÃO
estão em contextos diferentes entre si
Eles estão juntos no Catálogo
O
“contextos diferentes” aqui é entre o BC Catálogo e o BC Pedidos
“Onde entra a ACL aqui?”
A ACL é uma camada que protege o seu domínio de modelos, conceitos e regras externas. Lembrando que ACL não é: DTO, API Client , Repositório, Adapter técnico, Mapper genérico (AutoMapper) e vive na camada de aplicação e não no domínio.
A ACL NÃO entra entre Categoria e Produto
Ela entra quando
OUTRO contexto consome dados do Catálogo
Exemplo:
Pedidos consumindo Produto do Catálogo
Catálogo publica (Published
Language):
| public sealed record
ProdutoCatalogoDto( Guid Id, string Nome, decimal Preco ); |
Pedidos recebe isso via ACL:
|
public sealed class
ProdutoCatalogoAcl { public ProdutoSnapshot Traduzir(ProdutoCatalogoDto dto) { return new ProdutoSnapshot( dto.Id, dto.Nome, new PrecoUnitario(dto.Preco) ); } } |
E o domínio de Pedidos usa: pedido.AdicionarItem(produtoSnapshot);
Pedidos nunca aceita Produto do Catálogo
Pedidos só aceita o que ELE
entende
Grave esta regra:
A ACL só existe ENTRE Bounded
Contexts.
Nunca dentro de um mesmo contexto.
Se você tem:
Categoria ↔ Produto no mesmo BC → sem ACL
Catálogo → Pedidos → com
ACL
Clientes → Pedidos → com ACL
A ACL só existe quando atravessamos uma fronteira de Bounded Context.
Dentro do mesmo contexto, não há ACL.
Entre
contextos diferentes, a ACL é obrigatória para proteger o domínio.
E estamos
conversados...
"Porque somos feitura sua, criados em Cristo Jesus
para as boas obras, as quais Deus preparou para que andássemos nelas"
Efésios 2:10
Referências:
NET - Unit of Work - Padrão Unidade de ...