Domain Driven Design - Responsábilidades da entidade

91 views
Skip to first unread message

Cassio Pinheiro Almeron

unread,
Dec 27, 2012, 2:21:14 PM12/27/12
to de...@googlegroups.com
Olá

Quando implementamos uma entidade de domínio, definimos nela mesma as regras de negócio, referente ao próprio objeto.
A dúvida é, quando uma regra de negócio depende de outras informações além de sí próprio.

Exemplo:
Em uma entidade chamada usuário, temos por regra de negócio não deixar mais de uma entidade com a propriedade Login igual.

Se for implementar essa validação na entidade, seria necessário que este comunica-se com um repositório para obter esta informação.

Isso é correto?
Ou este tipo de validação é pertinente a outra camada?

Grato
Cássio Almeron

Jonatas Saraiva

unread,
Dec 27, 2012, 3:22:00 PM12/27/12
to de...@googlegroups.com
Cassio, neste caso vc pode criar um serviço de dominio que tem a responsabilidade de verificar se existe algum outro usuario com o mesmo login.

Você cria na camada de dominio o serviço, por exemplo, LoginSerice, que recebe em seus construtor a interface do repositorio e tem um método que verifica se existe algum usuario com o login do usuario que vc pode passar para este método.

Eu resolveria assim.




Em 27 de dezembro de 2012 17:21, Cassio Pinheiro Almeron <cassio...@gmail.com> escreveu:
Isso é correto?
Ou este tipo de validação é pertinente a outra camada?



--
Ats,
Jonatas da Costa Saraiva
Desenvolvedor .Net Ágil
Porto Alegre, RS

"A falta de tempo é desculpa daqueles que perdem tempo por falta de métodos."
Albert Einstein

Felipe Lima

unread,
Dec 27, 2012, 3:39:11 PM12/27/12
to de...@googlegroups.com
Na minha opinião, apenas validação do model não justifica a criação de mais uma camada de abstração, vide frameworks como Ruby on Rails, que integram validação e persistência dentro do model. Caso existam outras regras de persistência mais complexas que exijam uma lógica mais elaborada, dai acredito que faria sentido a criação de um LoginService

-- 
Felipe Lima

--
--
Acesse nosso blog http://devrs.net/
Siga-nos no twitter! http://twitter.com/DevRsNet
--
Antes de criar um novo post, para maior organização do grupo, procure seguir as regras de TAGS: http://devrs.net/regras-da-lista
Para postar para o grupo, envie email para de...@googlegroups.com
Para sair do grupo, envie email para devrs+un...@googlegroups.com

Jonatas Saraiva

unread,
Dec 27, 2012, 3:54:27 PM12/27/12
to de...@googlegroups.com
Concordo contigo Felipe, validação do modelo não justifica mais um nível de abstração. Tanto que em temos os dataannotations para validar o modelo.

Mas vejo que não é uma simples validação, é uma regra de negocio que diz: "usuários não podem ter o mesmo login",  diferente de "o tamanho do nome do usuário não pode ultrapassar 50 caractere".


Felipe Lima

unread,
Dec 27, 2012, 4:15:51 PM12/27/12
to de...@googlegroups.com
Apesar de "usuários não podem ter o mesmo login" não ser tão simples quanto "limite de 50 caracteres para o nome do usuário", é uma validação um tanto quanto recorrente, no sentido que a grande maioria dos sistemas (web) que criamos possuem uma regra assim ou similar. Sinceramente não me lembro se existe DataAnnotations para isso, pois já faz alguns anos que não trabalho com ASP.NET MVC, mas creio que deveria existir. 
Exemplo de validação equivalente em Rails: http://guides.rubyonrails.org/active_record_validations_callbacks.html#uniqueness ou validates_uniqueness_of

-- 
Felipe Lima

Jonatas Saraiva

unread,
Dec 27, 2012, 6:39:32 PM12/27/12
to de...@googlegroups.com
Não tem DataAnnotations para este caso, o que pode ser feiro é customizar um que trabalha com a interface do repositorio de usuário.

Bacana esta solução em Rails. Acho que não temos em .net algo parecido, nem o entity framework da suporte ainda.

Mas esta solução em Rails faz com que a Entidade Accounttenha conhecimento da tecnologia de acesso a dados (ActiveRecord), correto?

Felipe Lima

unread,
Dec 27, 2012, 7:44:21 PM12/27/12
to de...@googlegroups.com
Jonatas,

Correto. Em Rails, não existe distinção entre o model e o repositório. Ambos são representados pela mesma entidade (o model). O ActiveRecord faz o trabalho de conectar o model à respectiva tabela no banco de dados (ORM).

-- 
Felipe Lima

Jonatas Saraiva

unread,
Dec 28, 2012, 6:35:02 AM12/28/12
to de...@googlegroups.com
Bem, para resolver a questão do nosso colega Cassio, podemos ter três abordagens.

  • Criar um Serviço de Domínio que verifica se já existe um usuário com mesmo username
  • Customizar um DataAnnotations, que fará esta verificação
  • Fazer com que a entidade faça a validação
Não existe o certo ou o errado, acho que vc tem que pensar o que vai gerar complexidade desnecessária e descartar. Faça o que for mais simples, você não precisa seguir todas as regras do DDD.


Felipe Lima

unread,
Dec 28, 2012, 12:47:10 PM12/28/12
to de...@googlegroups.com
De acordo :)

-- 
Felipe Lima

Cassio Pinheiro Almeron

unread,
Dec 28, 2012, 1:17:05 PM12/28/12
to de...@googlegroups.com
Olá

Pelo jeito gerei uma discussão para aquecer o grupo, fiquei contente com isso.
Lá vai mais uma continuando o assunto:

Bom, gostei mais da primeira opção do Jonatas.
Mas ai me surgiu agora outra dúvida que me deu um "T" na cabeça.

Desta forma, nos teremos contratos para os repositórios no domínio.
Eu faria a chamada ao serviço de verificar no Set da propriedade Usuario, antes de passar o value para o atributo correspondente, e caso retornasse falso, estouraria uma exception, mantendo o valor original.

Porém, segundo que já li, e ouvi do Giovani Bassi, "persistência não é responsabilidade do domínio".
Dessa forma cheguei a conclusão de que o Domínio não deveria conhecer sequer os contratos para os repositórios.
Então acessar um repositório a partir do domínio de alguma forma se tornou um paradoxo contraditório.
A não ser que o domínio não veja o ILoginService como repositório, mas sua implementação esteja acessando-o.

Não sei.

Obrigado pela atenção de vocês.

Leonardo Lima

unread,
Dec 28, 2012, 6:52:56 PM12/28/12
to de...@googlegroups.com
Ola Cassio,

    vou pegar o bonde andando mas vou tentar ajudar.

De fato o domínio não não é responsável pela persistência, ou seja, a implementação.
Um domínio que tem um usuário que deve ser persistido, deve ter um repositório(se for raiz de agregação) que deve saber o que fazer com este usuário.

A implementação deste repositório deve ficar em um projeto de infra estrutura, que sabe se este sera salvo em banco, arquivo, planilha, web service etc.
Ou seja o domínio tem o repositório que representa a regra(interface), mas não a implementação(classe concreta).

Quanto a validação, eu não recomendo data annotations.
O data annotations é bonitinho para usar com o MVC, valida tanto na interface quanto antes de inserir no banco de dados usando o EF etc.
Mas isto quer dizer que uma entidade de domínio pode ser criada de forma invalida.
Usa o conceito de fábricas do livro do Eric, que pode ser o construtor do objeto, ou no caso da tua regra, pode ser um objeto separado para fabricar o usuário válido.

Na fábrica (seja o construtor ou outro objeto) tu vai validar tudo que tu precisa para o objeto existir, uma vez criado pela fabrica ele será valido em todas as camadas, do controller que pode mandar construir até o banco de dados que persiste. Criando um ponto único para criação e validação evitando a possível replicação das regras, além de ser mais "natural".


Cassio Pinheiro Almeron

unread,
Dec 31, 2012, 10:08:01 AM12/31/12
to de...@googlegroups.com
Olá Leonardro

Estou de acordo.
Já venho trabalhando da forma, onde as propriedades consideradas obrigatórias possuem um parâmetro correspondente no construtor da entidade.
Partindo também do princípio que o objeto nunca deve entrar em um estado inválido.
Qualquer valor inválido setado em uma propriedade é estourada uma exception.
Da mesma forma, no construtor, quando passado um valor em um parâmetro, o objeto sequer nasce.

Jonatas Saraiva

unread,
Jan 2, 2013, 6:21:50 AM1/2/13
to de...@googlegroups.com
Cassio, 

realmente "persistência não é responsabilidade do domínio", mas tenho o entendimento de que isso é relacionado a forma de implementação. O domínio não precisa saber se vc esta usando ADO, Entity Framework, NHibernate  XML ou um MongoDB para fazer a resistência, o Domínio conhece um contrato com o repositório no caso uma interface, e você pode usa-la em uma entidade ou em um serviço de domínio.

Cassio Pinheiro Almeron

unread,
Jan 3, 2013, 3:52:38 PM1/3/13
to de...@googlegroups.com
Jonatas,

De acordo.

O Dominio não pode conhecer como o procedimento técnico de persistência e recuperação é realizado.
Porém, com a afirmação do Giovani Bassi o que eu tinha concluído é que os contratos de repositório sequer fariam parte do Domínio. ou seja, não seria reponsabilidade do mesmo chamar os metodos dos contratos.

Quem mandaria salvar no banco através de contrato?
Por exemplo, uma entidade de NotaFiscal.
Seria um metodo NotaFiscal.Salvar() que chamaria um método de salvar do contrato de repositório, e se passando this como parâmetro?
De quem seria a responsabilidade de chamar o metodo do contrato para "salvar" a entidade?

Obrigado pela atenção

Leonardo Lima

unread,
Jan 3, 2013, 6:10:43 PM1/3/13
to de...@googlegroups.com
Ola Cassio,

   vamos ao teu exemplo.
   A Nota fiscal não deve "se" salvar.

   Por exemplo, usando ASP Net MVC, CRUD simples.
   No construtor do controller tu recebe via Injeção de dependência a implementação do teu IRepositorioDeNotaFiscal (caso a nota seja uma raiz de agregação).


   private readyonly IRepositorioDeNotaFiscal _notas;

   public NotaFiscalController(IRepositorioDeNotaFiscal notas){
         
        this._notas = notas;

  }

   No teu método do controller tu vai ter:

   public ActionResult EmitirNota(parametros){
      
       var entidadeDeNotaFiscalDoDominio = .....
      .....
      .....
      .....

     this._notas.Salvar(entidadeDeNotaFiscalDoDominio);

  }


Note que no exemplo, a entidade nota não sabe quem persiste, o próprio controller não conhece quem persiste, mas ele é responsável neste ponto por orquestrar o fluxo da aplicação.
No caso de regras complexas no lugar de chamar direto o repositório, tu teria um serviço de aplicação ou domínio que montaria a nota pra ti e salvaria.














Cassio Pinheiro Almeron

unread,
Jan 7, 2013, 8:29:18 AM1/7/13
to de...@googlegroups.com
Leonardo

Estou de acordo.

O que posso concluír com isso é que a persistência em sí é a aplicação que orquestra, mas se eu precisar obter informações do repositório, posso ter serviços de Domínio para isto.

Estive testando a sujestão do Jonatas quanto a ter um serviço de domínio para verificar a existência de um login repetido, obtendo essa informação do repositório.

A situação que me surgiu foi a seguinte:

Cada vez que eu vou "editar" um usuário, carrega-se a partir do repositório objeto de domínio do usuário.
Este é convertido para Dto, para trafegar por WCF, e de Dto para ViewModel.
Toda vez que eu obtenho do repositório um usuário, este é instanciado, e quando carrega a propriedade Login, a validação é realizada, (em minha opinião de forma desnecessária, pois estou só carregando).

É assim mesmo?
Dessa vez não vejo outra solução.

Leonardo Lima

unread,
Jan 8, 2013, 6:09:11 PM1/8/13
to de...@googlegroups.com
Então Cassio, 
vamos tentar entender a situação.


Esta validação precisa ocorrer somente no momento da criação de um novo usuário, correto?
Então, a validação tu pode criar utilizando o padrão chamado "especificação" do livro do Evans (http://blog.lambda3.com.br/2008/12/livro-de-ddd-do-evans-de-graca-na-web/).

A criação de um novo usuário deve ser feito utilizando uma fábrica, que deve ser outro objeto em função da validação.
Bom, uma vez criado e persistido o usuário é valido, logo quando tu carrega do banco de dados tu não precisa validar.
No meu caso utilizo um ORM (EF) que ja faz o trabalho sujo de ir ao banco e me trazer o objeto válido.

Mas sim, validar quando retorna do banco não é necessário.

Quanto ao DTO, WCF, etc são casos específicos do teu projeto que não cabe mais ao DDD resolver.


Espero ter ajudado.




Bernardo Bosak de Rezende

unread,
Jan 8, 2013, 7:10:14 PM1/8/13
to de...@googlegroups.com
Oi Leonardo,

Desta forma você está atrelando a validação ao mecanismo de persistência na hora de hidratar os objetos.
Se a validação diz respeito à regra da entidade, porquê não mantê-la dentro do objeto?



2013/1/8 Leonardo Lima <leoli...@gmail.com>



--
Bernardo Bosak de Rezende
http://bernardorezende.net/ - Arquitetura e Desenvolvimento
https://github.com/bernardobrezende/ - GitHub

"The weather-cock on the church spire, though made of iron, would soon be broken by the storm-wind if it did not understand the noble art of turning to every wind."
Heinrich Heine

Leonardo Lima

unread,
Jan 9, 2013, 6:31:15 AM1/9/13
to de...@googlegroups.com
Ola Bernardo,

Não estou com meu livro do Evans comigo, mas verei nele onde ele fala o porque não fazer e te digo as paginas, se não me engano é justamente na parte que ele explica que uma fabrica pode ser o construtor do objeto ou outro objeto de acordo com a complexidade das regras e das responsabilidades envolvidas.

Mas resumindo, quanto uma regra envolve mais de uma entidade diferente tu esta dizendo que esta entidade tem a responsabilidade de conhecer outra.
Não vejo esta regra como "da entidade", mas sim do negocio.
A entidade pode ser criada com qualquer nome o problema não é dela, o negocio é que não pode deixar que duas entidades tenham um mesmo valor numa determinada propriedade.
Sem contar o problema que o Cassio citou de que sempre que tu cria a entidade, seja tela-banco ou banco-tela tu tem a execução da validação, que no sentido banco-tela é irregular, visto que uma vez persistida a entidade ela é válida.



Leonardo Lima

unread,
Jan 10, 2013, 8:19:29 AM1/10/13
to de...@googlegroups.com
Ola Bernardo,

   no livro em português esta na pagina 150, no capitulo de repositórios.
   figura em anexo.
DDD-EVANS.jpg
Reply all
Reply to author
Forward
0 new messages