DDD: Mais uma dúvida sobre (Repositório na Entity) x Serviço

Salve, salve, galera do GUJ.

Estou desenvolvendo um projeto JSP+Servlets, e estou tentando aplicar os conceitos MVC para camada de apresentação (essa parte está, ok, utilizando diversos Core J2EE e GoF Design Patterns) e gostaria de tentar implementar os conceitos DDD para a camada model.

Li alguns posts, (enooormes! rs) e ainda não vi nenhuma solução para a minha dúvida, por isso estou postando. (Mas se alguem lembrar de algum post, pode me passar o link? rs!). Tenho uma dúvida que deve ser bastante simples para o mais experientes nessa técnica, que é o seguinte:

Em um sistema de eventos, um novo visitante (que é uma pessoa) pode se inscrever em um determinado evento. Esta ação deve cadastrar a pessoa e associa-la a um evento.

De acordo com o pouco que eu conheço de DDD, o repositório de pessoa armazena e recupera as pessoas e o de eventos armazena e recupera os eventos. Isso está, ok. E segundo o mais pouco ainda que eu sei sobre POO, o visitante deve se inscrever no evento, pois é isso que acontece no mundo real, correto?

Minha dúvida é se posso colocar esses repositórios dentro da entidade Pessoa, sendo acionado por um método do objeto visitante (que é uma pessoa), como por exemplo:

Pessoa visitante = new Pessoa();// é hard só para exemplo, ok?
visitante.seInscreverEmEvento(evento); //e dentro desse método eu aciono o repositório de pessoa e o de eventos.

Ou seria melhor colocar essa ação no meu Serviço de controle de eventos? Algo como:

gestorDeEvento.inscrever(visitante, evento); 
/*
lembrando que nesse momento o Repositório de Pessoas deve ser acionado para guardar a nova pessoa. 
Ou seja, deverei ter o repositório de pessoa dentro do serviço de controle de eventos.
*/

Alguma dessas abordagens esta adequada?

A dúvida apenas surgiu pq, pelo meu entendimento, um visitante se inscreve em um evento e não vejo, nesse caso, a necessidade de ter um serviço no meio (ta correto?).

Tenho outras dúvidas, mas por enquanto isso me faria avançar.

Agradeço antecipadamente e fico no aguardo!

Rogério.

Esse projeto é real ou você está fazendo só para treino?
Caso seja real, procure saber com o seu cliente se a Inscrição não deveria ser uma entidade.
Caso não seja real, e você prefira não criar uma entidade Inscrição, eu acharia mais adequado torná-la um serviço.

Não necessariamente.

A abordagem do gestor é mais adquada. “gestor” não precisa ser uma pessoa pode ser um serviço de inscrições.
Se como o tnaires falou vc precisar uma entidade Inscrição vc pode ainda melhora da seguinte forma :

Inscricao ins = gestorDeEvento.inscreve(visitante, evento); 

O visitante não se inscreve porque ele não sabe como. É o sistema que sabe como uma inscrição deve ser criada.
O visitante apenas mostra o seu interesse e escolhe o evento em que se quer inscrever.

Oi rogerio.alcantara,

Estou de acordo com o que tnaires disse.

Mas acho que isso que você está fazendo pode estar relacionado com [b]aggregates[/b], talvez seja porisso que vc esteja achando que a questão não seja resolvida no serviço apesar de participar da solução.

P.S. Lembrando que muitas vezes não existe uma resposta absoluta e sim soluções mais adequadas para determinados problemas, exigindo de nós uma análise mais profunda e ponderada.

[]'s

Eu havia respondido nesta thread mas parece que algo aconteceu com minha mensagem anterior…

Basicamente você não precisa de Repositório neste caso. Você tem as duas instâncias, basta fazer visitante.inscreveSeEm(evento) e deixar o Hibernate/JPA cuidar do resto.

Caso você não use HibernateJPA você pode acabar tendo que usar o repositório como que faz updates nos objetos no banco. Neste caso eu sugiro que voce faá iso no seu Façade, sua Camada de Aplicação. Desta forma voc6e pode ter um método como este, que é chamado pelo seu Servlet/Action/Tela Swing:

public void inscrever(Usuario usuario, Evento evento){
 usuario.inscreveSeEm(evento);
 repositorioUsuario.salva(usuario);
 repositorioEvento.salva(evento);
}

Mas eu sinceramente recomendo que você use Hibernate ou JPA e deixe a persistência automática cuidar disso.

Sobre as formas em si, ninguém vai conseguir te dar uma forma adequada porque não conhecemos direito seu domínio. Não adianta alguém vir aqui e te dizer como modelar um domínio que não conhece, é apenas especulação vazia. Lembre-se que o grande objetivo de Domain Driven Design é utilizar a linguagem do usuário/negócio no código, como seu usuário se refere a este processo? Ele diz que o usuário se inscreve no evento? Então é quase sempre melhor fazer desta forma no software.

Nossa, muito obrigado a todos pelas respostas!

Acompanho o GUJ há algum tempo e sou fã de todos! …principalmente dos blogs do sérgio e do philip! XD

tnaires, sergio, muito obrigado pelas dicas! Apesar de ser um projeto academico, se for bom, poderá entrar em produção, por isso considero um projeto real. E sim, acho que faz todo o sentido essa “ação” retornar uma inscrição! Vou aplicar, valeu!!

fantomas, demorei para responder pq estava pesquisando aki no guj sobre aggregate que vc comentou (hehe!), valeu! Achei a definição em um comentário do cmoscovo aki(http://www.guj.com.br/posts/list/60/85604.java#458264). Mais uma para o cinto de utilidades! ;D

philip, infelizmente, nesse projeto, eu não posso utilizar nenhum framework, estou utilizando apenas JSP+Servlets+DesignPatterns.

Pois é, pensando na tal da Ubiquitous Language, eu achei que ficaria muito mais natural a abordagem

pois ao meu ver, para esse caso, representa melhor a realidade.

Porém essa abordagem, implicaria na entidade pessoa (visitante) possuir uma referencia ao repositorioDeInscricoes, entende? Minha dúvida, é se isso fere algum principio DDD.

Mais uma vez muito obrigado a todos, já foi bastante esclarecedor.

Rogério.

Ferir não fere mas você não precisa disso. Dê uma olhada no código que eu escrevi, você pode chamar o repositório para salvar evento e visitante após o trecho acima.

Você guardou no seu cinto uma cópia do livro de Eric Evans? :wink:

Philip,

Toda vez que você cria uma nova entidade, por exemplo

Que, na verdade, (se não me engano você tinha dito que usava um factory para isso), você implementa isso da segunda maneira

Uma vez criando dessa maneira, todas as dependências são injetadas na classe pessoa (por Spring/Guice ou whatever, injetando repositories e coisas do gênero), para que, por exemplo, esse tipo de operação possa ser feita:

ou

ou

// Alguma operação que seja feita no banco pessoa.seilah();

Diante desse caso, eu gostaria de saber como você resolveria os seguintes problemas:

  • Como ficaria se por exemplo, você fosse buscar uma lista de pessoas no banco e fazer com que esse resultado viesse as entidades já com suas dependências já preenchidas? Como você resolveria essa situação?
  • Além disso, digamos que, pensando em AOP, na minha entidade tenha um pointcut para um aspecto, no caso do Spring, ele precisa ser criado pelo application context (para criar os proxys, essas coisas). Isso poderia ser resolvido se colocassemos uma classe de Service (PessoaService no caso) e, essa mesma ser injetada e daí sim ela viria com todas as features (AOP, transacional, autowiring entre outros). Se a minha entidade possuir todas essas features, como métodos transacionais e aspectos, como que os resultados de uma HQL fariam para possuir essas features, sendo que quem cria isso é o application context do Spring?

Não sei se você entendeu as dúvidas, qualquer coisa eu posto denovo, ficou difícil pra explicar hehe

Tarso

Opa, pode crer que está na lista!

No momento estou me concentrando em me adaptar na plataforma (sou migrante de C#, =P) e conhecer/aplicar Design Patterns. Pensei em tentar abordar, de forma introdutória, DDD, baseando em leituras dinâmicas como os artigos por aew, como os do blog do Philip e do Sérgio. Mas o livro do Erik está na fila, sim, valeu!

Muito obrigado pela dica!

;D

[quote=rogerio.alcantara]Tarso

Opa, pode crer que está na lista!

No momento estou me concentrando em me adaptar na plataforma (sou migrante de C#, =P) e conhecer/aplicar Design Patterns. Pensei em tentar abordar, de forma introdutória, DDD, baseando em leituras dinâmicas como os artigos por aew, como os do blog do Philip e do Sérgio. Mas o livro do Erik está na fila, sim, valeu!

Muito obrigado pela dica!

;D[/quote]
Ah, se você vem do C#, então precisa conhecer esse livro também ( se já não conhece ):

Em Java eu acho isso suicídio.

[quote=Leozin]

  • Como ficaria se por exemplo, você fosse buscar uma lista de pessoas no banco e fazer com que esse resultado viesse as entidades já com suas dependências já preenchidas? Como você resolveria essa situação? [/quote]

Da uma olhada no http://sourceforge.net/projects/hinjector . Ele resolve exatamente isso.

Rafael

[quote=rodrigoy][quote=rogerio.alcantara]
philip, infelizmente, nesse projeto, eu não posso utilizar nenhum framework, estou utilizando apenas JSP+Servlets+DesignPatterns.
[/quote]

Em Java eu acho isso suicídio.[/quote]

Pois é Rodrigo, eu também acho!

Fiquei frustado quando soube que não poderia usar JPA e estou apanhando escrevendo todas queries das DAO’s na unha. =S

Só para eu não ficar “feio na fita” logo nos meus primeiros posts, vou comentar o que acontece:

No curso de pós-graduação que eu faço, foi ministrada uma disciplina de Programação para Web, que abordou apenas JSP e Servlets. E só!

Como avaliação da disciplina, foi solicitado a reformulação do site de um evento sobre Java que a universidade promove anualmente. A avaliação consiste em utilizar apenas o que foi dado em sala de aula + Design Patterns. O melhor projeto, será o novo site do evento.

Posto esse cenário, não me restou outra alternativa a não ser caprichar no MVC e todos os blueprint e GoF Patterns possiveis. Bom, não quero detalhar muito a arquitetura, pois não é o propósito do tópico, porém, acredito (espero!) que, dentro das possibilidades, ela não tenha ficado tão ruim. No final das contas, a camada de apresentação lembra bastante um avô, feio e pobre do struts… hehe! =P

Agora, a minha idéia, éra utilizar DDD para a camada model apenas de forma introdutória para finalidade acadêmica, mesmo. Isso pq não terei como ir a fundo no assunto (lendo o Evans por exemplo) pois além da implementação, estou estudando todos os blueprints e GoF Patterns.

Mas sim, me aprofundar em DDD é um dos meus próximos passos! E de preferência, sendo auxiliado por frameworks consagrados! =T

AH! Mas nem tudo está perdido: estou tentando implementar o melhor desacoplamento entre as camadas possível, para, no futuro, migrar para JSF+Hibernate sem stress! ;D

Mas muito obrigado pela orientação e pela preocupação!

(Desculpem se o post ficou comprido. As vezes sou um pouco verborrágico. =S)

[quote=tnaires]
Ah, se você vem do C#, então precisa conhecer esse livro também ( se já não conhece ):

Sim, tnaires, eu tenho eu esse cara em PDF aki em algum lugar!! XD …até comecei a ler, mas não tive tempo de continuar, dado o prazo para o trabalho e todo o estudo em cima do blueprint e do GoF Patterns!! =S

Mas valeu pela lembrança!!

Um abraço!

[quote=Rafael Steil][quote=Leozin]

  • Como ficaria se por exemplo, você fosse buscar uma lista de pessoas no banco e fazer com que esse resultado viesse as entidades já com suas dependências já preenchidas? Como você resolveria essa situação? [/quote]

Da uma olhada no http://sourceforge.net/projects/hinjector . Ele resolve exatamente isso.

Rafael[/quote]

Falae Rafael tudo bem?

Comecei a ler esse artigo: http://docs.codehaus.org/display/YAN/Transparent+Dependency+Injection+for+Rich+Domain+Objects mas não me ajudou no problema descrito acima.

Não pude acessar esse link que você me passou porque o sourceforge aqui no trampo é bloqueado (vê se pode!)

Sobre esse framework, poderia você me responder uma dúvida:

  • Ele somente faz somente injeção de dependência ou ele pode, por exemplo, criar um objecto complexo “proxiado” já pelo Spring? (com AOP, com transações, autowiring etc)

Eu pensei em fazer algum tipo de repository que, por AOP, poderia identificar se o objeto é um objeto de dominio completo com essa features ou se é só um managed object do JPA (daí nesse caso poderia criar um objeto novo por factory que passaria as informações retornadas do banco pro novo objeto full-featured). Mas acredito que há soluções mais elegantes do que essa.

A ideia do HInjector é interceptar a criacao de entidades gerenciadas pelo JPA / Hibernate, e injetar todas as dependencias. Na implementacao atual para Spring (a qual estou usando no JForum3), voce precisa apenas declarar uma SessionFactory especial, que todo o resto do trabalho é feito automaticamente.

No caso, ao inves de usar a AnnotationSessionFactoryBean do Spring, vc usa

<bean id="sessionFactory" class="org.hinjector.spring.HInjectorAnnotationSessionFactoryBean">

e pimba. Só isso, o resto é magica :wink:

No startup do sistema, as entities vao ser registradas com beans do Spring, entao sim, teoricamente vc pode aplicar regras AOP e etc em cima delas.

Rafael

Eu faria com JPA/Hibernate. Se não houvesse a possibilidade você vai ter que fazer lazy-loading na mãe e todas as vezes que eu tive que fazer isso o código de persistência ficou uma bagunça. Eu não sei se existe alguma técnica simles para lazy loading manual mas o que eu faria seriam métodos como:

Evento recuperaEvento(Long id);
List<Visitante> recuperaVisitantesDoEvento(Evento e); 
Cidade recuperaCidadeDoVisitante(Visitante v);

O problema é que a única classe que sabe qual profundidade necessária no grafo vai ser o Façade. Neste caso o Façade acaba com a responsabilidade de chamar os métodos corretos no Repositório.

Acho que o bom uso de DDD em Java implica necessariamente num framework ORM na maioria dos casos.

[quote=Leozin]

  • Além disso, digamos que, pensando em AOP, na minha entidade tenha um pointcut para um aspecto, no caso do Spring, ele precisa ser criado pelo application context (para criar os proxys, essas coisas). Isso poderia ser resolvido se colocassemos uma classe de Service (PessoaService no caso) e, essa mesma ser injetada e daí sim ela viria com todas as features (AOP, transacional, autowiring entre outros). Se a minha entidade possuir todas essas features, como métodos transacionais e aspectos, como que os resultados de uma HQL fariam para possuir essas features, sendo que quem cria isso é o application context do Spring?[/quote]

Interceptors do Hibernate, se é que o Spring já Não tem algo pronto para isso (o que o Spring não tem?)

[quote=Rafael Steil]
No caso, ao inves de usar a AnnotationSessionFactoryBean do Spring, vc usa

<bean id="sessionFactory" class="org.hinjector.spring.HInjectorAnnotationSessionFactoryBean">

e pimba. Só isso, o resto é magica :wink:

No startup do sistema, as entities vao ser registradas com beans do Spring, entao sim, teoricamente vc pode aplicar regras AOP e etc em cima delas.

Rafael[/quote]

Então, pensando a nível do JPA: Haveria algum tipo de HInjectionEntityManager(Factory)?

Outra coisa, quando você diz “startup do sistema”, você diz quando o application context inicia?

E, em situações como as de lazy-loading, a única forma seria na mão, como o philip mostrou no post anterior?

Poxa, eu nunca fiz DDD na prática porque, como SEMPRE uso Spring, veria problemas quando juntasse IoC + ORM

Que serviços do spring você usa nas sua classes? A menos que você esteja usando AOP para lógica de negócios eu não consigo pensar em muitos casos onde simplesmente interar transações do Spring com Hibernate (vários exemplos no Google) seja suficiente. De qualquer modo aspectos com regras de negóios não são exatamente o melhor para Domain Driven Design, creio.