DDD - Criticas à minha arquitetura.  XML
Índice dos Fóruns » Arquitetura de Sistemas
Autor Mensagem
peerless
GUJ Master
[Avatar]

Membro desde: 22/01/2007 14:52:26
Mensagens: 1391
Localização: Porto Alegre / RS
Offline

Pessoal, bom dia!
Com base nesse tópico: http://www.guj.com.br/posts/list/90694.java , resolvi dar as caras e mostrar um protótipo de arquitetura (baseada em DDD) para ser criticada (sugestões são bem vindas) por vocês e assim todos nós tiramos proveito!
Segue:

Possuo um POJO que recebe um repositório no seu constructor:





Uma interface representando um "repositório genérico"




A interface em sí do "repositório do usuário":



O DAO, veja que não implementei ainda o tratamento da persistência, mas fique a vontade para criar uma outra interface genérica para acesso aos dados o qual o DAO TAMBÉM poderia estar implementando em conjunto com a interface do repositório. Que tal um EntityManager aí ?



Os serviços, aí eu colocaria o Spring para gerenciar as transações e injetar os repositórios, uma interface para embrulhar os serviços tbm seria interessante, ah sim, e talvez um filtro (aop?) para criar os beanzinhos!



Bom, eras isso!

Editado: Modificações conforme sugestões. Remoção do "autenticar", e inclusão de uma consulta para exemplo.

This message was edited 4 times. Last update was at 19/05/2008 07:29:51


follow me
pitacos

"The most problems that teams face are about communication, and all the others are too." - Dan North





[MSN]
sergiotaborda
GUJ Expert
[Avatar]

Membro desde: 22/03/2005 20:57:48
Mensagens: 3433
Offline

Um ponto que eu apontaria é o fato do repositorio estar fazendo autenticação. Isso é no minimo estranho.
Além disso vc está colocando no usuário a responsabilidade de se autenticar, mas na realidade está passando-a para o repositorio. Essa delegação indica que não é do usuário a responsabilidade de autenticar o usuário.
A minha sugestão é que mova esse método para um serviço e o retire do usuário e do repositorio.

Criando sua própria API de Validação



Blog do MiddleHeaven
[WWW]
Leonardo3001
GUJ Ranger

Membro desde: 04/07/2007 18:28:58
Mensagens: 975
Offline

Ruim.

E ruim também é a maioria das discussões sobre DDD que se resumem a "faz aquela arquitetura em camadas de sempre, de acordo com os Patterns J2EE, mas adiciona um Repositório no meio", ou seja, resulta em algo que não tem nada de DDD, mas tem lá o Repositório!. Não preciso nem dizer que isso só adiciona complexidade, sem obter muitos benefícios.

Vamos lá dizer os pontos problemáticos:
1 - Porque eu tenho Usuário e UsuárioLogic? DDD não seria algo mais OO? E portanto, lógica e estado relacionados dentro de um mesma classe?

2- Porque o repositório autentica o usuário? Repositório é para buscar alguma coisa que não se sabe daonde, e depois, com essa coisa em mãos, fazer alguma coisa.

3- Pra que um repositório genérico? Pense nessas coisas depois.

4- Reparou que DAO e Repository possuem o mesmo nível de abstração? Repository deveria ser mais ao nível de usuário, enquanto DAO, ao nível de infraestrutura.

Leonardo Veríssimo
-------------------------------------------------
Objectzilla
[WWW]
peerless
GUJ Master
[Avatar]

Membro desde: 22/01/2007 14:52:26
Mensagens: 1391
Localização: Porto Alegre / RS
Offline

Leonardo3001 wrote:...


E quais são suas idéias para melhorar?

Vamos lá dizer os pontos problemáticos:
1 - Porque eu tenho Usuário e UsuárioLogic? DDD não seria algo mais OO? E portanto, lógica e estado relacionados dentro de um mesma classe?


Entenda por serviço. Ou você estaria gerenciando as transações dentro do repositório ? Como você faria isso ?




3- Pra que um repositório genérico? Pense nessas coisas depois.

Ué. Os métodos são genéricos, ao que me parece .. um repositório é lugar onde se guarda coisas, se se guardam coisas num lugar, então temos comportamentos como adicionar, remover, listar todos.. pq eu estaria replicando isso em todos os repositórios? Como você faria isso?

4- Reparou que DAO e Repository possuem o mesmo nível de abstração? Repository deveria ser mais ao nível de usuário, enquanto DAO, ao nível de infraestrutura.

Discordo. Meu repositório está a nível de abstração de um repositório (veja a interface List por ex), deixei bem claro que não há nenhum método do DAO dentro do DAO de exemplo, e se tiver, certamente quem precisar de um repositório não irá enxergar!

This message was edited 1 time. Last update was at 16/05/2008 10:14:50


follow me
pitacos

"The most problems that teams face are about communication, and all the others are too." - Dan North





[MSN]
Rodrigo Carvalho Auler
Virtual Machine Man

Membro desde: 14/02/2003 15:59:17
Mensagens: 576
Localização: Rio de Janeiro
Offline

As única críticas são:
Realmente o repositório não tem que autenticar o usuário, o repositório poderia ter um método getByLogin() que um service vai usar pra fazer a autenticação.
Eu não faria um UsuarioDAO, teria só um DAO genérico, principalmente se usar o hibernate.
Seria bom criar factories pra criar seus usuários, eu uso o próprio repositório pra isso. Eu criaria um método UsuarioRepositorio.create().

[]'s

Rodrigo Auler
Leonardo3001
GUJ Ranger

Membro desde: 04/07/2007 18:28:58
Mensagens: 975
Offline

peerless wrote:
Leonardo3001 wrote:...


E quais são suas idéias para melhorar?

Vamos lá dizer os pontos problemáticos:
1 - Porque eu tenho Usuário e UsuárioLogic? DDD não seria algo mais OO? E portanto, lógica e estado relacionados dentro de um mesma classe?


Entenda por serviço. Ou você estaria gerenciando as transações dentro do repositório ? Como você faria isso ?



Você está usando Faces ou Struts 2? Então coloque um managed bean/action gerenciado pelo Spring e lá você coloca uma regra de transação. Mas isso é algo que você não deveria se preocupar num primeiro instante


peerless wrote:
3- Pra que um repositório genérico? Pense nessas coisas depois.

Ué. Os métodos são genéricos, ao que me parece .. um repositório é lugar onde se guarda coisas, se se guardam coisas num lugar, então temos comportamentos como adicionar, remover, listar todos.. pq eu estaria replicando isso em todos os repositórios? Como você faria isso?


O fato de um repositório ser um lugar onde guarda coisas, não implica ser um lugar onde você põe as coisas. Repositório só possui buscas.

Isso seria facilmente implementado usando a combinação JPA/Hibernate com Spring, afinal, quem salva é a transação.


peerless wrote:
4- Reparou que DAO e Repository possuem o mesmo nível de abstração? Repository deveria ser mais ao nível de usuário, enquanto DAO, ao nível de infraestrutura.

Discordo. Meu repositório está a nível de abstração de um repositório (veja a interface List por ex), deixei bem claro que não há nenhum método do DAO dentro do DAO de exemplo, e se tiver, certamente quem precisar de um repositório não irá enxergar!



O seu repositório ainda pensa em termos de base de dados, não em negócio. E o fato de ter getById e getAll denota isso. Na prática, do ponto de vista do negócio, ninguém quer trazer todos os dados existentes, nem um dado baseado num identificador artificial. O que o cara do negócio quer mesmo saber são os clientes inadimplentes, os produtos mais vendidos, o que está faltando no estoque e etcetera.

Acho também que o exemplo de autenticação é muito ruim, isso se refere à infraestrutura do sistema, um container Java EE faz isso via configuração.

Poderia mudar ligeiramente o exemplo para um cadastro de usuário que ainda não existe, que tal?

Leonardo Veríssimo
-------------------------------------------------
Objectzilla
[WWW]
cmoscoso
Virtual Machine Man

Membro desde: 23/10/2007 10:08:29
Mensagens: 687
Offline

Leonardo3001 wrote:
O fato de um repositório ser um lugar onde guarda coisas, não implica ser um lugar onde você põe as coisas. Repositório só possui buscas.


Pode esclarecer se você não "pões as coisas" no repositório como faz então?

Leonardo3001 wrote:
O seu repositório ainda pensa em termos de base de dados, não em negócio. E o fato de ter getById e getAll denota isso. Na prática, do ponto de vista do negócio, ninguém quer trazer todos os dados existentes, nem um dado baseado num identificador artificial. O que o cara do negócio quer mesmo saber são os clientes inadimplentes, os produtos mais vendidos, o que está faltando no estoque e etcetera.


Não tem nada de errado com o getById ou getAll em si, pelo contrário getById principalmente é bastante comum. Igualmente comum é as pessoas nao entenderem o papel do repositorio no dominio. Se uma regra for realmente importante para o negócio os conceitos envolvidos serão mapeados em objetos de domínio criados com a responsabilidade de atender essa regra específica.

Por outro lado se cliente, produto e estoque ainda são conceitos importantes para o seu domínio (existem na ubiquitious language) mas o código que implementa como os clientes inadimplentes ou os produtos mais vendidos são obtidos não é importante para o negócio neste caso o repositório é util. O repositorio no domínio é descrito em termos da ubiquitous language mas a ele cabe apenas a responsabilidade de abstrair infraestrutura.

This message was edited 2 times. Last update was at 17/05/2008 10:29:29

[Email]
tnaires
GUJ Master
[Avatar]

Membro desde: 22/12/2003 08:05:58
Mensagens: 1678
Localização: Porto Alegre/RS - Natal/RN
Offline

Concordo com o colega cmoscoso, quando ele discorda da seguinte afirmação do Leonardo3001:
Leonardo3001 wrote:O fato de um repositório ser um lugar onde guarda coisas, não implica ser um lugar onde você põe as coisas. Repositório só possui buscas.

No capítulo sobre Repositórios do livro do Eric Evans, há um trecho que diz:
Eric Evans (DDD, págs 151-152) wrote:For each type of object that needs global access, create an object that can provide the illusion of an in-memory collection of all objects of that type. Set up access through a well-known global interface. Provide methods to add and remove objects, which will encapsulate the actual insertion or removal data in the data store. (...)

Tarso Nunes Aires

Blog - http://cabritin.wordpress.com/
Delicious - http://delicious.com/tnaires
Twitter - @tnaires

peerless
GUJ Master
[Avatar]

Membro desde: 22/01/2007 14:52:26
Mensagens: 1391
Localização: Porto Alegre / RS
Offline

Leonardo3001 wrote:
Você está usando Faces ou Struts 2? Então coloque um managed bean/action gerenciado pelo Spring e lá você coloca uma regra de transação. Mas isso é algo que você não deveria se preocupar num primeiro instante


Ahh, para! Isso aí é um protótipo exemplar, como citei. Não importa que framework mvc eu vou usar. Pode ser até para um ambiente desktop.. Então vc gerencia suas transacoes nas actions? Se não existisse frameworks vc gerenciaria nos servlets, é isso? E se por ventura vc trocar de framework mvc, vai ter que pensar seriamente onde diabos estão sendo gerenciadas as transacoes? Delegar negocio nem sempre é ruim nestes casos.


O fato de um repositório ser um lugar onde guarda coisas, não implica ser um lugar onde você põe as coisas. Repositório só possui buscas.
Isso seria facilmente implementado usando a combinação JPA/Hibernate com Spring, afinal, quem salva é a transação.

os amigos em cima já lhe corrigiram.



O seu repositório ainda pensa em termos de base de dados, não em negócio. E o fato de ter getById e getAll denota isso. Na prática, do ponto de vista do negócio, ninguém quer trazer todos os dados existentes, nem um dado baseado num identificador artificial. O que o cara do negócio quer mesmo saber são os clientes inadimplentes, os produtos mais vendidos, o que está faltando no estoque e etcetera.

Acho também que o exemplo de autenticação é muito ruim, isso se refere à infraestrutura do sistema, um container Java EE faz isso via configuração.

Poderia mudar ligeiramente o exemplo para um cadastro de usuário que ainda não existe, que tal?


Voce ja disse (assim como o SergioTaborda) que o exemplo de autenticacao é ruim. Ainda bem que eu coloquei outros exemplos que poderiam entrar em comentários. Essa critica, nao havia ainda comentado, mas acataria sem problemas.

This message was edited 1 time. Last update was at 17/05/2008 12:44:42


follow me
pitacos

"The most problems that teams face are about communication, and all the others are too." - Dan North





[MSN]
Rodrigo Carvalho Auler
Virtual Machine Man

Membro desde: 14/02/2003 15:59:17
Mensagens: 576
Localização: Rio de Janeiro
Offline

tnaires wrote:No capítulo sobre Repositórios do livro do Eric Evans, há um trecho que diz:
Eric Evans (DDD, págs 151-152) wrote:For each type of object that needs global access, create an object that can provide the illusion of an in-memory collection of all objects of that type. Set up access through a well-known global interface. Provide methods to add and remove objects, which will encapsulate the actual insertion or removal data in the data store. (...)

Ele diz isso, mas isso não é uma verdade imutável. Em várias partes do livro ele defende que não existe receita bolo e que devemos adaptar os padrões e arquiteturas para a realidade da equipe, seja por limitações de infra-estrutura ou requisito maluco ou mesmo por gosto pessoal.

O seu repositório pode estar bem implementado com ou sem um add/remove ou getById.

Por exemplo, se eu crio meus objetos através de uma fábrica ( que pode ou não ser o próprio repositório ), não vejo muita necessidade de ter um método pra adicionar o objeto no repositório.

[]'s

Rodrigo Auler

This message was edited 2 times. Last update was at 17/05/2008 13:42:34

cmoscoso
Virtual Machine Man

Membro desde: 23/10/2007 10:08:29
Mensagens: 687
Offline

Rodrigo Carvalho Auler wrote:
Ele diz isso, mas isso não é uma verdade imutável. Em várias partes do livro ele defende que não existe receita bolo e que devemos adaptar os padrões e arquiteturas para a realidade da equipe, seja por limitações de infra-estrutura ou requisito maluco ou mesmo por gosto pessoal.


Acho que você não entendeu, a verdade imutável neste caso é de que não pode haver add/remove nos repositórios.

Rodrigo Carvalho Auler wrote:
O seu repositório pode estar bem implementado com ou sem um add/remove ou getById.

Se eu crio meus objetos através de uma fábrica ( que pode ou não ser o próprio repositório ), não vejo muita necessidade de ter um método pra adicionar o objeto no repositório.


Eu faco assim geralmente pra salvar entidades pequenas -repositorioCueca.findOrCreate(freiada). Para outros agregados as vezes crio um metodo capaz de incluir ou atualizar o grafico inteiro -repositorioTerno.addOrUpdate(terno)- portanto assumindo o objeto já criado.

Como você faria nesses casos onde a factory não é o repositorio ou mesmo para remover o agregado que nao seja por meio de metodos na interface do repositório?
[Email]
tnaires
GUJ Master
[Avatar]

Membro desde: 22/12/2003 08:05:58
Mensagens: 1678
Localização: Porto Alegre/RS - Natal/RN
Offline

Rodrigo Carvalho Auler wrote:Ele diz isso, mas isso não é uma verdade imutável. Em várias partes do livro ele defende que não existe receita bolo e que devemos adaptar os padrões e arquiteturas para a realidade da equipe, seja por limitações de infra-estrutura ou requisito maluco ou mesmo por gosto pessoal.

O seu repositório pode estar bem implementado com ou sem um add/remove ou getById.

Por exemplo, se eu crio meus objetos através de uma fábrica ( que pode ou não ser o próprio repositório ), não vejo muita necessidade de ter um método pra adicionar o objeto no repositório.

[]'s

Rodrigo Auler

É verdade. Dependendo dos requisitos ( ou pelos outros motivos que você citou ), acho que não teria problema em, por exemplo, eu acessar meu mecanismo de persistência ( um DAO ou um objeto Session do Hibernate ) diretamente da camada de aplicação para persistir meu objeto de negócio, ao invés de criar um add() no repositório e delegar para o referido mecanismo.

Mas não entendi sua colocação sobre a fábrica. Ela tem como função abstrair a criação de novas instâncias de objetos de domínio, sendo assim, não vejo como ela poderia substituir um add() no repositório.

Abraços

This message was edited 2 times. Last update was at 17/05/2008 14:27:12


Tarso Nunes Aires

Blog - http://cabritin.wordpress.com/
Delicious - http://delicious.com/tnaires
Twitter - @tnaires

Rodrigo Carvalho Auler
Virtual Machine Man

Membro desde: 14/02/2003 15:59:17
Mensagens: 576
Localização: Rio de Janeiro
Offline

cmoscoso wrote:Como você faria nesses casos onde a factory não é o repositorio ou mesmo para remover o agregado que nao seja por meio de metodos na interface do repositório?

Não vejo motivos pra factory não ser o próprio repositório, mas mesmo não sendo, ela pode usar os mesmos mecanismos do repositório pra de alguma forma persistir o objeto ao fim de uma transação. Uma outra opção seria Active Record, apesar de alguns não gostarem, não vejo mal em usar se for bem implementado.

tnaires wrote:É verdade. Dependendo dos requisitos ( ou pelos outros motivos que você citou ), acho que não teria problema em, por exemplo, eu acessar meu mecanismo de persistência ( um DAO ou um objeto Session do Hibernate ) diretamente da camada de aplicação para persistir meu objeto de negócio, ao invés de criar um add() no repositório e delegar para o referido mecanismo.

Ser flexivel não é desculpa pra fazer besteira.

tnaires wrote:Mas não entendi sua colocação sobre a fábrica. Ela tem como função abstrair a criação de novas instâncias de objetos de domínio, sendo assim, não vejo como ela poderia substituir um add() no repositório.

Na criação de uma nova instancia ele pode injetar no objeto o que ele precisa saber pra se persistir, se for usar ActiveRecord. Ou , dependendo de como for sua persistência, já colocar seu objeto pra ser persistido ao fim da transação.

[]'s

Rodrigo Auler
Leonardo3001
GUJ Ranger

Membro desde: 04/07/2007 18:28:58
Mensagens: 975
Offline

Peerless,

peço qualquer desculpa se você interpretou minhas declarações como ofensa pessoal, minha intenção era somente emitir opiniões sobre o seu exemplo.

Bom vamos às tréplicas:
com relação ao repositório, eu acho realmente estranho ele ter métodos de salvar. Eu sei que pro Evans não é assim, e que pro Nilsson também não, mas é gosto pessoal mesmo. A razão da minha implicância é que quando peço um objeto para o repositório, este objeto não deixou de existir no repositório, tanto é que as próximas consultas irão trazer o mesmo objeto. Então, por que adicionar um objeto ao repositório se este ainda tem conhecimento daquele?
Talvez porque no mundo real, sem um Hibernate, fazer os objetos se salvarem por mágica seja impossível, ou pelo menos, requer muito trabalho, daí esses metódos estão lá no repositório para não complicar muito nossas vidas. Porém, ainda não deixa de ser esquisito pra mim.

Foi uma mancada eu ter dito que poderia usar actions como camada de serviço. Idealmente, não. E às vezes dá problema em se fazer isso. Mas tem vezes, principalmente quando as actions são POJOs e quando a ação é simples, que eu "quebro o protocolo" e faço da action a camada de serviço. Não acho isso o fim do mundo, principalmente se isso está sendo feito conscientemente. O problema fui eu em transformar a exceção em regra.

É isso.






Leonardo Veríssimo
-------------------------------------------------
Objectzilla
[WWW]
tnaires
GUJ Master
[Avatar]

Membro desde: 22/12/2003 08:05:58
Mensagens: 1678
Localização: Porto Alegre/RS - Natal/RN
Offline

Rodrigo Carvalho Auler wrote:Ser flexivel não é desculpa pra fazer besteira.

Mas não é besteira. Se eu tiver certeza que nunca vou deixar de usar Hibernate no projeto, não há problema em chamar o Session diretamente da camada de aplicação ( embora eu prefira mil vezes mais deixar o repositório "editável", conforme sugerido pela descrição do padrão no livro do Eric Evans ).

Tarso Nunes Aires

Blog - http://cabritin.wordpress.com/
Delicious - http://delicious.com/tnaires
Twitter - @tnaires

 
Índice dos Fóruns » Arquitetura de Sistemas
Ir para:   
Powered by JForum 2.1.8 © JForum Team