| Autor |
Mensagem |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 24/11/2007 11:02:18
|
bonfarj
Java Ninja
![[Avatar]](/images/avatar/1454ca2270599546dfcd2a3700e4d2f1.jpg)
Membro desde: 28/03/2006 09:55:47
Mensagens: 298
Offline
|
Trabalho no desenvolvimento de um sistema desde 2005. Desde então o sistema cresceu muito e sempre que posso procuro criar formas de otimizar o nosso trabalho, identificando oportunidades de melhorias para que seja possível fazer mais e melhor em menos tempo. O sistema utiliza Struts 1.2 (pretendemos iniciar uma migração para Struts 2 no primeiro semestre de 2008 ) e Hibernate 3.2.
Algo que tem incomodado ultimamemente é a utilização do chamado "Modelo Anêmico". Já melhoramos um pouco, mas algumas classes continuam bastante anêmicas, hehehe. Por exemplo, imaginem que eu quero inserir um objeto da classe Pessoa. Hoje a requisição é recebida por uma classe Action (ex: PessoaAction), que encaminha os dados para uma classe que costumam chamar de "Service" (ex: PessoaService) que valida as informações e chama uma classe estática que fica responsável pela persistência dos objetos com o Hibernate. O maior problema que eu vejo nessa solução é que as regras de negócio da classe Pessoa estão em PessoaService. Na minha visão, PessoaService continuaria existindo apenas para diminuir a dependência do Struts, mas ao invés de validar as regras e chamar a classe estática para persistência, ela apenas invocaria o método (não estático) Pessoa.inserir().
Para tornar isso realidade tenho que solucionar uma questão. Como poderia fazer com que minha classe de modelo Pessoa conseguisse persistir os objetos sem criar uma dependência? Eu andei lendo um pouco sobre injeção de dependências, não sei se este é o caminho da solução. Se alguém souber de algo e puder ajudar eu ficarei muito feliz! :D
Muito obrigado, amigos, bom fim de semana pra vcs!
This message was edited 2 times. Last update was at 26/11/2007 15:11:28
|
IGOR BRITO ALVES
@igoralves
|
|
|
 |
|
|
![[Post New]](/templates/default/images/icon_minipost_new.gif) 24/11/2007 11:22:44
|
sergiotaborda
GUJ Expert
![[Avatar]](/images/avatar/b4a0e0fbaa9f16d8947c49f4e610b549.png)
Membro desde: 22/03/2005 20:57:48
Mensagens: 3420
Offline
|
bonfarj wrote:
Algo que tem incomodado ultimamemente é a utilização do chamado "Modelo Anêmico". Já melhoramos um pouco, mas algumas classes continuam bastante anêmicas, hehehe. Por exemplo, imaginem que eu quero inserir um objeto da classe Pessoa. Hoje a requisição é recebida por uma classe Action (ex: PessoaAction), que encaminha os dados para uma classe que costumam chamar de "Service" (ex: PessoaService) que valida as informações e chama uma classe estática que fica responsável pela persistência dos objetos com o Hibernate. O maior problema que eu vejo nessa solução é que as regras de negócio da classe Pessoa estão em PessoaService. Na minha visão, PessoaService continuaria existindo apenas para diminuir a dependência do Struts, mas ao invés de validar as regras e chamar a classe estática para persistência, ela apenas invocaria o método (não estático) Pessoa.inserir().
Pessoa.inserir é o padrão ActiveRecord. Usar esse padrão não é uma boa. Continue usando a sua classe estática (acho que quiz dizer metodo estático) para fazer a persistencia ou seja arrojado e crie um DAO. Regra de negocios de pessoa... qual seria um exemplo de regra de negocios de pessoa ?
Se essa regra usar entidades que não estão no grafo de pessoa então vc precisa de um Service. Mova para Pessoa todas as regras que dependem apenas do objeto pessoa e daqueles que estão no seu grafo e deixe em service aqueles que usam outras entidades. O nome do service deve ser [objetivo]Service ou [acção]Service e não [entidade]Service por isso foque nas acções/objetivos e agrupe os que são comuns
|
Criando sua própria API de Validação
Blog do MiddleHeaven |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 24/11/2007 11:25:54
|
sergiotaborda
GUJ Expert
![[Avatar]](/images/avatar/b4a0e0fbaa9f16d8947c49f4e610b549.png)
Membro desde: 22/03/2005 20:57:48
Mensagens: 3420
Offline
|
[duplicado]
This message was edited 1 time. Last update was at 24/11/2007 11:29:39
|
Criando sua própria API de Validação
Blog do MiddleHeaven |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 24/11/2007 13:05:05
|
bonfarj
Java Ninja
![[Avatar]](/images/avatar/1454ca2270599546dfcd2a3700e4d2f1.jpg)
Membro desde: 28/03/2006 09:55:47
Mensagens: 298
Offline
|
sergiotaborda wrote:Continue usando a sua classe estática (acho que quiz dizer metodo estático)
Exatamente, não me expressei bem, quis dizer que tenho uma classe composta apenas por métodos estáticos.
sergiotaborda wrote:Regra de negocios de pessoa... qual seria um exemplo de regra de negocios de pessoa ? Se essa regra usar entidades que não estão no grafo de pessoa então vc precisa de um Service. Mova para Pessoa todas as regras que dependem apenas do objeto pessoa e daqueles que estão no seu grafo e deixe em service aqueles que usam outras entidades.
Na verdade o sistema não tem classe Pessoa, foi apenas um exemplo. O que você chamou de grafo são os relacionamentos de dependência? Eu não acho legal essa idéia de passar as coisas para uma classe Service, pois o conhecimento sobre o negócio está deixando as classes de modelo. Por exemplo, eu não posso excluir um objeto da classe Cliente se ele está relacionado a um objeto da classe Pedido. Eu gostaria de um modelo que eu pudesse olhar e entender ali todas as regras de negócio, evitando que elas fiquem espalhadas. Este exemplo com Cliente/Pedido que citei é trivial, mas existem regras que envolvem estados dos objetos que são bem mais complexas, essa descentralização tem trazido problemas.
sergiotaborda wrote:Pessoa.inserir é o padrão ActiveRecord. Usar esse padrão não é uma boa.
Eu não sabia que isso não era uma boa. Se não estou enganado isso é usado no queridinho do momento Ruby On Rails, não sei se traz algum problema que eu ainda não tenha conseguido visualizar. Você pode exemplificar algo nesse sentido?
Abraços e muito obrigado pela sua resposta!
|
IGOR BRITO ALVES
@igoralves
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 24/11/2007 13:51:56
|
Alessandro Lazarotti
Virtual Machine Man
![[Avatar]](/images/avatar/2aaaddf27344ee54058548dc081c6541.jpg)
Membro desde: 21/01/2004 14:12:54
Mensagens: 718
Offline
|
ActiveRecord não é legal para o design de sua modelagem. Pense da seguinte forma, Fornecedores não se salvam nem se deletam.
Se você tenta modelar os objetos de forma que façam sentido para o negócio, os métodos das classes tem que fazer sentido também.
|
... Lezinho
------------------------
twitter: @lazarotti
http://alessandrolazarotti.wordpress.com/
http://jbossbrasil.org/
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 11:28:23
|
sergiotaborda
GUJ Expert
![[Avatar]](/images/avatar/b4a0e0fbaa9f16d8947c49f4e610b549.png)
Membro desde: 22/03/2005 20:57:48
Mensagens: 3420
Offline
|
bonfarj wrote:
sergiotaborda wrote:Regra de negocios de pessoa... qual seria um exemplo de regra de negocios de pessoa ? Se essa regra usar entidades que não estão no grafo de pessoa então vc precisa de um Service. Mova para Pessoa todas as regras que dependem apenas do objeto pessoa e daqueles que estão no seu grafo e deixe em service aqueles que usam outras entidades.
Na verdade o sistema não tem classe Pessoa, foi apenas um exemplo. O que você chamou de grafo são os relacionamentos de dependência?
Não. Em O não ha "relacionamentos", ha objetos contendo objetos. Isso é um grafo.
Eu não acho legal essa idéia de passar as coisas para uma classe Service, pois o conhecimento sobre o negócio está deixando as classes de modelo. Por exemplo, eu não posso excluir um objeto da classe Cliente se ele está relacionado a um objeto da classe Pedido. Eu gostaria de um modelo que eu pudesse olhar e entender ali todas as regras de negócio, evitando que elas fiquem espalhadas. Este exemplo com Cliente/Pedido que citei é trivial, mas existem regras que envolvem estados dos objetos que são bem mais complexas, essa descentralização tem trazido problemas.
Cuidado com o que vc pensa.
1) CRUD não é regra de negocio. Isto que fique bem claro. "Não posso excluir o cliente quando ele tem pedidos" é um regra de consistencia de dados e não de dominio/negocio.
2) A relação entre cliente e pedido não forma um grafo fixo.
pode parecer que c contém a coleção de pedidos, mas não. Aquele método de dominio que mostra a relação entre cliente e pedido
apenas consulta o repositorio de pedidos por aqueles cujo cliente é c. Não ha necessidade do cliente andar com uma lista de pedidos às costas.
Ainda mais quando essa lista muda a qq momento.
DDD dix-lhe para criar o método getPedidos() e outros do mesmo tipo e isso que é uma regra de dominio. Isto não tem nada a ver com CRUD.
O crud do pedido é independente do crud do cliente.
This message was edited 1 time. Last update was at 25/11/2007 11:29:12
|
Criando sua própria API de Validação
Blog do MiddleHeaven |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 12:14:48
|
bonfarj
Java Ninja
![[Avatar]](/images/avatar/1454ca2270599546dfcd2a3700e4d2f1.jpg)
Membro desde: 28/03/2006 09:55:47
Mensagens: 298
Offline
|
Lezinho wrote:ActiveRecord não é legal para o design de sua modelagem. Pense da seguinte forma, Fornecedores não se salvam nem se deletam.
Se você tenta modelar os objetos de forma que façam sentido para o negócio, os métodos das classes tem que fazer sentido também.
Entendo o que você diz, faz sentido. [ ]
Estou começando a acreditar que o que temos hoje no sistema não é tão ruim, embora seja necessário melhorar algumas coisas.
sergiotaborda wrote:Não. Em O não ha "relacionamentos", ha objetos contendo objetos. Isso é um grafo.
(...)
2) A relação entre cliente e pedido não forma um grafo fixo.
Eu realmente fiquei confuso com essa concepção de grafo, não entendi. Imagine que uma classe Pedido possui um atributo Cliente. Isso não pode ser visto como um relacionamento entre as duas classes? Seguindo o que você falou, Cliente pertence ou não ao grafo de Pedido? Se você tiver um link falando sobre grafos nesse contexto eu gostaria de ver, não consegui entender bem.
sergiotaborda wrote:
pode parecer que c contém a coleção de pedidos, mas não. Aquele método de dominio que mostra a relação entre cliente e pedido
apenas consulta o repositorio de pedidos por aqueles cujo cliente é c. Não ha necessidade do cliente andar com uma lista de pedidos às costas.
Ainda mais quando essa lista muda a qq momento.
Agora que eu não entendi mesmo. Necessidade de andar com uma lista? Mas isso não está relacionado a forma como você implementa? Também não entendi o porquê de Cliente não conter uma coleção de pedidos, porque o que você descreveu, para mim, indica claramente que existe um relacionamento bidirecional entre as duas classes.
Abraços a todos!
|
IGOR BRITO ALVES
@igoralves
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 14:07:49
|
feliperod
JavaTeenager
![[Avatar]](/images/avatar/12d836bf64839f987338414ccbec657f.jpg)
Membro desde: 07/11/2006 14:10:54
Mensagens: 184
Offline
|
Acho que essa questão seria facilmente resolvido com o uso de um PessoaRepository.
A classe Pessoa deve conter regras do tipo que elas tem no mundo real. Disso consiste a abstração.
Por exemplo, Pessoa.pedirMercadoriaParaEstoque(String mercadoria). Já o codigo pertinente a salvar uma Pessoa ou não vai no PessoaRepository.
Mas aí fica uma outra dúvida, é bom chamar o repository direto da Action do Struts?
|
Felipe Rodrigues de Almeida
No Twitter: @felipero
www.fratech.net
The Fratech way |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 14:12:55
|
Alessandro Lazarotti
Virtual Machine Man
![[Avatar]](/images/avatar/2aaaddf27344ee54058548dc081c6541.jpg)
Membro desde: 21/01/2004 14:12:54
Mensagens: 718
Offline
|
feliperod wrote:Acho que essa questão seria facilmente resolvido com o uso de um PessoaRepository.
A classe Pessoa deve conter regras do tipo que elas tem no mundo real. Disso consiste a abstração.
Por exemplo, Pessoa.pedirMercadoriaParaEstoque(String mercadoria). Já o codigo pertinente a salvar uma Pessoa ou não vai no PessoaRepository.
Mas aí fica uma outra dúvida, é bom chamar o repository direto da Action do Struts?
Cabe a decisão da equipe, contudo repository faz parte do negócio. Qualquer livro de DDD você vai ler a recomendação de isolar camada de negócio de camada de aplicação (Actions, ManagedBeans, etc), geralmente isso é o mais indicado.
This message was edited 1 time. Last update was at 25/11/2007 14:13:47
|
... Lezinho
------------------------
twitter: @lazarotti
http://alessandrolazarotti.wordpress.com/
http://jbossbrasil.org/
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 14:18:09
|
feliperod
JavaTeenager
![[Avatar]](/images/avatar/12d836bf64839f987338414ccbec657f.jpg)
Membro desde: 07/11/2006 14:10:54
Mensagens: 184
Offline
|
Lezinho wrote:
...
Cabe a decisão da equipe, contudo repository faz parte do negócio. Qualquer livro de DDD você vai ler a recomendação de isolar camada de negócio de camada de aplicação (Actions, ManagedBeans, etc), geralmente isso é o mais indicado.
Concordo contigo em isolar o domain da camada de application. E isso não é nem do DDD só, vem dos Patterns J2EE mesmo e está sendo reforçado no DDD. Mas aí o cara cai na utilização de um Service pra fazer esse isolamento (É o que eu uso, ou utilizo uma Entity chamando o repository). Alguém pode postar um exemplo de como vocês fazem?
|
Felipe Rodrigues de Almeida
No Twitter: @felipero
www.fratech.net
The Fratech way |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 14:27:58
|
Alessandro Lazarotti
Virtual Machine Man
![[Avatar]](/images/avatar/2aaaddf27344ee54058548dc081c6541.jpg)
Membro desde: 21/01/2004 14:12:54
Mensagens: 718
Offline
|
Não existe mal em vc chamar Repositories de um Entity ou Service. Tanto um como outro são da camada de negócio, esta tudo ok.
|
... Lezinho
------------------------
twitter: @lazarotti
http://alessandrolazarotti.wordpress.com/
http://jbossbrasil.org/
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 15:03:33
|
feliperod
JavaTeenager
![[Avatar]](/images/avatar/12d836bf64839f987338414ccbec657f.jpg)
Membro desde: 07/11/2006 14:10:54
Mensagens: 184
Offline
|
Lezinho wrote:Não existe mal em vc chamar Repositories de um Entity ou Service. Tanto um como outro são da camada de negócio, esta tudo ok.
Mas aí caímos no Entity.insert() falado acima. Só que a logica dentro de Entity.insert() seria uma simples chamada ao repository.
A verdade é que o modelo anêmico está mais relacionado com o que a classe não faz do que com o que ela faz. Caso ela esteja fazendo coisas que não estão no seu escopo, aí o problema é de classes obesas, e não anêmicas.
Mas essas discussões são sempre ótimas para reafirmar o conceitos que temos e a forma que fazemos as coisas.
|
Felipe Rodrigues de Almeida
No Twitter: @felipero
www.fratech.net
The Fratech way |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 16:10:04
|
Alessandro Lazarotti
Virtual Machine Man
![[Avatar]](/images/avatar/2aaaddf27344ee54058548dc081c6541.jpg)
Membro desde: 21/01/2004 14:12:54
Mensagens: 718
Offline
|
Mas aí caímos no Entity.insert() falado acima.
Não necessariamente. Um repository não faz apenas CRUD, eles realizam buscas necessárias para os entities. *Nestes e outros casos* um repository dentro de um entity faz todo sentido do mundo.
Outra situação é ocorrer em meio de um processamento de método de negócio, um objeto (um Aggregate) persistir outro objeto (composto pelo Aggregate), ou até mesmo requisitar sua própria persistencia. A grande diferença é o contrato de sua assinatura, ela não faz sentido ter um save ou persist. Mas se em meio a sua lógica for necessário guardar sua informação no repositorio, não te pq não faze-lo.
Normalmente, mas não por regra, os CRUDs acabam por cair nas costas de um Service.
|
... Lezinho
------------------------
twitter: @lazarotti
http://alessandrolazarotti.wordpress.com/
http://jbossbrasil.org/
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 20:11:28
|
sergiotaborda
GUJ Expert
![[Avatar]](/images/avatar/b4a0e0fbaa9f16d8947c49f4e610b549.png)
Membro desde: 22/03/2005 20:57:48
Mensagens: 3420
Offline
|
bonfarj wrote:
sergiotaborda wrote:Não. Em O não ha "relacionamentos", ha objetos contendo objetos. Isso é um grafo.
(...)
2) A relação entre cliente e pedido não forma um grafo fixo.
Eu realmente fiquei confuso com essa concepção de grafo, não entendi. Imagine que uma classe Pedido possui um atributo Cliente. Isso não pode ser visto como um relacionamento entre as duas classes? Seguindo o que você falou, Cliente pertence ou não ao grafo de Pedido? Se você tiver um link falando sobre grafos nesse contexto eu gostaria de ver, não consegui entender bem.
Pedido contém um atributo do tipo Cliente. Sim. Cliente pertence ao grafo de Pedido e eu faço pedido.getCliente().
O cliente do pedido reponde a "Quem fez o pedido?"
Mas se eu quiser responder a "Quais pedidos o cliente fez?" ai eu uso cliente.getPedidos().
Com estas duas coias eu posso responder a "Que pedidos o cliente que fez este pedido, fex?" apenas com pedido.getCliente().getPedidos().
Isto é uma regra de dominio.
O facto de pedido ter um atributo ter um cliente sim pode ser encarado como um relacionamento entre as duas entidades, mas esse relacionamento é "virtual" ou seja, não existe um objeto Relacionamento que tenha um referencia a cada um. (Poderia haver, mas normalmente não ha). O que ha é uma Referencia de pedido a cliente , mas não de cliente a pedidos. Quando executa Cliente.getpedidos() vc está executando uma regra de negocio que é muito mais complexa que pedido.getCliente(). cliente.getPedido() implica num raciocinio "procura os pedidos onde o cliente é this"
Em codigo :
Embora do lado de fora pareça que Set<Pedidos> existe dentro de cliente, ele não existe de fato. Isso é a vantagem de encasulação.
O que tudo isto interessa?
Quando vc salva o pedido , ha um campo na tabela Pedido que diz respeito ao cliente. Logo o sistema tem que averiguar se o cliente está tb salvo. Se não, salva-o ( ou salva-o logo por default e pronto)
Mas quando o sistema salva o cliente ele não salva a coleção de pedidos. Porque ele não salava? porque não ha nenhum atributo desse tipo em cliente.
Então getPedidos() parece igual a getCliente(), mas não são. Mas o objetivo do DDD é exatamente que pareçam, mesmo que internamente não sejam.
Agora que eu não entendi mesmo. Necessidade de andar com uma lista? Mas isso não está relacionado a forma como você implementa? Também não entendi o porquê de Cliente não conter uma coleção de pedidos, porque o que você descreveu, para mim, indica claramente que existe um relacionamento bidirecional entre as duas classes.
!
Se o cliente contivesse um lista de pedidos cada vez que vc salva o cliente salvaria os pedidos e cada vez que retorna um cliente, retorna todos os pedidos tb. Entenda que isso cria um cliclo vicioso. Salvar o pedido salva o cliente que salva o pedido, que salva o cliente ... Claro que a sua ferramente de persistencia pode evitar isso, mas o ponto aqui é que Pedido não pertence ao grafo de cliente. Pedido não especifica o cliente. Mas cliente especifica o pedido. Essa é a diferença.
E não, ninguém anda com uma lista. Sim, depende de como implementa. Mas se vc implementar diferente vai ter muita dor de cabeça por causa do paradoxo que falei antes.
Em termos de banco de modelo E-R existe um relacionamento bidirecional, mas em termos de DDD e OO não. Isso porque não é a mesma coisa vc obter pedidos a partir de um cliente e o cliente ter uma referencia a esses pedidos. E em OO o que conta são as referencias e não os relacionamentos.
Pense assim : vc poderia executar PedidosRepository.findByCliente(Cliente c) sempre que precisasse em qq ponto da aplicação. Mas isso é uma falha de encasulamento. Isso é equivalente a usar o objeto cliente como um DTO e isso é contra a ideia do DDD. É mais claro , e simples , que seja cliente.getPedidos().
Espero ter esclarecido.
This message was edited 1 time. Last update was at 25/11/2007 22:42:55
|
Criando sua própria API de Validação
Blog do MiddleHeaven |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/11/2007 20:30:56
|
bonfarj
Java Ninja
![[Avatar]](/images/avatar/1454ca2270599546dfcd2a3700e4d2f1.jpg)
Membro desde: 28/03/2006 09:55:47
Mensagens: 298
Offline
|
Oi, sergiotaborda, gostei muito do seu último post. Agora eu entendi melhor o que você quis dizer, embora algumas coisas não tenham ficado perfeitamente claras. Atribuo isso a minha inexperiência com DDD, tenho procurado ler sobre o assunto.
Abraços,
|
IGOR BRITO ALVES
@igoralves
|
|
|
 |
|
|