Hibernate e Domain-Driven Design

42 respostas
L

Bom pessoal, depois de ler a famosa discussão
http://guj.com.br/posts/list/60/60916.java
sobre Repositorio x DAO ficou uma coisa martelando em minha cabeça.

Afinal de contas.

Qual é a melhor forma de se utilizar o hibernate em um DDD?

Se o correto é evitar VOs e BOs
é normal eu exibir, em uma camada de apresentação algo como por exemplo

Cliente c = //Obter o cliente de alguma forma para apresentação.

cliente.getFilialEmSaoPaulo().getContato().getEndereco().getCidade();

E para persistir os dados?
No momento em que eu vou cadastrar um cliente em uma determinada “tela faz tudo” em ajax que nela vou salvando os dados dos contatos e seus respectivos endereços. É normal se aproveitar do cascateamento do hibernate para isso e ter por exemplo um método

ClienteRepositorio.salvarCliente(Cliente cliente);

que salvaria todos os meus dados de cliente, também dos seus contatos e respectivos enderecos?

Qual é a forma que vocês fariam?

42 Respostas

A

Hoje eu uso Hibernate dentro do JBoss e faço da forma que vc falou. Só que o que vc faz com o “Repositorio”, eu faço com o DAO.

L

Certo. Mas dessa forma eu estou expondo meu domain model (negócios) na camada de apresentação. Isto é correto?

E se por alguma força maior do destino eu ser obrigado a não utilizar o hibernate… eu serei obrigado a criar um monte de repositórios com alguns métodos que fariam o que o hibernate faz.

Logo eu teria em um certo:

List<Endereco> enderecos = cliente.obterEnderecos();

E , dentro da classe cliente, eu teria uma instancia de um EnderecoRepositorio (ou EnderecoDao) para eu retornar os dados.
Este EnderecoRepositorio teria o método

EnderecoRepositorio.obterEnderecoCliente(Cliente cliente).

E assim com as demais relações que eu tiver no meu modelo de domínio.
Ae então… voltando ao exemplo anterior:

Eu teria de implementar um cascateamento manual.

Vendo dessa forma vcs não acham que um Domain Model acaba de uma certa forma “exigindo” uma ferramenta de persistência?

(Sempre trabalhei com DDD e na maioria das vezes utilizei o hibernate ou similares e quando não utilizei tive bastante problemas desse tipo para resolver. Fico imaginando agora como seria a melhor forma de resolver sem ele ehehehe).

S

A melhor forma é aquela que funciona se vc alterar alguma coisa. Como vc disse se usar o hibernate directamente, e um dia vc deixar de poder usar o hibernate vc tem um problema. Mas se vc usar um objecto intermediário que encapsula o acesso ao repositorio se por detrás dos panos ele usar hibernate ou jpa ou jdbc não interessa ao resto da aplicação. O repositorio tem o proposito:

  1. resolver o problema de localização. É pelo repositorio que os objetos do dominio encontram as entidades.
  2. resolver o mapeamento de agregados*.
    2.1) de isolar o dominio da persistência. Se o software requerer persistencia, ela será encapsulada dentro do repositorio. Mas um repositorio não é um DAO. A persistencia final será da responsabilidade de um DAO

*Agregado é um padrão para criar entidades em que os objetos que lhe são especificos são apenas maniuplados por ela. O repositório tem acesso privilegiado a isso para poder mapeá-los durante a persistência.

O jogo é mais ou menos assim

Uma ação de procura é requisitada ao Repositorio
O Repositorio traduz essa pesquisa em entiddes do dominio.
O repositorio usa um DAO para obter os dados das entidade. Estes dados podem ser dados em várias tabelas ou não.
O repositorio mapeia os dados obtidos do DAO para o objeto da entidade. Por exemplo, endereço é um objeto dentro de cliente, mas na tabela ele é um cojunto de campos no mesmo registro que os outros campos de cliente. O repositorio faz esse trabalho de separar quais dados são de quais objetos.
O repositorio retorna a entidade (ou conjunto de) pretendido.

Repare que o local “fisico” onde os dados estão é responsabilidade do DAO saber e não do Repositorio.
VC poderia ter um HibernateDAO ou um XMLDAO ou um HashMapDAO ou qq outra coisa. O repositorio não se interessa por esses detalhes. Por outro lado o DAO não sabe o que são aquele conjunto de campos que ele recebe. Ele é um “burro de carga” entre o local fisico onde os dados estão persistidos e o repositorio. Apenas isso.

Claro que o Repositorio e o DAO podem ser fundidos, mas isso, quanto a mim, não é flexivel.

L

Então pensando dessa forma como seria o melhor isolamento da camada de persistência?

seria algo como

class Cliente
{
   /*...Inicializações, variáveis, etc...*/
   

   private List<Endereco> enderecos;

   public List<Endereco> obterEnderecos()
   {
      if (enderecos == null) 
         enderecos = EnderecoRepositorio.getEnderecosCliente(this);

      return enderecos;
   }

}

Ae se eu utilizo o hibernate, eu retorno direto a lista de endereços… se não eu não retorno.

Seria mais ou menos assim?

A

Eu prefiro separar os acessos ao repositório/DAO em FACADEs (Session Beans). Na realidade, o que vc está propondo é diferente (Active Record).

L

Taz:

Eu prefiro separar os acessos ao repositório/DAO em FACADEs (Session Beans). Na realidade, o que vc está propondo é diferente (Active Record).

Teria como postar um exemplo?

A

Assim...

@Stateless
public class CepFACADEBean implements CepFACADE {

	@EJB 
	CepDAO cepDAO;

	public Cep persiste(Cep cep) {
		if (cep == null) {
    		throw new IllegalArgumentException("Cep == null");		
    	}
		if (isValido(cep)) {
			return cepDAO.makePersistent(cep);
		}
		return null;
	}

	public void remove(Cep cep) {
		cepDAO.makeTransient(cep);
	}
}

Gostaria de colocar a validação nos próprios Pojos, mas não foi possível devido a um problema com o Hibernate Validator.

S

Seria mais como

class Cliente
{
   
  public Client(String id){
     this.id = id;
   }

  String id; 
  String nome
   List<Endereco> enderecos = new ArrayList<Endereco>();

   public List<Endereco> enderecos(){
      return enderecos;
   }

   public void add(Endereco end){
       enderecos.add(end);
   }
  
}


class ClientRepository {

     DAO dao;

     public static Client  findByID(String id){

         Client c = new Client  (id);
         Map d = dao.getDadosCliente(id); // aqui os dados vêm num map, mas poderia ser outra coisa
         c.nome = d.get("nome");
         c.enderecos = dao.getEnderecoDoCliente(id);
         
         return c;
     }
}
L

Sérgio agora você complicou minha cabeça.

Estamos vendo em isolar a camada de persistência…

Desta sua forma está isolado…
Mas ae não consigo enxergar a utilização do hibernate…

Seguindo este processo. com dao.getDadosCliente(id) retornando um map ou a outra coisa…
no hibernate utilizaríamos o dao.getDadosCliente(id) retornando o próprio cliente?

Mas ae a interface muda. como seria fazer um repositório híbrido?

S

lelis718:
Sérgio agora você complicou minha cabeça.

Estamos vendo em isolar a camada de persistência…

Desta sua forma está isolado…
Mas ae não consigo enxergar a utilização do hibernate…

Seguindo este processo. com dao.getDadosCliente(id) retornando um map ou a outra coisa…
no hibernate utilizaríamos o dao.getDadosCliente(id) retornando o próprio cliente?

Mas ae a interface muda. como seria fazer um repositório híbrido?

:lol: :lol: :lol: Quem quiz usar o hibernate com DDD foi vc , não eu :lol: :lol: 8)

O Hibernate é mais do que um simples ORM e mais do que um DAO, ele é um novo conceito
É um mecanismo de abstração de persistência em banco de dados. Esse mecanismo é muito semelhante ao JPA (aliás é historicamente ao contrário, mas ok)
Esse mecanismo do hibernate é mapeamento entre objectos e banco (ORM) + um mecanismo de controlo de ciclo de vida (em semelhança com os entity beans do EJB) mas só funciona com bancos de dados. A sua sintaxe e mecanismo são directamente relacionados ao SQL e à noção de tabela e campo.

Politica à parte, e no essencial das coisas, existe muito campo de manobra em DDD. Nem os seus criadores concordam na implementação do repositorio. A implementação de um repositorio pode ser tão directa como o uso directo de JDBC (que aliás se percebe que pode ser usado dentro das classes elas mesmas) ou tão indireta com o uso de um DAO que não assume mecanismos de persistencia (ou seja, não parte do principio que existirá um banco de dados, mas apenas um mecanismo de persistência abstracto)
Existem opiniões divergentes quanto a se um repositorio é um dao e vice-versa. Quanto a mim não é a mesma coisa. Um dos pilares da programação OO é a separação de responsabilidade. Ela traz mais classes e complica mais o código, mas simplifica a manutenção e a alteração. Veja, entidade não é um dado, registro não é uma entidade. É por isto que precisamos de mapeamento, mas ele só não chega.

A figura do repositorio em DDD é criada , como já disse, com o objetivo principal de permitir que entidades sejam encontradas por outros objetos do dominio e não com o objetivo de persistência. Repare que nenhuns outros tipos de objetos são obtidos com repositórios. No hibernate se vc tem cliente–>Endereço vc pode pgar todos os clientes (com ou sem o endereço) ou todos os endereços (sem os clientes) já que vc está abstractamente lendo duas tabelas diferentes. Em DDD vc não pode ler os endereços em separados dos clientes , a mesmos que os endereços sejam eles próprios entidade ( como chave) per se. São duas visões bem diferentes.
Por outro lado, veja que DDD é extremamente OO apenas na definição das partes do modelo. Ou seja, DDD é uma filosofia de modelagem, não de implementação. Tanto é que podemos ver exemplos de implementações usando JDBC diretamente( e ao mesmo tempo com a sugestão de usar ORM) mas até de uma forma pouco centralizada - que estariamos à espera de encontrar num programa que usa DAO.

Enfim, vc quer mesmo implementar um repositorio e usar DDD ? Esqueça persistência. DDD é tudo sobre modelar e nada sobre persistência. Em DDD nem tudo é uma entidade (nem tudo tem um ID), mas mesmo assim pode estar numa tabela. Isto é bem diferente da filosofia do JPA/Hibernate.

Provavelmente se usar DDD e depois de ter seus objetos de dominio vc for usar Hibernate/JPA irá acabar com essas classes cheias de annotations. Ora, é neste ponto que não é claro se colocar informações de persistência no dominio é violação de principios ou não é. Alguns dizem que não ( porque as annotations são meta programação) e outros dizem que sim ( porque elas estão vinculadas À classe, para as alterar é preciso alterar a classe). Eu acho que sim, pelo simples delas dependerem do DAO. Imagine que eu tenho um DAO puro JDBC
mas tá dando um trabalho cao para manter. Ai eu decido usar JPA/Hibernate. Mas com isso sou forçado a implementar annotations nos meus objetos de dominio só porque o JPA funciona assim. (sim, eu sei que pode escrever tudo no xml, esse não é o ponto). Se a implementação JPA deu pau e tiver momentaneamente que voltar para o DAO JDBC de que me servem todas aquelas anotações ? De nada. Isso mostra o vinculo que existe entre e o DAO e as anotações ( usadas fora do DAO mas que satisfazem apenas um DAO em particular).

O que eu tentei explicar é a diferença entre a responsabilidade de um Repositório em comparação com a de um DAO, que quanto a mim, não são a mesma. Os DAO que a gente vê por ai ( sobre tudo aquelas genericos que usam Hibernate/JPA por detrás dos panos) são na realidade um hibrido (ou seria mutante?). Eles fazem ambos os trabalhos. Mas em qual camada pertence um objeto que sabe sobre o dominio e sobre os dados persistidos ?
Para forçar a separação é preciso ter os dois.

O Repositorio encapsula todas as regras de relações entre objetos do dominio, em especial de entidades com seus VO , enquanto o DAO encapsula o acesso aos mecanismo de persistência.
Usar hibernate como um mecanismo de persistência dentro de um DAO é sim um sobre-trabalho, mas isso porque a tecnologia do hibernate não está nem ai para os repositorios e os DAO. o hibernate é um mediador completo entre o objeto da entidade e o banco e vice-versa que despresa o DAO.

É uma colisão de filosofias e concerteza complica a cabeça de muita gente.

Provavelmente vc retorna um objeto ClienteMemento, ou alguma coisa assim, que será mapeado para Cliente propriamente dito. Para discutir isto em profundidade tem que estar presente o conceito de Aggregado (Aggregation) para que seja clara a distinção entre entidade e conjunto de campos. Pois só assim faz sentido ter um repositorio (coleção de entidades) e um dao (acesso a conjuntos de campos)

A

Sérgio,

estaria vc dizendo que não é possível implementar DDD com Hibernate!?

Acredito que DDD (“uma filosofia de modelagem”, como vc mesmo disse) pode utilizar Hibernate (uma decisão de implementação).

Realmente, no Hibernate vc pode fazer isso, mas não precisa. Vc poderia criar um DAO apenas para Cliente que retornasse também os Endereços, ignorando assim a existência de um DAO para Endereço. É uma questão de garantir que a implementação esteja adequada à sua “filosofia de modelagem”.

S

Taz:
sergiotaborda:

O que eu tentei explicar é a diferença entre a responsabilidade de um Repositório em comparação com a de um DAO, que quanto a mim, não são a mesma. Os DAO que a gente vê por ai ( sobre tudo aquelas genericos que usam Hibernate/JPA por detrás dos panos) são na realidade um hibrido (ou seria mutante?). Eles fazem ambos os trabalhos. Mas em qual camada pertence um objeto que sabe sobre o dominio e sobre os dados persistidos ?
Para forçar a separação é preciso ter os dois.

Sérgio,

estaria vc dizendo que não é possível implementar DDD com Hibernate!?

não. Não estou dizendo isso. O que estou dizendo é : se separar Repositorio de DAO e Entidade (DDD) de Entidade (de persistência) e tentar usar Hibernate para o DAO de persitencia, vc vai ter problemas de repetição (usando coisas como ClientMemento ou) ou problemas de acoplamento ( usando annotations)
Se não usar o DAO (com ou sem hibernate) e programar o acesso aos dados (com ou sem hibernate) directamente no repositorio vc está misturando responsabilidades. Se um dia precisar mudar o mecanismo de persistencia vai dar trabalho.

Imagine-se um programa cuja persistência é em xml. O programa cresce e agora é preciso usar banco de dados.
Como vc não isolou a persistencia num DAO e fez tudo no repositorio, agora vc tem que programar todos os repositorios de novo. Mas se vc tivesse usado um DAO e uma implementação XMLDAO agora era só implementar um DataBaseDAO e trocar pelo outro.

L

Sim então…
é esse o ponto em que eu iria chegar.

Então não existe um modelo para implementar um DAO utilizando o Hibernate?

Nos meus projetos eu utilizo o DAO e faço implementações sobre o hibernate em cima de um “HibernateDAO” onde faço todo trabalho de sessões do hibernate nesta Dao e retorno, diretamente da DAO, objeto necessário por exemplo o método

Cliente cliente = dao.obterCliente(id);

E então eu tenho alguns problemas em cima do Domain Model onde caio naqueles resultados que postei :

class Cliente  
{  
	/*...Inicializações, variáveis, etc...*/  


	private List<Endereco> enderecos;  

	public List<Endereco> obterEnderecos()  
	{  
		if (enderecos == null)   
			enderecos = EnderecoRepositorio.getEnderecosCliente(this);  

		return enderecos;  
	}  

}

onde sou realmente obrigado a implementar como vc mesmo diz um ActiveRecord.

Agora seria esta a melhor forma de implementação de um domain model com o hibernate? com o padrão de ActiveRecord ?
E então numa situação onde sou obrigado a retirar o hibernate o meu objeto passa a solicitar as informações para os Repositórios…
O que você acha disso?

E

Vamos lá, estou estudando isso e deixe-me ver se sei responder ou ajudar alguma coisa, pq tb to tendo alguma dificuldade de entender esses conceitos, nem tanto de entender mas de ver a coisa toda se encaixando.

O Dao sabe como persistir e recuperar um objeto (não importa onde). O repositório atua no meio de campo entre os objetos de domínio e os dao. OU seja o repositório sabe quais daos instanciar e usar para salvar e/ou recuperar um determinado objeto.

Dessa forma os conceitos são diferentes, o dao tem de se preocupar com banco de dados, xml, arquivo texto, etc, ele carrega mastiga e o repositório gerencia os objetos de domínio e suas agregações. Olhando pelo outro lado, objetos de domínio deveriam trabalhar apenas com o repositório e não precisam saber ou imaginar o q é dao.

No repositório então vc teria um método List<Usuario> getUsuarioComNotaBaixaSemComentario(); (por que sua lógica de negócios exige que vc marque todos os usuários sem comentários e com notas baixas), e dentro do método vc chama o dao, monta a query.

Acho que um dos problemas principais de entender essa abordagem é a dificuldade de ver exemplos práticos disso implementados, enquanto uso de dao com hibernate vc acha montes de exemplos códigos, sugestões, com ddd, vc não acha tanto código e mais a parte teórica. O motivo disso, eu vejo que normalmente usa-se ddd em sistemas maiores e mais complexos, sendo assim difícil de ter um sisteminha de locadora ou biblioteca ou cdteca com essas idéias. Não sei quanto aos outros, mas eu gosto de pegar código e comparar com o q eu faço.

Quem sabe mais favor indicar os erros, rs


S

É isso ai mesmo. Muito bom resumo.

Eu acho que ActiveRecord é um retrocesso.
Eu acho que realmente não é proveitoso/prático usar Hibernate para implementar um DAO. (Porque, como já falei 1) O Hibernate já é um DAO em si mesmo 2) tem o problema do acoplamento das anotações).

Em DDD vc tem que pensar muito bem se Endereço é uma entidade. Se ele precisa realmente ter um ID proprios ou se uma referencia ao seu cliente dono é suficiente. Este gerenciamento é o proprio cerne de DDD e da noção de agregado. Repare que não deve existir um XYZRepositorio a menos que XYZ seja uma entidade (no sentido do DDD e não no sentido de ORM).

Por outro lado vc quer fazer lazy-loading dos endereços. Tudo bem que vc faça isso, mas então crie uma lazy-List e use como se fosse uma outra lista qualquer (melhor). Ou crie um LazyLoader que é usado pela classe cliente e por detrás referencia o DAO e/ou o repositorio (menos bom que o lazy-list, mas melhor que invocar o repositorio diretamente)
Esqueça por um momento o lazy loading e pense que o repositório sempre monta o cliente do zero quando ele é requisitado. Comece por ai, e depois vc encaixa as otimizações.

Enfim ,acho que primeiro é importante ter o modelo bem definido, pois isso é vital para saber quantos e quais os repositorios necessários.

A

Sobre Facades…

Uma aulinha…

http://www.parleys.com/display/PARLEYS/Java+EE+5+Blueprints+(JPA)?showComments=true

Direto da fonte…

http://www.hibernate.org/124.html

Sobre DAOs com Hibernate…

http://www.hibernate.org/328.html

Suas dependências, a grosso modo, ficariam assim:

Cliente -> Facade
Facade -> DAO (Hibernate)
Facade -> Pojos
Facade -> Facade (outro componente)

L

Olá

Só para citar uma outra opinião:

http://www.adam-bien.com/roller/page/abien?entry=jpa_ejb3_killed_the_dao

http://www.adam-bien.com/roller/page/abien?entry=to_layer_or_not_to

https://p4j5.dev.java.net/

Quero deixar claro que não é sempre que concordo com Adam Bien mas taí a opinião dele.

[]s
Luca

S

Taz,será que está dizendo que Repository é um Façade ? Posso até endender isso, mas o repository é só uma parte da historia do DDD. Como vc modelas as entidades ? POJO com anotações PJA ? Se sim, para quê o DAO ?
Como já disse e o Luca deixou confirmado com as suas referencias JPA/Hibernate não precisa do DAO. (Visto de outra forma, o JPA tem um DAO chamado EntityManager e o Hibernate tem o Session)

Entendamos que existe uma questão politica à volta do hibernate. É uma ferramenta facilitadora que pegou o que melhor havia no ejb, jogou independencia de banco e tornou-se um padrão na forma do JPA. Como todos os padrões eles estão ai para não serem usados- afinal EJB foi um padrão que teve que ser muito remodelado para agradar. Mas tem uma pegadinha, nem todas as persistencias são em banco de dados, nem todos os DAO são locais. O famoso problema do objetos desconexos existe porque o JPA herdou do Hibernate uma visão local. O DAO tem um alcance muito superior a isso. Depois um verdadeiro DAO abstrai o acesso a dados e não apenas oacesso a dados no banco relacional. Para aplicações web, que correm num unico servidor ( mesmo onde o clustering pode ser automatico) o fator local do JPA/Hibernate não afeta ninguem. Mas a partir do momento que o sistema é um desktop swing com servidor central o hibernate vai para o espaço. Junto com o JPA. O hibernate é um ORM end-to-end mas funciona apenas para bancos de dados. Poderiamos até pensar em um Session que é façade remoto, ou um que conversa com xml ou outro tipo de persistencia, mas a questão é que a sobre-valorização do Hibernate/JPA pode não ser uma tão boa ideia - afinal nem todo o mundo faz aplicações web.

E vou ter que dizer que nem sempre se quer um codigo esparguete sem layers nem reponsabilidades definidas criado on-the-fly por uma equipa ágil. Às vezes queremos algo que dure, não no sentido que é imutável, mas no sentido que é tão facil de mudar que sempre será moderno e atual.

Acho que que a critica a layiring não cabe em DDD quando a propria teoria é sobre criar um layer completo. Por outro lado, um Façade+DAO é uma super simplificação da intenção do Repositorio do DDD. Pelo menos a meu ver. Mas também , a meu ver, DDD não é tudo isso que dizem… como dissse no principio a implementação de DDD não é muito clara nem para os seus criadores. Por outro lado os escritos dos mesmos sempre mostram um certo span temporal demasiado grande. Frases do tipo ’ algums meses depois concluimos que o modelo precisava ser alterado e remodelá-mos as classes A e B’ - convenhamos que “alguns meses” não é propriamente pouco tempo para uma modelagem. Mas o hype do DDD irá passar ( se é que alguma vez chegou) e todo o mundo irá continuar criados seu programas ágeis sem layers nem daos apenas com a ajuda do JPA e o cuspo das annotations (na versão seguinte JPA terá Criteria, que é mais um mecanismo herdado do Hibernate).

Vamos ver no que dá.

A

Não. Facade é Facade. Repository é Repository. Estou usando Facades.

Sim. POJO com anotações, elas não incomodam tanto. Dê uma olhada no link que passei e entenderá melhor. JPA não é a pancéia, em alguns casos vc precisa fazer acessos mais específicos à base (com Criteria do Hibernate por exemplo). Daí, o DAO.

Sim, e estou perseguindo isso: camadas com responsabilidades bem definidas. Na realidade, é um projeto SOA e estamos utilizando também o JBoss ESB para implementar os serviços em um nível de granularidade maior. Até andei trocando umas idéias sobre Facades com o pessoal da JBoss ESB:

http://www.jboss.com/index.html?module=bb&op=viewtopic&t=115682

Não entendi essa… :roll:

A

Luca:
Olá

Só para citar uma outra opinião:

http://www.adam-bien.com/roller/page/abien?entry=jpa_ejb3_killed_the_dao

http://www.adam-bien.com/roller/page/abien?entry=to_layer_or_not_to

https://p4j5.dev.java.net/

Quero deixar claro que não é sempre que concordo com Adam Bien mas taí a opinião dele.

[]s
Luca

hehehe,

na realidade ele corrobora o que eu disse… ele também usa Facades (Sessions), e ainda quer colocar o código dos DAOs dentro deles (Facades).

S

Embora os padrões existão vc não é obrigado a usá-los
Existem muitos padrões e muitos deles, ou viraram anti-patterns (DTO por exemplo) ou nunca foram realmente
utilizados (EJB EntityBeans) o que levou à criação de novos padrões (JPA, Dependency Container) que resolvem os problemas os anteriores

A

Quais frameworks/camadas vc usa nos seus projetos?

A

Sérgio,

Agora entendi pq Facades (Session Beans) e Repositories são conceitos bem parecidos. O pessoal do Spring simplesmente chama de Repositories o que EJB3 chama de Session Beans.

http://www.parleys.com/display/PARLEYS/Writing+JPA+applications?showComments=true

Tá vendo como padrões podem ajudar, até na comunicação.

Acho que vc exagerou quando disse: “Como todos os padrões eles estão ai para não serem usados”

Imagine que ZONA seria se não existissem padrões de codificação, por exemplo.

Quando vc fala que padrões não servem para nada, vc está falando que todos os profissionais que participam do JCP e de times que implementam suas especificações em empresas como Red Hat, BEA, IBM e Oracle, etc, etc fazem um trabalho inútil e em vão!!! E isso, absolutamente, não é verdade…

S

Hei! Eu nunca disse que eles não servem para nada. O que eu disse é que nem todos eles são usados. As pessoas não se sentem bem/gostam de usar certo padrão. Isso leva a que essas pessoas criem outros padrões, que por resolverem os problemas encontrados nos originais são mais aceites. Mas este ciclo é viciado e sempre existirá um padrão mais evoluido. Sobretudo quando se trata de padrões da industria (EJB,PJA, Hibernate)e não padrões teoricos (Singleton, Factory, etc).

Eu não uso hibernate se quer saber.

Mas o que eu uso ou deixo de usar não tem nada a ver com o assunto.

A

Na boa, acho que tem a ver. Se vc ciritca Hibernate e padrões, deve usar/defender algo melhor. Apresente sua sugestão…

S

Taz:
sergiotaborda:

Mas o que eu uso ou deixo de usar não tem nada a ver com o assunto.

Na boa, acho que tem a ver. Se vc ciritca Hibernate e padrões, deve usar/defender algo melhor. Apresente sua sugestão…

Parece que ha algum mal entendido aqui. Eu não critico o hibernate nem os padrões. O hibernate é uma otima ferramenta para aquilo que se propõe resolver.

A questão é que no contexto do DDD usar annotations é violar a separação de responsabilidade.
No caso de usar annotations vc está implicitamente violando as fronteiras da camada de dominio e da de persistencia. A menos que vc coloque ambos na mesma camada isso é errado.
Então vc pode :

  1. Colocar dominio e persistencia no mesmo saco, anota as classes do dominio com annotations do hibernate/JPA
    usar o Repositorio como mapeador ou
  2. Criar um DAO generico que usa para acessar os dados e o Repositorio para orquestrar a conversa entre o dominio e o DAO. Generico significa que não obriga os objetos que lhe são passados a implementar nenhum contrato extra. Configure o seu DAO de forma independente do dominio. Por exemplo, tamahos de campos da tabela, indices, etc… Se vc puder realizar esta tarefa com hiberante/JPA maravilha, mas não obrigue o seu dominio a se submeter às regras das ferramentas.

o modelo é mais o menos assim

Applicação --usa regras do–> Dominio – que procura entidades usando -> Repositorio --que procura/guarda dados usando–> DAO

DAO --intrepreta comandos para linguagem SQL–> Banco
ou
DAO --intrepreta comandos para linguagem XQuery–> XML
ou
DAO --intrepreta comandos invocação remota --> HttP/RMI/Delegação --> (Servidor) --> DAO (outra implementação)
DAO --intrepreta comandos localmente e lê um cache em memoria

Além de usar o DAO o Repositorio é quem mapeia de/e para objetos conforme as regras do dominio.

A

OK. Seria isso?

Cliente->Pojos (Domínio)->Repositorio->DAO!?

Parece um Active Record, não!?

S

Taz:
sergiotaborda:

o modelo é mais o menos assim

Applicação --usa regras do–> Dominio – que procura entidades usando -> Repositorio --que procura/guarda dados usando–> DAO

OK. Seria isso?

Cliente->Pojos (Domínio)->Repositorio->DAO!?

Não. Porque o Dominio são mais coisas que apenas os Entity. São tb os serviços, por exemplo.
Portanto, não são apenas os Entity que usam o repositorio para encontrar Entitites.

Não.

A

Como não!? Foi o que vc escreveu não foi!?

Outra…

Ops, se os Entity usam repositórios ou DAOs ou seja lá o que for para buscar dados, estamos falando de Active Records.

S

Antes de responder deixe-me perguntar: o objetivo desta conversa … qual é ?

  1. Não confunda DAO com Repository. Achei que neste ponto estaria clara a diferença.
  2. Persistir significa carregar os dados de/guardar dados em meio não volátil. Encontrar/buscar/Procurar não tem nada a ver com persistir.
  3. ActiveRecord é um padrão em que os objetos se persistem a si mesmos, i.e. sem usar DAO nem nenhum outro padrão de dados. A logica de persistencia (load/save) está toda no próprio objeto. Donde, um objeto que não se persista a si mesmo não é um ActiveRecord. Como Entity não se persiste sozinho nem persiste nenhum outro objeto , ele não pode ser um ActiveRecord c.q.d.

Não sei de onde nasceu essa necessidade de inclui o ActiveRecorda na conversa, mas como já disse - e já me estou a repetir muitas vezes - ActiveRecord não é compativel com DDD. Sendo que o topico é sobre DDD esqueça ActiveRecord. Aliás, esqueça que este padrão existe. É uma atrapalhação no caso geral, sua utilidade é muito restricta.

Para deixar bem clara diferença:

// ActiveRecord
public class A {

 // get/set

 public void save(){ // codigo que persiste this}

 public void load() { // codigo que recupera this}

}


// DDD

public class B {

   // get/set 

}

public class BRepository {


public void store(B b){
    // codigo que coloca B disponivel a ser encontrado no metodo find
}

public B find (Object parametro ){
     // codigo que encontra um objeto da classe B com base no parametro
}

}

Se mesmo assim , vc acha que ActiveRecord e DAO são compativeis ou tem sequer algo a ver… tente implementar. rápidamente vc vai ver que 1) ou está duplicando codigo 2) ou está criando codigo redundante
e espero que chegue na conclusão que ao usar ActiveRecord não poderá usar DAO e vice-versa.

A

Seu exemplo é bastante rudimentar e omite o principal. Quem chama os métodos do Repository!?

De acordo com o campo “Assunto:” aí em cima é discutir a melhor implementação Hibernate + Domain-Driven Design.

Vc acha que tem que usar Repositories/DAOs, etc, de dentro de seus Entitys (e isso é ACTIVE RECORD!!!). Eu não acho isso. Prefiro fazer os acessos dos Services (no caso Session Beans) e uso diretamente DAOs pq só tenho dados em BD e é só de persistência em BD que eu preciso. OK?

Desisto. Vc já perdeu o fio da meada e parece bastante perdido.

S

Os Serviços e outros objetos do dominio. Já falei isso antes:
" Applicação --usa regras do–> Dominio – que procura entidades usando -> Repositorio --que procura/guarda dados usando–> DAO "
"Porque o Dominio são mais coisas que apenas os Entity. São tb os serviços, por exemplo. "

O seu problema é que está achando que repository é um façade implementado com EJB stateless.
Isso não é um Repository, é um Service.

Eu já expliquei 3 vezes. Tlv antes de continuar vc devesse ler o livro que vagueia ai pela internet sobre DDD
http://www.infoq.com/news/2006/12/domain-driven-design.Ao menos para não continuar chamando os Entity de ActiveRecord. Já expliquei porque os Entity não são AtiveRecord, mas vou-lhe dar mais um motivo: se entity fosse AtiveRecord para o quê seria necessário o Repository ? (pergunta retórica)

Eu não acho que tem que usar Repository/DAO dentro do Entity. Quem acha isso é o cara que inventou o DDD.
O que eu acho que é que deve existir um DAO e um Repository e não apenas um deles. (Nisso o Evans , nem ninguem do DDD é claro). E nesta prespectiva nenhum dos dois deve usar Hibernate/JPA con annotations. Como implementa DDD com Hibernate ? Não implementa. Ou menos não sem violar o principio de separação de responsabilidade. Mas como eu já disse, se implementou meia boca, funciona e está feliz, esqueça o que eu digo.
Vc prefere usar SessionBeans e DAO , otimo, mas isso não é DDD. Ok?

Eu estou perdido porque estou explicando N vezes a mesma coisa e vc não ainda entendeu e eu não sei porquê vc não entendeu.

[/quote]

A

Se vc se propõe a postar num tópico sobre DDD + Hibernate e a criticar uma solução que nem conhece, deveria pelo menos usar. :wink:

S

Taz:
sergiotaborda:

Eu não uso hibernate se quer saber.

Se vc se propõe a postar num tópico sobre DDD + Hibernate e a criticar uma solução que nem conhece, deveria pelo menos usar. :wink:

Eu poderia entender essa frase como um argumento ad hominem, mas não vou.
Eu não o uso exatamente porque o conheço. Para mim, para aquilo que eu faço ele é limitativo.
Cada caso é um caso, e no meu caso, ele é mais um problema que uma solução.

Eu postei neste tópico relativamente ao DDD porque vários post apresentavam os conceitos de DDD de forma errada, incompleta ou ambígua. Eu só tentei esclarecer esses pontos, com o meu ponto de vista e baseado no que li de DDD por ai.

Não estou criticando nenhuma tecnologia, apenas as escolhas que foram apontadas e a coerência (ou não) dessas escolhas com princípios e padrões básicos.

No fim, quem decide é quem vai implementar.

F

Não está havendo uma confusão sobre a palavra “Entity”?

Realmente em DDD, entity não é um ActiveRecord… é um objeto com ID(uma identidade unica), diferente de um VO(vo do DDD) que não tem ID e só o valor interessa

Por outro lado, na spec ejb 2.1 o EntityBean é um ActiveRecord…

A

felipec:
Não está havendo uma confusão sobre a palavra “Entity”?

Realmente em DDD, entity não é um ActiveRecord… é um objeto com ID(uma identidade unica), diferente de um VO(vo do DDD) que não tem ID e só o valor interessa

Talvez sim. O pessoal confunde as terminologias e não sabe enxergar que “meia dúzia é 6”.

A vida é simples. Veja:

Teminologia do Eric Evans (DDD):

Cliente (delega) -> Service
Service (busca objetos) -> Repository
Service (manipula) -> Aggregates de Entities

Terminologia Java EE/JPA/Hibernate:

Cliente (delega) -> Facade (Session)
Facade (busca objetos) -> DAO
Facade (manipula) -> Pojos que contêm outros Pojos (que a JPA também chama de Entities)

felipec:

Por outro lado, na spec ejb 2.1 o EntityBean é um ActiveRecord…

Não, não é. Ele é instanciado pelo Home.

F

Taz:

pela definição do fowler é sim…

http://martinfowler.com/eaaCatalog/activeRecord.html

A

Se foi isso o que vc entendeu, deve ser mesmo… :wink:

L

Bom… depois de muitas discussões, caimos novamente na
http://guj.com.br/posts/list/60/60916.java

Acho que o foco aqui deu uma escapada…
A discussão central aqui Hibernate e DDD, foi justamente para saber se devo ou não isolar o hibernate do meu Domínio (Não gosto de usar termos como VOs, BOs).
Se devo isolar o hibernate (que na minha opinião é o mais sensato de se fazer) como isolar?

Pelo que percebi, já que o hibernate “carrega” tudo sozinho, todas as minhas relações entre classes no domínio são controladas por ele. Logo para eu utilizá-lo e ao mesmo tempo não depender dele, sou obrigado a fazer um certo mix de funções como eu citei logo no começo da discussão.

class Cliente 
{ 
	/*...Inicializações, variáveis, etc...*/ 


	private List<Endereco> enderecos; 

	public List<Endereco> obterEnderecos() 
	{ 
		if (enderecos == null)  
		enderecos = EnderecoRepositorio.getEnderecosCliente(this); 

		return enderecos; 
	} 

}

Se focando no Hibernate e no DDD eu pergunto.

Este seria o melhor jeito de isolá-lo?
Já que faz-se a pergunta - se meus endereços não foram carregados pelo hibernete, carregue-os.

Sei sim esta é uma das idéias do Active Record, (que ao mesmo tempo em que temo o método save dentro do objeto do domínio, temos também que aparentemente todas as relações estão sendo “automaticamente” persistidas.) e não gosto muito deste padrão, mas seria esta forma uma das mais sensatas?

Até agora vocês não conseguiram me passar uma forma que eu achasse mais viável que esta.

Gostaria de saber, se possível com algum exemplo simples, como vocês fazem o isolamento.

Abraço pessoal!

A

Que tal uma consultoria!? Nem só de idealismo vive um homem… :wink:

S

Vc deve isolar. A questão é: vc consegue ?
No seu código de exemplo não ha referencia nenhuma ao hibernate, logo vc já isolou (!).
O que vc quer mais que se diga ?

Ai vc responde: “mas eu configurei todos os attributos tudo usando anotações só que não escrevi no exemplo” . Bom, então já tem uma referencia ao hibernate. Já não está isolado.

Afinal qual é o problema com a palavra “isolar” ? Isolar é manter distancia, não tocar , não ter conhecimento.
Se vc escreve uma virgula que seja na sua classe cliente porque está usando hiberante , então não está isolado. Vc consegue escrever a classe cliente sem assumir que está usando hibernate ?

A sua classe cliente tem algum método de negocio ? coloque ai o codigo.
Se a sua classe Cliente não tem métodos de negocio esta conversa é inútil porque cliente não é objeto de domínio é um DTO. Nota: métodos que lêm coisas do banco não são métodos de negocio.

Quantas vezes é preciso escrever que aquilo não é um ActiveRecord ???
O que faz um objeto ser activo é ter um método save e um load de si mesmos. Ter lazy-loading (que é o nome da tenica que vc está usando ali) não o faz ser ativo. Está claro isso ?!

E eu já lhe disse logo no inicio da thread para esquecer o lazy-loading. E até lhe expliquei como tornar o loading lazy sem escrever isso explicitamente na classe cliente.
O que é que vc não entendeu ?

Parece que andamos à roda sempre da mesma coisa… assim não vamos lá.

F

sergiotaborda, eu consigo entender perfeitamente quando você diz que ActiveRecord não deve ser levado a sério.

Mas toma cuidado com o que diz. ActiveRecord não tem implementação decente em Java. Não se esqueça de colocar isso nas frases criticando o ActiveRecord.

Dizer que ActiveRecord só funciona para casos simples é um absurdo. ActiveRecord não funciona em Java.

Taz, quanto a ser ActiveRecord ou não, pode ser simples:

class Gato {  // esse é um ActiveRecord
  private ComidaRepository repository;

  Gato(ComidaRepository repository) { ... }

  public List&lt;Comida&gt; getComidaDasUltimasTresSemanas() {
    repository.getComida(this, Period.weeks(3));
  }

  public void salvar() {
    this.repository.salva(this);
  }

  public void remover() {
    this.repository.remove(this);
  }
}

class Gato {  // esse NÃO é um ActiveRecord
  private ComidaRepository repository;

  Gato(ComidaRepository repository) { ... }

  public List&lt;Comida&gt; getComidaDasUltimasTresSemanas() {
    repository.getComida(this, Period.weeks(3));
  }
}

O fato do gato ter ou não as operações de persistência (saber ele mesmo cuidar do seu estado persistente) diz se é ou não um ActiveRecord. O método getComidaDasUltimasTresSemanas() não tem nada a ver com persistencia. Quem chama o metodo num gato, nem sabe se a comida vem de uma List<Comida> ou do banco de dados.

Em ambos os casos, o gato usa um Repositório (que é um conceito de negócio, pertence ao domínio) para recuperar as comidas relacionadas. Mas isso não tem NADA a ver com persistência (portanto não faz com que o gato seja um ActiveRecord), neste caso o Repositório tem a responsabilidade de cuidar das relações entre as duas entidades do domínio: gato e comida.

Mas em uma coisa eu concordo: a diferença em alguns casos é bem sutil e pode até ser discutível.

Criado 28 de agosto de 2007
Ultima resposta 26 de set. de 2007
Respostas 42
Participantes 7