DDD: Regras de negócio nos repositórios?

33 respostas
M

Ontem eu estava assistindo a um vídeo de uma palestra do Giovanni Bassi sobre DDD (http://unplugged.giggio.net/unplugged/post/Video-sobre-Domain-Driven-Design.aspx), em geral achei muito boa mas não consegui engolir uma coisa:
O Giovanni diz que repositórios não podem ter regras de negócio.

Mas o repositório não faz parte da camada de negócios? Nesse caso, por que não poderia ter regras de negócio?

Segundo o que tenho lido, a diferença entre um repositório e um DAO é justamente essa: O DAO é infra-estrutura, e por isso não pode ter regras de negócio. Já o repositório faz parte do negócio, por isso pode executar validações e tudo mais

33 Respostas

Giulliano

Já começa errado dizer que seu domínio esta em uma camada. Esqueça esse negócio de camada. Pense em um domínio de negócio. E nem o repositório e nem ninguém possui a regra de negócio como era feito com os BO (business objects) as regras de negócios estão implícitas no domínio como um todo.

M

Ok… Então quais classes devem validar estas regras?

Giulliano

Cite um exemplo de validação !!!

M

Vejamos…

Em um sistema de hoteis, não pode haver mais de uma conta para o mesmo quarto no mesmo período

Giulliano

Legal…agora qual é o nosso domínio ?

Quarto
Hotel
Despesa
Serviço
Periodo
Reserva
etc…

Um quarto possui várias reservas, cada reserva é composta por um período. Cada reserva só pode conter uma conta por período. Onde isso deveria ser feito ??? Se eu estivesse escrevendo este sistema seria na reserva do quarto, após a reserva ninguém mais pode entar neste quarto até o término do período, o que garante que este período só tera uma conta.

Emerson_Macedo

Tem uma Thread que fala sobre isso e apesar de um pouco antiga tem bastante conteúdo pra te ajudar, creio eu.

http://www.guj.com.br/posts/list/85604.java

[]s

M

magnomp:
Vejamos…

Em um sistema de hoteis, não pode haver mais de uma conta para o mesmo quarto no mesmo período

Num modelo orientado a objetos invariantes sao implementadas advinha, nos objetos. Encapsulamento é seu amigo.

thokk

Pelo pouco que sei de DDD domain driver designer é que vc deixa o modelo anemico de lado e adota as regras de negocio na camada de modelo, onde possui suas entidades.

M

Emerson Macedo,
Eu já havia lido essa thread, foi uma discussão realmente boa

Giulliano,
Isso implica que o quarto tenha que acessar o repositório, para poder consultar as reservas. Correto?
Não há nenhum problema nisso?

Giulliano

magnomp:
Emerson Macedo,
Eu já havia lido essa thread, foi uma discussão realmente boa

Giulliano,
Isso implica que o quarto tenha que acessar o repositório, para poder consultar as reservas. Correto?
Não há nenhum problema nisso?

Sim…se o quarto precisar acessar qualquer informação ele pode recorrer aos repositórios que por sua vez podem recorrer a um DAO se for necessário.

Mas olha só…no mundo real vc não cria um quarto e busca uma reserva para ele. Vocẽ cria uma reserva e associa ela a um quarto disponível.

; )

Alessandro_Lazarotti

Acho radicalismo dizer que repositórios não podem conter regras de negócio, uma vez que eles pertencem ao negócio. O que acontece é que muitos desenvolvedores adotam a implementação em Java onde repositório é uma interface implementada diretamente por um DAO, neste caso regras de negócio na camada de infraestrutura pode não ser uma boa. Mas o crédito disto é da implementação e não do padrão em si.

D

Giulliano:
magnomp:
Emerson Macedo,
Eu já havia lido essa thread, foi uma discussão realmente boa

Giulliano,
Isso implica que o quarto tenha que acessar o repositório, para poder consultar as reservas. Correto?
Não há nenhum problema nisso?

Sim…se o quarto precisar acessar qualquer informação ele pode recorrer aos repositórios que por sua vez podem recorrer a um DAO se for necessário.

; )

Ou seja, abusando da abstração, poderia enxergar o repositório como uma “facade” para um DAO ou outras implementações de consultas a arquivos, banco de dados, WS, etc…?

marvinla

Aproveitando a discução:

imaginem um caso, onde é necessário buscar todos os quartos que estarão disponíveis para uso em um período futuro.
Com certeza esta busca teria um certo grau de complexidade que, inevitavelmente, iria colocar lógica de negocio no repositorio. Se o repositório não tiver acesso a nem isso da lógica de negócio, seria necessário trazer todos os quartos, todas as reservas e o que mais fosse necessário, fazer um processamento via linguagem de programação, o que geraria um overhead grande.

Neste caso, o que é recomendado?

Abraços

marvinla

Daniel_MV:

Ou seja, abusando da abstração, poderia enxergar o repositório como uma “facade” para um DAO ou outras implementações de consultas a arquivos, banco de dados, WS, etc…?

No livro de DDD do Eric Evans (o livro azul) ele diz para enxergarmos os reposiórios como Coleções com métodos epecializados para seu negócio, exemplos:

adicionar
retornarTodosOsQuartos()
retornarQuartosDisponiveis()

etc.

D
marvinla:
Daniel_MV:
Ou seja, abusando da abstração, poderia enxergar o repositório como uma "facade" para um DAO ou outras implementações de consultas a arquivos, banco de dados, WS, etc..?

No livro de DDD do Eric Evans (o livro azul) ele diz para enxergarmos os reposiórios como Coleções com métodos epecializados para seu negócio, exemplos:

adicionar
retornarTodosOsQuartos()
retornarQuartosDisponiveis()

etc.

Então considerando que exista um DAO que já utiliza esse tipo de nomenclatura em vez de termos técnicos (como eu costumo fazer normalmente).

DAOHotel{
void adicionarReserva(Cliente c);
List<Quartos> retornarTodosOsQuartos();
List<Quartos> retornarQuartosDisponiveis();
}

Qual seria a grande vantagem? A não ser isolar negócio da implementação da consulta. Mas isso um Negocio já faz.

NegocioHotel{

List<Quartos> retornarTodosOsQuartos(){

/// Consulta mais regras de negócio.
return new DAOHotel().retornarTodosOsQuartos();

}


}

Ao meu ver o benefício que vejo dos repositórios nesse caso (lembrando que ainda estou tentando entender o DDD) seria essa "facade", tendo uma camada a mais para abstração.

Seria isso?

marvinla
Daniel_MV:
marvinla:
Daniel_MV:
Ou seja, abusando da abstração, poderia enxergar o repositório como uma "facade" para um DAO ou outras implementações de consultas a arquivos, banco de dados, WS, etc..?

No livro de DDD do Eric Evans (o livro azul) ele diz para enxergarmos os reposiórios como Coleções com métodos epecializados para seu negócio, exemplos:

adicionar
retornarTodosOsQuartos()
retornarQuartosDisponiveis()

etc.

Então considerando que exista um DAO que já utiliza esse tipo de nomenclatura em vez de termos técnicos (como eu costumo fazer normalmente).

DAOHotel{
void adicionarReserva(Cliente c);
List<Quartos> retornarTodosOsQuartos();
List<Quartos> retornarQuartosDisponiveis();
}

Qual seria a grande vantagem? A não ser isolar negócio da implementação da consulta. Mas isso um Negocio já faz.

NegocioHotel{

List<Quartos> retornarTodosOsQuartos(){

/// Consulta mais regras de negócio.
return new DAOHotel().retornarTodosOsQuartos();

}


}

Ao meu ver o benefício que vejo dos repositórios nesse caso (lembrando que ainda estou tentando entender o DDD) seria essa "facade", tendo uma camada a mais para abstração.

Seria isso?

Os repositórios podem acessar DAOs convencionais, acessando um banco de dados, pode encapsular o acesso a um WEB Service, um XML, etc. Como disse, como se fosse uma coleção de objetos de um tipo, não importando de onde vem o resultado.
Além disso, para entender melhor o uso de repositórios, é importante também o conceito de Aggregates e Aggregate Roots[1]. Em DDD você tem um repositório para cada Aggregate Root. Este repositório (como unico componente da camada de negocios a enxergar a infra-estrutura) pode conter N DAOs. Os DAOs você tem em uma base de 1 DAO por classe a ser persistida(não necessáriamente...).

Fugindo um pouco do setor de hotelaria, que não conheço, um exemplo mais tradicional:

Classes Pedido e ItemPedido (clássico). O Pedido é seu Aggregate Root (a raiz do Aggregate). Você teria um RepositorioPedido. Porém, poderia ter um DAOPedido e DAOItemPedido, cada um responsável por persistir suas respectivas classes.

[1] http://en.wikipedia.org/wiki/Domain-driven_design#Building_Blocks_of_DDD

fantomas

Concordo com o post anterior.

Só para reforçar, na minha opinião, DAO não é a mesma coisa que Repositorio. DAO se torna interessante quando vc precisa de acessos a vários tipos de banco de dados. Repositorios são para a manipulação dos dados (consultas e alterações), lembrando que se você utilizar DAOs os Repositorios irão depender deles para obter os dados. Regras nos Repositorios só se forem de acesso aos dados (critérios).

O titulo do tópico passa a impressão de que não se sabe exatamente onde as regras serão descritas.

Considero a resposta um pouco complicada de formular tambem.

Na minha opinião tem que analisar bem a regra para perceber onde ela “se encaixa” melhor: Ela pode ser colocada no Repositorio (critério = regra?), nas fachadas, nos serviços, em um local especifico para regras quando existem DTOs envolvidos e principalmente nas entidades. O ideal é que a decisão seja tomada pela equipe no momento de indecisão.

flws

peczenyj

E a diferença entre regra de negócio e regra de domínio?

Giulliano

Daniel_MV:
Giulliano:
magnomp:
Emerson Macedo,
Eu já havia lido essa thread, foi uma discussão realmente boa

Giulliano,
Isso implica que o quarto tenha que acessar o repositório, para poder consultar as reservas. Correto?
Não há nenhum problema nisso?

Sim…se o quarto precisar acessar qualquer informação ele pode recorrer aos repositórios que por sua vez podem recorrer a um DAO se for necessário.

; )

Ou seja, abusando da abstração, poderia enxergar o repositório como uma “facade” para um DAO ou outras implementações de consultas a arquivos, banco de dados, WS, etc…?

Esse abuso esta errado. Repositório NÃO é um facade para o DAO se vc o usa assim ou o enxerga assim esta com dificuldades para entender um repositório. ESQUEÇA que um repositório tenha qualquer ligação com DAO. Se vc conseuir esquecer isso consiguirá pensar melhor. Um repositório pode trazer informações de um request, de um atributo estático, de um arquivo, da memória, a sua função é trazer as informações que eu preciso. DAO é usado para realizar o trabalho sujo, por exemplo, se precisamos ler um arquivo txt, toda a infra estrutura de abrir um File, FileReader e todo o resto fica no DAO, o repositório só precisa trazer estes dados, e se precisar mesclar estes dados com outros dados que estão em um BD, o mesmo método no repositório deve ter a inteligência de buscar essas infomaões adicionais e mesclar todas. Mas nem sempre usamos um DAO, o repositório poderia buscar informações num HttpServletRequest, que não tem nada haver com DAO.

O repositório deve trazer a informação e ter inteligẽncia e capacidade de buscar essa informação nem que seja no inferno (rs).

E para finalizar o repositório reside no DOMÍNIO da sua aplicação, enquanto que o DAO é uma classe de infra estrura.

M

marvinla:
Aproveitando a discução:

imaginem um caso, onde é necessário buscar todos os quartos que estarão disponíveis para uso em um período futuro.
Com certeza esta busca teria um certo grau de complexidade que, inevitavelmente, iria colocar lógica de negocio no repositorio. Se o repositório não tiver acesso a nem isso da lógica de negócio, seria necessário trazer todos os quartos, todas as reservas e o que mais fosse necessário, fazer um processamento via linguagem de programação, o que geraria um overhead grande.

Neste caso, o que é recomendado?

Abraços

Nao tem nada de complexo, mas o que vc chama de regra de negocio na verdade é apenas um criterio de busca. O exemplo é ruim pra explicar DDD porque vc esta criando repositorios pensando em requisitos do ponto de vista do usuario. Mas ninguem precisa criar domain model pra fazer uma visualizacao do banco de dados. DDD nao é uma nova maneira de fazer relatorios ou CRUD.

Mas o que fazer se o domain model precisa confirmar uma reserva e pra isso precisa checar se os quartos estaos disponiveis? Bom, parece mais facil agora ne?

marvinla

mochuara:
marvinla:
Aproveitando a discução:

imaginem um caso, onde é necessário buscar todos os quartos que estarão disponíveis para uso em um período futuro.
Com certeza esta busca teria um certo grau de complexidade que, inevitavelmente, iria colocar lógica de negocio no repositorio. Se o repositório não tiver acesso a nem isso da lógica de negócio, seria necessário trazer todos os quartos, todas as reservas e o que mais fosse necessário, fazer um processamento via linguagem de programação, o que geraria um overhead grande.

Neste caso, o que é recomendado?

Abraços

Nao tem nada de complexo, mas o que vc chama de regra de negocio na verdade é apenas um criterio de busca. O exemplo é ruim pra explicar DDD porque vc esta criando repositorios pensando em requisitos do ponto de vista do usuario. Mas ninguem precisa criar domain model pra fazer uma visualizacao do banco de dados. DDD nao é uma nova maneira de fazer relatorios ou CRUD.

Mas o que fazer se o domain model precisa confirmar uma reserva e pra isso precisa checar se os quartos estaos disponiveis? Bom, parece mais facil agora ne?

Pra mim este é o ponto mais critico de entender: no caso eu teria um metodo acessível pelo menu domain model: quartosDisponiveis(DataInicial, DataFinal). Este método acessaria a fonte de dados atravéz do DAO, WS, o que for para trazer as reservas do período e verificaria quais quartos não estão na lista, estes serão os disponíveis.
Ou, poderia ser feito atravez de uma única instrução SQL, ou mesmo HQL ou Criteria do Hibernate, porém a lógica de verificar quais quartos estão disponíveis estaria sendo codificada na camada de infra.
Isso afetaria a performance, visto que, se fizesse do primeiro modo, teria que, realizar 1 acesso à fonte de dados para buscar TODOS os quartos, 1 acesso para buscar TODAS as reservas do período, e ainda verificar quarto a quarto qual está disponível.
Neste exemplo pode ser banal, mas em um ambiente com um grande volume de dados, isso pode fazer a diferença.

sergiotaborda

Acho que o grande problema aqui é que as pessoas acham que isto

é uma regra de negocio.

Depois dizem que se eu preciso fazer uma pesquisa irada para trazer os quartos que podem ser reservados no periodo em que o sol é ocultado por marte então eu tenho que escrever isso numa super hiper marte SQL matador que executa em 1 segundo… não.

Regras de negocio são coisas como “duas pessoas não podem reservar o mesmo quarto simultaneamente”, como eu forço isto ? Com queris ? Não. Com validadores. AS queries são ferramentas para perguntar, mas não para decidir. Vc cria um validador que consulta o banco e pergunta “tem alguem reservando o quarto neste peridodo” ? e a query vai responder, sim/ não . E o validador vai bloquear o ato de reserva ou não.

As queries matadoras são necessárias para agilizar a resposta À pergunta. Saber fazer a pergunta do jeito certo é muito importante, mas é uma questão de performance, não é uma questão de chegarou não na resposta. Em sistemas antigos pre-SQL isso nem sequer existe. vc faz um while e testa todos os registro na mão.

Portanto, repositorios podem ter regras de negocio ? Não. Repositorios existem para encontrar coisas, fazer (boas) perguntas. Não para decidir, impedir, proibir, controlar…
Agora, significa isso que repositorios ignoram o negocio ? Não. Eles sabem exactamente de que tipo de assunto estamos falando e o valor da pergunta que fazem.
Essa é diferença do DAO… O Dao não tem regras e ignora o negocio. Ele é um serviço de dados (dados, não entidades. Não se chama Entity Access Objet)

E claro que repositorios não são DAO nem façades para daos, nem interfaces de daos, nem coisas nenhuma dessas. Repositório é uma coisa e DAO é outra.
(Eu gostaria de saber quem foi o cretino que espalhou esse conceito de DAO e repositorio é a mesma coisa… ).

P.S. Eu sei quem foi o dito cujo. É uma pergunta retórica.

marvinla

sergiotaborda:

Olá sergiotaborda, obrigado pela resposta. Ajudou ainda mais a clarear um dos pontos mais críticos pra mim.

fantomas

Hahahahahahahahahahahah!

flws

M

Regras de negocio são coisas como “duas pessoas não podem reservar o mesmo quarto simultaneamente”, como eu forço isto ? Com queris ? Não. Com validadores.
(…)
Portanto, repositorios podem ter regras de negocio ? Não. Repositorios existem para encontrar coisas, fazer (boas) perguntas. Não para decidir, impedir, proibir, controlar…
Agora, significa isso que repositorios ignoram o negocio ? Não. Eles sabem exactamente de que tipo de assunto estamos falando e o valor da pergunta que fazem.

Então não existem validações diretamente nos repositórios. Ao invés disso, os repositórios passam a bola para outra classe para fazer as validações antes de salvar as informações. É isso?

sergiotaborda

magnomp:
Regras de negocio são coisas como “duas pessoas não podem reservar o mesmo quarto simultaneamente”, como eu forço isto ? Com queris ? Não. Com validadores.
(…)
Portanto, repositorios podem ter regras de negocio ? Não. Repositorios existem para encontrar coisas, fazer (boas) perguntas. Não para decidir, impedir, proibir, controlar…
Agora, significa isso que repositorios ignoram o negocio ? Não. Eles sabem exactamente de que tipo de assunto estamos falando e o valor da pergunta que fazem.

Então não existem validações diretamente nos repositórios. Ao invés disso, os repositórios passam a bola para outra classe para fazer as validações antes de salvar as informações. É isso?

não. Os repositorios não fazem validações. Quem faz validações são os serviços. ( na realidade quem faz são validadores, e os serviços usam esses validadores) São eles que modificam as coisas, logo eles que precisam se certificar que podem mudar. As validações são controladas nos serviços. Os repositorios servem para ler dados ( aka fazer pesquisas, aka executar queries)

Se houver um dado inválido o serviço aborta e o repositorio nem é chamado.

As actions tb podem fazer validações desde que invocando um validador.

M

Nesse caso, o que é que os repositórios acrescentam ao sistema para justificar o seu uso? Por que não usar DAOs apenas?

M

Voce pode usar DAO apenas, mas faca ele se passar por um repositorio para os objetos de dominio.

M

marvinla:
mochuara:
marvinla:
Aproveitando a discução:

imaginem um caso, onde é necessário buscar todos os quartos que estarão disponíveis para uso em um período futuro.
Com certeza esta busca teria um certo grau de complexidade que, inevitavelmente, iria colocar lógica de negocio no repositorio. Se o repositório não tiver acesso a nem isso da lógica de negócio, seria necessário trazer todos os quartos, todas as reservas e o que mais fosse necessário, fazer um processamento via linguagem de programação, o que geraria um overhead grande.

Neste caso, o que é recomendado?

Abraços

Nao tem nada de complexo, mas o que vc chama de regra de negocio na verdade é apenas um criterio de busca. O exemplo é ruim pra explicar DDD porque vc esta criando repositorios pensando em requisitos do ponto de vista do usuario. Mas ninguem precisa criar domain model pra fazer uma visualizacao do banco de dados. DDD nao é uma nova maneira de fazer relatorios ou CRUD.

Mas o que fazer se o domain model precisa confirmar uma reserva e pra isso precisa checar se os quartos estaos disponiveis? Bom, parece mais facil agora ne?

Pra mim este é o ponto mais critico de entender: no caso eu teria um metodo acessível pelo menu domain model: quartosDisponiveis(DataInicial, DataFinal). Este método acessaria a fonte de dados atravéz do DAO, WS, o que for para trazer as reservas do período e verificaria quais quartos não estão na lista, estes serão os disponíveis.
Ou, poderia ser feito atravez de uma única instrução SQL, ou mesmo HQL ou Criteria do Hibernate, porém a lógica de verificar quais quartos estão disponíveis estaria sendo codificada na camada de infra.
Isso afetaria a performance, visto que, se fizesse do primeiro modo, teria que, realizar 1 acesso à fonte de dados para buscar TODOS os quartos, 1 acesso para buscar TODAS as reservas do período, e ainda verificar quarto a quarto qual está disponível.
Neste exemplo pode ser banal, mas em um ambiente com um grande volume de dados, isso pode fazer a diferença.

Não é um problema de persistencia, mas de design. Se trata de um sistema real vc deve primeiro saber distinguir regras de negocio de estado essencial, estado acidental, logica e validacoes existentes. E sim, saber o que esta fazendo faz toda a diferenca!

M

Voce pode usar DAO apenas, mas faca ele se passar por um repositorio para os objetos de dominio.
Tá, mas na prática, o que diferencia um repositório de um DAO, além do fato de um ficar na camada de domínio e o outro ser infraestrutura?

O que pode ser feito em um repositório que não pode ser feito em um DAO?

M

magnomp:
Voce pode usar DAO apenas, mas faca ele se passar por um repositorio para os objetos de dominio.
Tá, mas na prática, o que diferencia um repositório de um DAO, além do fato de um ficar na camada de domínio e o outro ser infraestrutura?

O que pode ser feito em um repositório que não pode ser feito em um DAO?

Nao estou a par da ultima definicao de DAO, mas repositorios nao precisam fazer nada, sao apenas contratos estabelecidos entre o domain model e o outro lado.

felipewebdf

Fala pessoal, tópico antigo mas queria apenas expressar qual a minha interpretação da diferença entre DAO e Repository e também passar uma ideia para validação de regra de negócio.

Bem como já foi dito a DAO faz parte da infra e repository do domínio, sendo assim a DAO não conhece o Domain, neste caso o repository fica com a responsabilidade de manipular suas Entity, ou seja, os dados vem da DAO (infra) e o repository (Domain) “transcreve” os dados para a Entity.

Falando em regra de negócio, o repository não deve decidir, ele apenas executa a sua função que é manipular as Entity. Validação de regras deve ficar no Serviço, cada serviço deve conter suas regras para manter o domínio coeso.

Uma boa forma de centralizar essas regras são as Specifications. Com esse pattern vocé poderar ter mais liberdade para adicionar ou retirar regras com maior flexibilidade, injetando as Specifications necessárias para cada serviço.

Bem galera, esse são os meus 2 cents na discussão… rs
Abraço!

L

E o JPA, como ficaria nesse caso? As entitys aidan conteriam as anotações, e seriam vistas pelo DAO?

Criado 14 de junho de 2010
Ultima resposta 7 de abr. de 2014
Respostas 33
Participantes 13