DDD - Criticas à minha arquitetura

Talvez não tenha nada ha ver, mas Sergio, você não está se referindo em que a Session do hibernate já seja a abstração necessária para tal e que, qualquer coisa acima disso deva ser tratada pelo repositório?

Tá dificil de entender isso mesmo… bem… vamos por partes… se vc for fazer um sistema hj que utiliza o Hibernate para ORM, vc não teria DAO? Como ficaria então? Explique-se, ai fica melhor de alinharmos um dialogo…
[/quote]

Sergio está correto. Ou vc usa um DAO (JDBC) pra mapear (Data Mapper, lembra?) seus objetos pra banco de dados, cartao perfurado ou seja lá qual for a persistência, ou vc usa Hibernate.

O problema é que muita gente ainda nao entendeu a diferença entre Repositorios e ( DAO / Hibernate )

[quote=fabiocsi]Sergio está correto. Ou vc usa um DAO (JDBC) pra mapear (Data Mapper, lembra?) seus objetos pra banco de dados, cartao perfurado ou seja lá qual for a persistência, ou vc usa Hibernate.

O problema é que muita gente ainda nao entendeu a diferença entre Repositorios e ( DAO / Hibernate )[/quote]

Ai vc se engana… DAO é um padrão, Hibernate, como JDBC é uma tecnologia… vc pode usar perfeitamente um DAO com Hibernate… DAO é justamente isso… uma classe que sabe qual a tecnologia usar pra resolver um determinado problema, abstraindo as outras camadas de conceitos de armazenamento.

Tá dificil de entender isso mesmo… bem… vamos por partes… se vc for fazer um sistema hj que utiliza o Hibernate para ORM, vc não teria DAO? Como ficaria então? Explique-se, ai fica melhor de alinharmos um dialogo…
[/quote]

Uai! ficaria exatamente assim :
Pesquisas: Applicação --> Repositorio --> Hibernate
Edições: Applicação --> Hibernate

[quote]

Pelo que entendi, neste caso, então, o repositorio chama alguma classe utilitária do Hibernate que realiza essa transação com o banco, os inserts, selects da vida…seria isso?[/quote]

O repositorio chama as proprias classes do hibernate. Crias criterias, abre sessões e faz pesquisas. Eventualmente, ele pode também mediar inserts etc… mas isso pode ser feito directamente usando o hibernate.

[quote=rodrigoallemand][quote=fabiocsi]Sergio está correto. Ou vc usa um DAO (JDBC) pra mapear (Data Mapper, lembra?) seus objetos pra banco de dados, cartao perfurado ou seja lá qual for a persistência, ou vc usa Hibernate.

O problema é que muita gente ainda nao entendeu a diferença entre Repositorios e ( DAO / Hibernate )[/quote]

Ai vc se engana… DAO é um padrão, Hibernate, como JDBC é uma tecnologia… vc pode usar perfeitamente um DAO com Hibernate… DAO é justamente isso… uma classe que sabe qual a tecnologia usar pra resolver um determinado problema, abstraindo as outras camadas de conceitos de armazenamento.[/quote]

Hibernate também é um padrão. É a implementação do padrão Domain Store.
DAO e Domain Store são padrões excludentes. Ou vc usa um , ou vc usa outro. Se vc usa DAO, vc não usa Domain Store, e por consequencia não usa hibernate ( nem JPA, que é outra implementação do mesmo padrão)

DAO é um Data Mapper , Domain Store é um gerenciador de perssitencia. Muito mais que um Data Mapper.
Todo o Domain Store contém um DAO.

A relação entre DAO e Domain Store é como entre InputStream e o POI ou iText. InputStrem é para acesso, não faz nada sozinho
É preciso algo que funciona “em cima” dele para criar valor: isso é o gerenciamento dos objetos “não-serializados”.

Repare : Domain Store = Loja/Armazém de Dominio : os objetos que vc manipulam são directamente os do dominio. No DAO vc manipula objetos definidos pelo contrato dele. Podem ser Map, ResultSet, etc… qq coisa, mas nunca podem ser objetos do dominio.

Nesse caso não depende do negócio; como regra geral ids de entities que são root de agregado precisam ser imutaveis e unicas para aquele tipo.

editado: no caso de entities nao-root o id precisa ser unico apenas para aquele agregado.

[quote=fabiocsi]
Sergio está correto. Ou vc usa um DAO (JDBC) pra mapear (Data Mapper, lembra?) seus objetos pra banco de dados, cartao perfurado ou seja lá qual for a persistência, ou vc usa Hibernate.

O problema é que muita gente ainda nao entendeu a diferença entre Repositorios e ( DAO / Hibernate )[/quote]

Acho que você está enganado. Segundo Fowler o DAO é um Table Row Gateway. O problema é que eu nunca vi, incluindo na documentação oficial do padrão, um DAO que se limitasse apenas à isso e não fosse também um Data Mapper. Ao utilizar Hibernate você não precisa mais utilizar o Table Row Gateway mas ainda pode ter necessidade de utilizar o Data Mapper.

Imagine que você tenha um método recuperaMaisAcessado() e que este método faz uma Query no Hibernate. A Query em questão retorna uma lista, porque é o default do Hibernate, mas você só está interessado no elemento e não na lista em si. O código que faz esta conversão (listaMaisAcessados.get(0), basicamente) é um Data Mapper. Além disso você ainda vai ter código que lida com Sessão do Hibernate e este deve estar isolado em um objeto de persistência. Você não precisa usar um DAO para resolver estes problemas mas é uma prática possível, usual e efetiva.

O Hibernate em si é uma implementação de Unit of Work (conforme site oficial do produto) e traz diveras facilidades que eliminam muitas das funções de um Data maper clássico, mas não o substitui completamente.

Em arquitetura de sistemas tudo depende do contexto. Os únicos errados são os que dizem verdades absolutas sem sequer conhecer o problema em questão.

Não entendi ao que se refere com “para tal” mas …
O session do hibernate é uma falha da arquitetura do hibernate. Na tentativa de controlar transações fora do ambiente jee é necessário criar uma forma de interceptar todas as operações. Embora o Transaction controle o ciclo de vida da transação o mecanismo transacionar está dentro do Session.

Isso é uma falha porque parte do principio que todas as operações acontecem dentro de uma unidade de trabalho (unit of work - UoW) que seria o Session.Isso não é verdade na realidade. Unidades de trabalho servem para isso mesmo, controlar o “trabalho”.
Leituras não têm porque estar dentro de uma UoW (embora possam estar , as UoW não existem para resolver esse problema).
Mas o hibernate precisa disto para poder controlar o cache de forma transacional. Sem o cache a performance é ridicula e a utilidade do hibernate é nenhuma. Logo, tudo é feito para proteger o coração que é o cache.
É essa falha de basear tudo no sesson que obriga a utilizar o Open Session in View ( OSiV). O Hibernate como um todo é uma implementação de Domain Store, mas porque ele foi feito para funcionar fora do ambiente EE ele precisa dar controle de transação ( basicamente encapsular o connectio.setAutoCommit(false)). A escolha de criar um Session é uma decisão que implica em problemas na arquitetura da sua aplicação. Em web o defeito é resolvido facilmente, mas não deixa se ser um defeito. Em Swing, vc é obrigado a manter o session sempre aberto , (o que, não faz sentido para começo de conversa) ou a abri-lo sempre que necessário.
Ora ai vc pode pensar que encapsular o acesso ao Hibernate num outro objeto (HibernateHelper) pode ajudar. Pode. Mas não deixa de ser gambiarra. A ideia do Domain Store foi criada para o JPA. O Hibernate foi adapatado da especificação do JPA e mais coisas foram adicionadas. Mas como essas adições não foram padronizadas o negocio saiu meio “feio”.

O repositorio pode tratar com essas idiosincrasias do hibernate, aliás, esse é o seu trabalho. Abrir sessões, transações, criar criteria e manipular o retorno. Só que, mesmo assim, vc estaria incorrendo em usar tecnicas para evitar as gambiarras do proprio hibernate. (por exemplo, transações devem ser um cuting concerne e não devem nunca ser tratadas pelos objetos de dominio)
É preciso ter muito cuidado ao usar hibernate em projetos de vida longa ( +3 anos) porque ele faz muitas coisas, mas isso tem um custo na sua arquitetura. Esse custo é tão importante que converter um sistema para usar Hibernate ou para deixar de usar Hibernate não é uma tarefa simples. Já que as peças do hibernate não estão encapsuladas. Para conseguir isso vc precisa de um framework a mais que o isole desses problemas( tal como Spring), mas ai vc cria dependencia de ainda mais um framework, que, também tem seus problemas. O ponto é: se vc quer usar , estude a coisa primeiro. Não se lance no abismo so porque alguem lhe disse que é o caminho mais rápido. Se não gostar do que vê, crie a sua solução ou procure alternativas.

Uma dúvida idiota de quem está esperando o Domain Driven Design chegar. :stuck_out_tongue:

Esses serviços gerenciados pelo Spring são serviços da camada aplicação (tipo o UsuarioService)?

O controle de sessão, bem como autenticação num sistema, é serviço somente da camada de aplicação? Foi sugerido, bem no início do tópico, que o repositório não autenticasse mais o usuário e tudo fosse movido pra um serviço de aplicação, nesse caso, o usuário não sabe mais se está logado e com a sessão aberta?

E apenas pra fechar, no caso de não usar DAOs, usar apenas o hibernate juntamente com o padrão Repository, a implementação dos repositórios faria parte de duas camadas? Afinal, ela é parte do domínio, mas não é parte da infraestrutura também? Penso isso pq ela está fazendo a persistência dos dados.

Obrigado!

[quote=wagnerfrancisco]Uma dúvida idiota de quem está esperando o Domain Driven Design chegar. :stuck_out_tongue:

Esses serviços gerenciados pelo Spring são serviços da camada aplicação (tipo o UsuarioService)?
[/quote]

Os serviços do Spring são agnosticos , ou seja, podem ser de aplicação ou de dominio.

Não responsabilidade do usuário saber isso. Isso é respnsabilidade do serviço de autenticação.

Não. Repositorios pertencem ao dominio.Quem pertence a infra é o hibernate sozinho.

Isso é, geralmente, um cross-cutting concern e pode ser tratado com técnicas de AOP. No Spring você ode usar o Acegi (ou como quer que estejam chamando essa semana), mas fazer algo com interceptors é bem simples.

O Repositório vai contêr código de infra estrutura (qualquer código que tocar o Hibernate diretamente). Apesar dele pertencer à Camada de Negócios (que é diferente de domínio) ele vai contêr lógica da Camada de ersistência. Como fali antes as vezes isso não é um problema mas as vezes é. Minha dica é deixar a interface do Repositório na Camada de Negócios e sua implementação (um DAO como descrevi antes) na Camada de persistência O nome disso é dependency inversion principle.

sergiotaborda e pcalcado, antes de mais nada obrigado pelas respostas.

[quote=sergiotaborda][quote=wagnerfrancisco]Uma dúvida idiota de quem está esp…
[/quote]

Os serviços do Spring são agnosticos , ou seja, podem ser de aplicação ou de dominio.
[/quote]

Interessante. Quem definirá a qual camada determinado serviço pertence é o código que utiliza ele e não o próprio serviço, correto?

Certo, vou pesquisar mais sobre técnicas pra fazer o serviço de autenticação. Ainda tá meio confuso, a maneira que eu pensava era em deixar o usuário sabendo que estava logado e quando fosse necessário, a verificação seria feita através do próprio objeto usuário. Vejo que me enganei.

Ok.

[quote=pcalcado][quote=wagnerfrancisco]
O controle de sessão, bem como autenticação num sistema, é serviço somente da camada de …
[/quote]
Isso é, geralmente, um cross-cutting concern e pode ser tratado com técnicas de AOP. No Spring você ode usar o Acegi (ou como quer que estejam chamando essa semana), mas fazer algo com interceptors é bem simples.
[/quote]

Logo que li sua apostila sobre o Spring AOP imaginei o emprego dele nessa situação. Vou me inteirar mais sobre isso e também sobre o Acegi, quem sabe fique mais claro pra mim.

[quote=pcalcado]

O Repositório vai contêr código de infra estrutura (qualquer código que tocar o Hibernate diretamente). Apesar dele pertencer à Camada de Negócios (que é diferente de domínio) ele vai contêr lógica da Camada de ersistência. Como fali antes as vezes isso não é um problema mas as vezes é. Minha dica é deixar a interface do Repositório na Camada de Negócios e sua implementação (um DAO como descrevi antes) na Camada de persistência O nome disso é dependency inversion principle.[/quote]

Certo. Essa camada de persistência não seria considerada como infraestrutura também? Talvez eu esteja fazendo confusão, pra mim o básico seria usar apenas as camadas de apresentação, aplicação, domínio e infraestrutura.

Mais uma vez, obrigado!

[quote=wagnerfrancisco]sergiotaborda e pcalcado, antes de mais nada obrigado pelas respostas.

[quote=sergiotaborda][quote=wagnerfrancisco]Uma dúvida idiota de quem está esp…
[/quote]

Os serviços do Spring são agnosticos , ou seja, podem ser de aplicação ou de dominio.
[/quote]

Interessante. Quem definirá a qual camada determinado serviço pertence é o código que utiliza ele e não o próprio serviço, correto?
[/quote]

Entenda que a camada a que alguma classe , objeto, serviço, etc… pertence é completamente irrelavante para o funcionamento do sistema. É apenas relevante para construir o sistema e explicar o sistema. Ou seja, é uma divisão logica, não uma divisão física.
O papel que algo faz no sistema não depende de “onde ele está” porque todo o mundo está na memoria, mas sim “o que ele faz”.
São as responsabilidades da classe/objeto, e as suas interações com outros objetos/classes que dizem a que camada ele pertence.

O Spring é básicamente um IoC. Sem o IoC vc não usa nenhuma das outras funcionalidades dele.
Se vc tem uma interface tipo DataSource que dá acesso a conexões ao banco isso é genérico o suficiente para ser de infra.
Mas se vc usa o mesmo mecanismo para injeta a implementação de um serviço do dominio, isso não muda o facto que o serviço é de dominio.

Essa forma não funciona por dois motivos: primeiro, como já disse, não é responsabilidade do usuário se logar ou saber se está logado. No máximo ele pode saber se foi autenticado ( que é algo diferente) . Por outro lado, manter esse tipo de info no objeto usuário viola o objetivo primário do ter um objeto usuário em primeiro lugar : segurança.
Estude a API JAAS para entender melhor as diferenças subtis entre login (identificação), autenticação, autorização e controle de acesso. A API Acegi do Spring (Spring Security) também pode ser uma base para entender esses conceitos. Mas lembre-se que nenhuma delas é completa …

Phillip,

Nesse caso eu teria que declarar meus métodos de consulta nos DAOs, fazendo com que os mesmos “conhecessem” o negócio da aplicação. Isso não é ruim?

Phillip,

Nesse caso eu teria que declarar meus métodos de consulta nos DAOs, fazendo com que os mesmos “conhecessem” o negócio da aplicação. Isso não é ruim?[/quote]

É sim mas até agora eu nunca vi um caso em que seja possível não colocar alguns conceitos de negócio em um DAO ou lógica de persistência no negócio. Dos dois eu prefiro o primeiro. Se você utiliza coisas como Criteria API com Query Objects o efeito não é tão danoso e dado que o Hibernate concentra a maior parte das regras é possível que o que seu DAO vai ter de lógica é irrelevante.

:arrow: Bom , foi um dos assuntos mais produtivos do GUJ, gostei desse debate !!!

:idea: Apesar que soluções migram para sobreviverem seja por nova implementações, ou inovações e tendências tecnológicas.

:arrow: Todos de parabens excelente , discurssão e embate técnico.

Entendo. Mas eu também acho interessante a idéia de aplicar Strategy nos repositórios, conforme foi sugerido pelo sergiotaborda e outros. Eu manteria a interface mas teria implementações específicas que utilizariam diretamente a tecnologia de persistência para realizar as consultas. Se no meu projeto eu utilizar Hibernate, eu teria uma implementação do repositório que usaria Session + Criteria; caso eu utilizasse JDBC puro, outra implementação usaria frases SQL e um DAO ( aqui, sem métodos de negócio ). Tudo isso, claro, se houvesse risco de mudar a tecnologia de persistência empregada.

[quote=tnaires]
Entendo. Mas eu também acho interessante a idéia de aplicar Strategy nos repositórios, conforme foi sugerido pelo sergiotaborda e outros. Eu manteria a interface mas teria implementações específicas que utilizariam diretamente a tecnologia de persistência para realizar as consultas. Se no meu projeto eu utilizar Hibernate, eu teria uma implementação do repositório que usaria Session + Criteria; caso eu utilizasse JDBC puro, outra implementação usaria frases SQL e um DAO ( aqui, sem métodos de negócio ). Tudo isso, claro, se houvesse risco de mudar a tecnologia de persistência empregada.[/quote]

Ok. Supondo que esse seu Repositório tenha regras de domínio -do contrário não faz diferença para usar um DAO que implementa uma interface Repositório- eu prefiro inverter a dependência do que misturar persistencia ao domínio. De qualquer modo, creio que esse sentimento de flexiblidade é falso (além de quebrar o YAGNI) porque a única maneira de trocar Hibernate por JDBC, por exemplo, é lidando com lazy-loading na mão e isso vai envolver mudar as interfaces do seu repositório.

Como eu ainda não vi nenhum exemplo de Repositório com regras de negócio (não que não exista, eu nunca vi) eu não vejo vantagem nessa abordagem.

Ainda não consegui pensar num caso relativamente “comum” em que Repository não é só apenas um nome para a interface do DAO.