Mais uma dúvida sobre Entites X Repositories dentro de DDD

Pessoal, li muitas da discussões aqui no fórum sobre Entities X Repositories, algumas muito acaloradas rsrsrsrsrs… mas ainda persistiu uma dúvida. Na verdade eu sou desenvolvedor do mundo .NET mas sempre visito os fóruns aqui do GUJ, pois neles encontro muita informação interessante que ainda hoje não é muito divulgada entre desenvolvedores em plataforma MS.

Estou apenas iniciando na utilização de DDD e tenho uma dúvida simples mas que ainda não me foi esclarecida mesmo após horas de leitura nos posts sobre o assunto aqui no GUJ.

No .NET quando vamos fazer a separação de Layers utilizamos projetos de classes diferentes e uma limitação que existe nesse caso é que não pode haver referência circular entre dois projetos.

Com essa limitação em mente e entendendo que a arquitetura que tenho proposto para um projeto pessoal no qual estou trabalhando atualmente se constitui de um modelo básico parecido com:

[Aplicação]-> [DDD: Entities, Repositories, etc] -> [Infraestrtura: DAL -> NHibernate]

surge a seguinte dúvida:

Eu tenho uma Entity User, esta Entity pode fazer referência direta ao meu DAO para as operações básicas de CRUD, ou seria parte de DDD que as minhas Entities utilizem o Repository para estas operações?

Sei que é uma dúvida primária, mas primário é o estado em que estou na utilização de DDD.

Obrigado e abraços.

Olá Luiz.
Domain-Driven trabalha com o domínio do software e isso não contempla classes "DAO"s, que é apenas um pattern de abstração da persistência dos seus dados:

http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

Repositories são dirigidos ao domínio e não a infraestrutura… ele esta (e faz parte) do domínio e se comunica com a camada de persistencia (normalmente DAOs Data Mappers):

http://martinfowler.com/eaaCatalog/repository.html

Independente disso, uma entidade não deveria conter repositórios apenas para satisfazer métodos CRUDs.
Um Usuário que contenha operações como salvar e apagar (ele mesmo), descaracteriza seu objeto como uma Entity de um Domain Model e o torna parte de outro padrão, o Active Record.

http://martinfowler.com/eaaCatalog/activeRecord.html

Em Domain-Driven, é o repositório que deve adicionar ou remover entidades e não ela própria (não rola Active Record), portanto retire estes métodos de sua entidade.

Repositórios são úteis dentro da entidade, mas em outros casos. As vezes é necessário que um método de negócio (e não um simples CRUD) de uma Entity armazene informações ou realize consultas em uma única lógica
Normalmente um Service utiliza mais informações do repositório do que uma Entity, mas isso varia de caso a caso.

Oi, Luiz,

Sua dúvida não é básica e nem é tão relacionada com Doain-Driven Design. Procure ler sobre Dependency Inversion Principle. Eu escrevi um artigo que fala sobre isso para uma Mundo Java ou Mundo .Net (não lembro qual) mas dentro da plataforma da Microsoft existe um ótimo livro: Agile Principles, Patterns, and Practices in C# . Esse livro é uma versão C# do livro anterior do Uncle Bob, que usa Java: Agile Principles, Patterns, and Practices.

Basicamente o mesmo conteúdo em linguagens diferentes.

Não exatamente. Active Record está relacionado ao Data Mapper, uma Camada abaixo do Domínio. Um AR pode ser um Entity sem problemas e não é porque você não usa um padrão descrito em Domain-Driven Design que você não está usando Domain-Driven Design.

Oi Luiz, um livro interessante sobre DDD com exemplos em C#…

Applying Domain-Driven Design and Patterns: With Examples in C# and .NET

Uma entidade com responsabilidades de persistencia é uma salada de conceitos. Ela pode continuar sendo uma Entity, mas ao meu ver, mal modelada. Afinal de contas, o repository esta aí pra isso …

Fala galera, obrigado pelas respostas até agora, está sendo muito esclarecedor.

Lezinho, apenas para esclarecer, se eu tenho uma entity que possui seus próprios métodos CRUD, se esta chama o Repositório para se auto-persistir, ainda assim seria incorreto de acordo com sua visão, ter esses métodos em minha Entity?

E se não for assim, ou seja decidi por não ter o CRUD em minhas Entities, no caso quando precisar persistir uma Entity, eu deveria faze-lo no meu Cliente (entenda-se por cliente, uma Fachada ou mesmo a minha aplicação) utilizando algo parecido com:


User user = new User();

// código que preenche as informações de user....

ProfileRepository.Save(user);

Mesmo assim ainda não estou convencido de qual o melhor e mais prático modelo a ser utilizado se entities com ou sem CRUD, mas gostaria de entender melhor sua visão.

Em meus estudos sobre DDD, não vi nenhum restrição em uma entity ter o CRUD em si, mas como a discussão sempre é esclarecedora, quero entender melhor cada um dos pontos aqui abordados.

Apenas para título de informação, se em meu projeto .NET eu decido manter em dois projetos diferentes os meus Repositories e meus Entities, crio um problema de referência, pois meu projeto Repositories precisa referênciar o projeto de Entities e o projeto de Entities, se precisar de um Repository, vai ter que referênciar Repositoreis, o que cria uma referência circular não aceita pelo .NET (como sitei em meu primeiro post), mesmo usando de Interfaces não consigo ver uma solução para isso, caso eu queira realmente manter as coisas em Assemblies separados.

Oi cara… na minha empresa trabalho também com .NET e temos este mesmo problema de referencia ciclica…

ai usamos um domain model que tem um certo overhead, pois criamos uma VO apenas para trafegar informação da camada de dominio pra camada de persistencia…

um cara aki estava propondo uma solução com reflection, ficava mto boa… evitava a referencia ciclica (pq vc referencia o objeto a partir do proprio assembly) e evitava o overhead de replicar as propriedades do dominio pra VO… a unica coisa ruim eh a complexidade mesmo, mas com umas factories acabou ficando bem legal

Entities e Repositories fazem parte da mesma layer, a de domínio. Então, não há a necessidade de você colocá-las em projetos separados. Aliás, todo o teu aplicativo pode estar no mesmo projeto, tendo apenas uma divisão clara de layers.

Sobre a persistencias de suas entidades, é exatamente assim como você citou - Repository.add(entity). A único detalhe que acho que vale a pena citar, é que normalmente usamos termos pros métodos de repositório diferentes do que usamos em DAOs. Geralmente, em repositório:

  • add
  • remove
  • update ou merge
  • get

Porque esses termos abstraem um pouco mais a idéia de repositório, que não necessáriamente é um banco de dados relacional. Mas isso não é uma regra!

Abraço! :wink:

Exemplo extraído do livro que te indiquei (capitulo 6):

public interface ICustomerRepository
{
    Customer GetById(int id);
    IList GetByNamePattern(string namePattern);
    void Add(Customer c);
}

[quote=luizaso]
Apenas para título de informação, se em meu projeto .NET eu decido manter em dois projetos diferentes os meus Repositories e meus Entities, crio um problema de referência, pois meu projeto Repositories precisa referênciar o projeto de Entities e o projeto de Entities, se precisar de um Repository, vai ter que referênciar Repositoreis, o que cria uma referência circular não aceita pelo .NET (como sitei em meu primeiro post), mesmo usando de Interfaces não consigo ver uma solução para isso, caso eu queira realmente manter as coisas em Assemblies separados.[/quote]

Olá luizaso,

Eu postei algo sobre esse problema de referências cíclicas do .NET em meu blog. Eu sempre vi isto como um problema de design, mas gostaria aber a opinião de vcs…

[]s

Uma entidade com responsabilidades de persistencia é uma salada de conceitos. Ela pode continuar sendo uma Entity, mas ao meu ver, mal modelada. Afinal de contas, o repository esta aí pra isso …[/quote]

Repositories não são a única forma de se modelar o acesso a fontes de dados, AR em linguagens “duras” como Java realmente é horrível (eu fiz uma vez usando introduções do AspectJ mas não me agradei muito do resultado não), mas quando você passa pra uma linguagem com menos burocracia AR deixa o código bem mais simples e ainda tem a vantagem de ser uma classe a menos, afinal os métodos do repositório são todos stateless, se transformam num monte de métodos estáticos na classe do AR.

Não acho que AR torne uma entidade mal modelada, até porque as implementações de AR que eu tive contato até agora são bem menos poluentes que os métodos comuns de persistência em Java como o uso de annotations.

Sim. Vc tb pode usar domain services pra isso e apesar de ser menos comum, até pode ser feito dentro da propria entity. O importante é que seja feito delegando ao repositorio.

[quote=luizaso]
Apenas para título de informação, se em meu projeto .NET eu decido manter em dois projetos diferentes os meus Repositories e meus Entities, crio um problema de referência, pois meu projeto Repositories precisa referênciar o projeto de Entities e o projeto de Entities, se precisar de um Repository, vai ter que referênciar Repositoreis, o que cria uma referência circular não aceita pelo .NET (como sitei em meu primeiro post), mesmo usando de Interfaces não consigo ver uma solução para isso, caso eu queira realmente manter as coisas em Assemblies separados.[/quote]

Você pode separar seu dominio em diferentes projetos mas nao deve faze-lo utilizando criterios tecnicos como o tipo do objeto (entities, repositorios, services, …). Isso vai te levar a codigo com alto acoplamento e baixa coesao (vide Uncle Bob).

Eric Evans sugere que organizemos nosso dominio em modulos (pacotes em java e namespaces em .net) utilizando criterios conceituais do dominio, fazendo com que a estrtura de pacotes contribua para a UBIQUITOUS LANGUAGE.

Isso porque referencias cruzadas devem ser evitadas em todos os niveis, inclusive entre modulos.

1 curtida

[quote]
Lezinho, apenas para esclarecer, se eu tenho uma entity que possui seus próprios métodos CRUD, se esta chama o Repositório para se auto-persistir, ainda assim seria incorreto de acordo com sua visão, ter esses métodos em minha Entity?[/quote]

Do meu ponto de vista você esta dando voltas desnecessárias. Um repositório armazena informações, correto? Por que colocar mais este método identico na entidade (os CRUDs)? Apenas para delegar para o repositório? Qual o ganho disso?

Uma entidade tenta representar algo de seu domínio, ela tem o comportamento pertinente a sí. Esta entidade é armazenada em algum lugar, um repositório de dados, que é outro objeto de negócio.

Se uma entidade faz uso de um repositório de dados em seu método de negócio, faz sentido ela solicitar a ajuda de um repositório. Contudo não faz sentido a entidade assumir o papel de um repositório de dados, atuando só como uma fachada, sendo que já existe um repositório pra isso (e tanto um como outro pertencem a mesma camada de negócio).

… isso faz mais sentido do que você sugeriu no princípio. Segue anexo o popular diagrama de uma “Layered Architecture” retirada do Domain-Driven Design. Veja que tanto a layer Application e até mesmo a UI pode acessar o domain, o que não se pode é o contrário (Repositório tbm é domain).


Uma entidade com responsabilidades de persistencia é uma salada de conceitos. Ela pode continuar sendo uma Entity, mas ao meu ver, mal modelada. Afinal de contas, o repository esta aí pra isso …[/quote]

Repositories não são a única forma de se modelar o acesso a fontes de dados, AR em linguagens “duras” como Java realmente é horrível (eu fiz uma vez usando introduções do AspectJ mas não me agradei muito do resultado não), mas quando você passa pra uma linguagem com menos burocracia AR deixa o código bem mais simples e ainda tem a vantagem de ser uma classe a menos, afinal os métodos do repositório são todos stateless, se transformam num monte de métodos estáticos na classe do AR.

Não acho que AR torne uma entidade mal modelada, até porque as implementações de AR que eu tive contato até agora são bem menos poluentes que os métodos comuns de persistência em Java como o uso de annotations.[/quote]

Concordo que é uma classe a menos, Mauricio, mas temos que ponderar se isso é ganho ou não. Repositório é tbm classe de negócio, tão quanto é uma entidade, eu acredito nesse valor agregado.

É claro que tbm se deve preservar o bom senso. Jamais iria ingorar AR usando RoR simplesmente por achar que o design fica melhor separando mais responsabilidades.

[quote=Lezinho][quote=Maurício Linhares]
Repositories não são a única forma de se modelar o acesso a fontes de dados, AR em linguagens “duras” como Java realmente é horrível (eu fiz uma vez usando introduções do AspectJ mas não me agradei muito do resultado não), mas quando você passa pra uma linguagem com menos burocracia AR deixa o código bem mais simples e ainda tem a vantagem de ser uma classe a menos, afinal os métodos do repositório são todos stateless, se transformam num monte de métodos estáticos na classe do AR.

Não acho que AR torne uma entidade mal modelada, até porque as implementações de AR que eu tive contato até agora são bem menos poluentes que os métodos comuns de persistência em Java como o uso de annotations.[/quote]

Concordo que é uma classe a menos, Mauricio, mas temos que ponderar se isso é ganho ou não. Repositório é tbm classe de negócio, tão quanto é uma entidade, eu acredito nesse valor agregado.

É claro que tbm se deve preservar o bom senso. Jamais iria ingorar AR usando RoR simplesmente por achar que o design fica melhor separando mais responsabilidades.[/quote]

Repositorio nao é um ojbeto de negocio tanto quanto uma entidade. Sim, ele deve aderir a UBIQUITOUS LANGUAGE por conveniencia ja que reside no dominio mas nao tem o papel de “expressar o modelo”. Seu papel, assim como Factories é atuar no gerenciamento de ciclos de vida complexos que precisam ser encapsulados. Ciclos de vida dos “reais” objetos de dominio.

Portanto, outras solucoes como uma implementacao de AR decente sao muito bem vindas para substituir repositorios.

Um repositório, diferente de uma factory, tem sentido real. É fatídico que as informações do negócio devem ser armazendas em algum repositório de dados, isso faz parte do core business, assim como a recuperação destes objetos. Este lugar de armazenamento é o repositório… o negócio tem conhecimento disso.

A Factory é um simples artifício de criação, irrelevante para o negócio.

Já tinha me esquecido como aqui no GUJ uma pequena solicitação de informação pode se transformar em uma verdadeira aula sobre o assunto.

Laércio,

realmente concordo com você, e ontém mesmo estava pensando como essa separação por projetos pode não fazer muito sentido, isso vem de influências que sofro todos os dias na empresa onde trabalho. Mas ao ler seu artigo tive mais embasamento pra chegar a conclusão que minha idéia ontém de manter todos os elementos de um determinado assunto do meu modelo de domínio em um único projeto, fazendo agrupamento destes elementos pela utilização de namespaces, é a mais adequada para meu caso, o que foi também confirmado pelas afirmações feitas pelo Lezinho.

Posso dizer a vocês com certeza que aprendi mais sobre DDD neste e em outros tópicos do GUJ relacionados ao assunto do que havia aprendido durante muito tempo sofrendo as influências erradas em meu emprego.

Estou correndo atraz de todos os livros que foram me dado de referência, vai demorar pra ler todos, mas vai valer a pena.

Muito obrigado e continuo acompanhando o tópico, pois pelo que estou percebendo ainda vem mais opiniões e discussões sadias em cima das questões que levantei neste tópico, por ai.

Num dos meus casos aqui terminei criando um repositório depois que o AR estava cheio demais de métodos de consulta, mas se não fosse isso, eu não teria utilizado repositórios. Acho que como forma de se separar as implementações ele é realmente muito importante, mas é extremamente simples assumir que a classe é o seu próprio repositório.

A instância não perde a sua identificação de entidade, mas a classe, que era “inútil” agora ganhou uma utilidade, ser a fonte das instâncias (dentro da linguagem ela já é isso, mas isso é outra história). O repositório continua existindo, só que agora ele não é uma classe separada, sem estado e que possívelmente vai ficar sendo injetada por alguma entidade externa.

Não entendi quando você diz que a classe era “inútil” Maurício. Normalmente em uma modelagem rica as entidades possuem seus comportamentos de negócio (não estou me referindo a CRUD), por isso não deveria ser anêmica mesmo sem usar AR.

Contudo, o que você disse sobre ActiveRecord é algo que Fowler retratou em PoEAA… com o tempo vai se inchando, e há isso ele atribui sua utilização mais conjunta em projetos com Transaction Script do que com Domaim Model.