DDD - Criticas à minha arquitetura

90 respostas
peerless

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

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

package com.site.domain.model.entity;

import java.io.Serializable;

import com.site.domain.model.repository.UsuarioRepository;

public class Usuario extends Pessoa implements Serializable {
	private static final long serialVersionUID = 1L;
	
	private Long id;
                private String login;
	private String password;
	private boolean isAdministrator;
	
	//transient
	private UsuarioRepository repository;
	
	public Usuario(UsuarioRepository repository) {
		this.repository = repository;
	}
	
//behaviour
        public List<Mensagem> listarMensagensEnviadasPorPeriodo(Date start, Date end) {
              return repository.listarMensagensEnviadasPorPeriodo(start, end);
        }

/*
        Aqui por ex, eu poderia ter outros comportamentos, por ex:
              public List<Historico> listarHistoricosDeLogin() { }
              public List<Log> listarLogsDeAcesso();

             
               etc. Entre outros comportamentos referentes ao USUÁRIO, os quais o repositório se encarregaria de resolver.
*/
	
	public String getLogin() {
		return login;
	}
	public void setLogin(String login) {
		this.login = login;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public boolean isAdministrator() {
		return isAdministrator;
	}
	public void setAdministrator(boolean isAdministrator) {
		this.isAdministrator = isAdministrator;
	}

	public Long getId() {
		return id;
	}
	
	public void setId(Long id) {
		this.id = id;
	}
}

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

package com.site.domain.model.repository;

import java.io.Serializable;
import java.util.List;

public interface Repository<T, ID extends Serializable> {
    T get(ID id);
    List<T> getAll();
    
    T add(T bean);
    void remove(T bean);
   
}

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

package com.site.domain.model.repository;

import com.site.domain.model.entity.Usuario;

public interface UsuarioRepository extends Repository<Usuario, Long> {
         public List<Mensagem> listarMensagensEnviadasPorPeriodo(Date start, Date end);
}

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

package com.site.domain.persistence.dao;

import java.util.List;


import com.site.domain.model.entity.Usuario;
import com.site.domain.model.repository.UsuarioRepository;

public class UsuarioDAO implements UsuarioRepository {

        public List<Mensagem> listarMensagensEnviadasPorPeriodo(Date start, Date end) {
                return null;
        }

	public Usuario add(Usuario bean) {
		// TODO Auto-generated method stub
		return null;
	}

	public Usuario get(Long id) {
		// TODO Auto-generated method stub
		return null;
	}

	public List<Usuario> getAll() {
		// TODO Auto-generated method stub
		return null;
	}

	public void remove(Usuario bean) {
		// TODO Auto-generated method stub
		
	}

}

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

package com.site.service;

import com.site.domain.model.entity.Usuario;
import com.site.domain.model.repository.UsuarioRepository;
import com.site.domain.persistence.dao.UsuarioDAO;

public class UsuarioService {
    

    private UsuarioRepository usuarioRepository;
	
	//spring transaction control
	public void delete(Usuario usuario) {
        usuarioRepository.remove(usuario);
		
	}

	public void save(Usuario usuario)  {
        usuarioRepository.add(usuario);
	}

}

Bom, eras isso!

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

90 Respostas

sergiotaborda

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

L

Ruim.

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

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

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

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

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

peerless

Leonardo3001:

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

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

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

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

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

Rodrigo_Carvalho_Aul

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

[]'s

Rodrigo Auler

L

peerless:
Leonardo3001:

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

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

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

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

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

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

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

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

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

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

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

C

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

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

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

tnaires

Concordo com o colega cmoscoso, quando ele discorda da seguinte afirmação do Leonardo3001:

No capítulo sobre Repositórios do livro do Eric Evans, há um trecho que diz:

peerless

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

os amigos em cima já lhe corrigiram.

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

Rodrigo_Carvalho_Aul

tnaires:
No capítulo sobre Repositórios do livro do Eric Evans, há um trecho que diz:

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

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

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

[]'s

Rodrigo Auler

C

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

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

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

tnaires

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

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

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

[]'s

Rodrigo Auler


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

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

Abraços

Rodrigo_Carvalho_Aul

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

Ser flexivel não é desculpa pra fazer besteira.

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

[]'s

Rodrigo Auler

L

Peerless,

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

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

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

É isso.

tnaires

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

C
Rodrigo Carvalho Auler:
Não vejo motivos pra factory não ser o próprio repositório, mas mesmo não sendo, ela pode usar os mesmos mecanismos do repositório pra de alguma forma persistir o objeto ao fim de uma transação.

Neste caso ela estaria sendo o próprio repositório! :)

Bom, factories não são repositórios. Apenas entidades podem ser persistidas e factories atacam o inicio do ciclo de vida do objeto, quem lida com o ciclo de vida das entidades são os repositórios. Se você não precisa de factories é normal para casos simples mas quando justificar uma não vejo porque criar um objeto hibrido, é um design pouco flexível pra dizer o mínimo. Na minha opinião pessoal acho melhor separar os dois conceitos e delegar responsabilidades entre eles quando for o caso.

Rodrigo Carvalho Auler:
tnaires:
Mas não entendi sua colocação sobre a fábrica. Ela tem como função abstrair a criação de novas instâncias de objetos de domínio, sendo assim, não vejo como ela poderia substituir um add() no repositório.
Na criação de uma nova instancia ele pode injetar no objeto o que ele precisa saber pra se persistir, se for usar ActiveRecord. Ou , dependendo de como for sua persistência, já colocar seu objeto pra ser persistido ao fim da transação.

Independente do mecanismo de persistência alguem não teria ainda que sinalizar qual o objeto e quando no processo ele seria persitido?

em.persist(entidade); // JPA

session.save(entidade); // Hibernate

Esse é justamente o código contido no metodo add(). Não entendi o que transação tem com isso.

sergiotaborda

cmoscoso:
Rodrigo Carvalho Auler:

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

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

É verdade que o Repositorio começa como uma necessidade orientada a pesquisas. Mas não é verdade que ele só possa ter esse tipo de funcionalidade. Ele ser o criador de objetos é muito interessante também. Ele assume mais do que o papel de fabrica, ele pode assumir o papel de injetor de dependência. Por outro lado é sempre bom encapsular a criação dos objetos e o Repositorio é tão bom quanto qualquer outro lugar. Afinal poderiamos ter um XPTORepository e um XPTOFactory , mas para quÊ complicar se podemos ter apenas um XPTORepository.createNew() ?
Quando a ter outros métodos como add/ remove/ merge ele pode ter mas até que ponto isso é uma vantagem e até que ponto esse objeto é apenas um repositorio é outra historia.

Ora ai está um problema findOrCreate significa encontre ou crie. Isso são duas coisas. São duas responsabilidade explicitamente fundidas. Quando o objeto retorna ele é novo ou foi encontrado ? Entenda como o desconhecimento da origem do objeto interfere com o processo do programa. Se eu mandar encontrar e quiser testar que ele não encontrou , como faria ? criaria um método existe() ? nesse caso não é mais simples separar create de find ? Afinal são duas ações muiiito diferentes.
AddOrUpdate já não é tão problemático já que significa apenas 'save", mas do ponto de vista do estado do repositório sempre será um update.

O repositorio e os objetos que ele contém são independentes. O objeto da entidade é criado fora do repositorio sem estar anexo a ele. Mesmo com repositorio.create() o repositorio irá apenas criar e retornar o objeto ele não o irá incluir na lista de objetos do repositorio. Para isso existe um add. Para remover o objeto do repositorio remove. Quando de obtêm um objeto e se altera o seu estado isso não pode refletir no objeto quardado no repositorio, ou seja, em uma pesquisa o repositorio irá retornar um copia e não o original. Já que se a alteração é revertida (roolback) o repositorio não pode ter mudado. Isto é controle de fronteira de transação ou se quiserem controle de fronteira de alteração de estado e não é especifico do repositorio.
Então após pegar um objeto do reposiorio e alterá-lo posso querer que o novo estado do objeto seja aplicado ao objeto que está no repositório, e para isso existe o merge. Claro que sendo que os objetos do repositorio são entidades e portanto têm identidade o método merge e o add podem ser fundidos num update ou save ou persist da vida. A ideia é , coloca este objeto no repositorio. Se ele já estiver lá, atualiza o seu estado.
Estas operações têm que ser ACID mesmo quando não estamos num contexto transacional e processo de concurrencia têm que ser levados em consideração. Tantas responsabilidades num só objeto podem ser rápidamente prejudiciais mas cooperam para uma implementação mais simples.

A base de um repositorio é ter métodos find. Vários se necessário ou utilizando QueryObject. getByID deveria ser findByID() já get implica que estou recuperando um atributo do repositório o que não é verdade.
Vários métodos find, para várias situações e ocasiões compõem um repositorio.
Contudo ele pode ainda conter métodos de alteração de estado como remove, add , merge , etc… Mas cuidado que isso faz dele um quase DomainStore e não apenas um Repositorio.

sergiotaborda

Leonardo3001:
P
Talvez porque no mundo real, sem um Hibernate, fazer os objetos se salvarem por mágica seja impossível, ou pelo menos, requer muito trabalho, daí esses metódos estão lá no repositório para não complicar muito nossas vidas. Porém, ainda não deixa de ser esquisito pra mim.

No mundo real isso não é desejável. Vc quer controlar o ciclo de vida, não quer que ele se controle sozinho “magicamente”.

C

Usar findOrCreate() ja foi a melhor opcao pra mim porque não havia diferença se a entidade era nova ou usada e a entidade sempre deveria existiri no retorno da chamada. Não é questão de serem duas ações diferentes porque você está afirmando isso sem um contexto, e no contexto daquele cliente de repositorio a ação era apenas uma, obter uma entidade existente no dominio com aquele atributo passado como parametro.

E pra isso existem factories!

Creio que isso seja indiferente para os clientes do repositorio ja que eles dependem apenas da interface.

C

sergiotaborda:
Leonardo3001:
P
Talvez porque no mundo real, sem um Hibernate, fazer os objetos se salvarem por mágica seja impossível, ou pelo menos, requer muito trabalho, daí esses metódos estão lá no repositório para não complicar muito nossas vidas. Porém, ainda não deixa de ser esquisito pra mim.

No mundo real isso não é desejável. Vc quer controlar o ciclo de vida, não quer que ele se controle sozinho “magicamente”.

Só pra esclarecer ao Leonardo as entidades que possuem repositorio próprio são chamadas de Aggregate Root e apesar do Hibernate salvar todo o agregado como “mágica” ainda é necessário chamar persist/save na entidade root, mesma que seja por algum mecanismo de indireção.

Thiago_Senna

Eu também implicava com isso. Para ajudar, imagine-se usando uma collection ao invés de repositório. Se você chamar list.get() e alterar alguma informação da instância retornada, a coleção também conterá a instância com suas devidas alterações. No entanto, imagine que em algum momento na aplicação é criado uma cópia desta instância e esta sofre alterações. O equals e hashcode são os mesmos. Para a coleção, o objeto ainda é o mesmo, apesar de serem instâncias diferentes. Se vc quiser que estas alterações sejam registradas na coleção então você terá que adicionar este objeto novamente na lista para substituir a instância antiga.

Repositorio deve ser similar a uma collection inclusive nestes aspectos, em minha opinião (o que muda é que faz mais sentido definir igualdade entre as entidade à partir dos Id’s ao invés do equals). Para facilitar gosto de pensar que ao obter uma entidade do repositorio, obrigatoriamente devo adicioná-lo novamente para que o repositório saiba das alterações que ocorreram na entidade.

Não sei se fui claro, mas assim como você, eu também tenho minhas implicâncias e esta era uma delas, que ao meu ver acabou sendo diluído pelo beneficios de produtividade que posso obter usando repositorio. Espero ter ajudado! :wink:

Até

peerless

Leonardo3001:
Peerless,

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

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

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

É isso.

Hei! De maneira alguma (e nem teria pq) levar como ofensa pessoal, hahahahahaa!!!
o topico foi criado para ser criticado mesmo… tanto é que como já disse, acatei algumas sugestões…

sergiotaborda

O ponto é: repositorios têm que ter add mesmo quando são eles a criar os objetos.

cmoscoso:

Creio que isso seja indiferente para os clientes do repositorio ja que eles dependem apenas da interface.

Não , não dependem.Elas dependem de um contrato. Contrato é muito mais que uma interface.
Vc já usou JPA ? já pensou para que serve o merge ? Já usou o Hibernate ? já pensou porque é preciso o Session in View ?

wagnerfrancisco

Muito bom o tópico.

Eu estou lendo o blog do Sérgio Taborda, especificamente sobre DAO e surgiram algumas dúvidas na parte dos repositórios:

Em relação a nomenclatura, no teu exemplo tu utiliza Repository, UsuarioRepository e UsuarioDAO. Em comparação com o artigo do Sérgio Taborda, seriam apenas nomes diferentes para:

Repository = GenericDAO
UsuarioRepository = UsuarioDAO (se existisse no exemplo passado pelo Sérgio)
UsuarioDAO = implementação do UsuarioDAO

Ou eu estou enganado? Parecem ser equivalentes. Mas aí surgiria outro ponto, que seria em relação a separação dos pacotes. Tu usa Repository no pacote aplicacao.domain.model.repository, SE ele for só uma interface para os DAOS não seria mais interessante mantê-lo em aplicacao.domain.persistence.dao?

Grato pela atenção,

Wagner.

sergiotaborda

Sim.
Repository é um objeto completamente separado do DAO. Tem interface diferente e tem proposito diferente.
Repositorios podem utilizar DAOs , mas DAOs não podem usar repositorios.

Repository = UsuarioRepository
DAO = UsuarioDAO
Implementação do DAO = JDBCUsuarioDAO (note o nome da tecnologia de persistencia no nome)

Mas não são.
DAO é um cara que recebe um parametro de pesquisa generico e executa uma API especial para retornar os dados brutos
dessa pesquisa.

Repositorio é um cara que recebe parametros especificos do dominio , criar um parametro (ou mais) que o DAO entenda
executa o método no DAO, pega o resultado, trata esse resultado e no fim devolve objetos do dominio.

O repositorio não compatilha a mesma interface que o DAO. Eles não são objetos da mesma hirarquia de classes, nem de interfaces.

Um DAO deve ser reaproveitável. Se vc não trabalha com sistemas legados isso é sempre possivel.
Nesse cenário o DAO não pertence ao codigo do seu projeto. Pertence a alguma API utilitária que vc já usou antes
e fica num pacote utilitário no mesmo nivel que um utils da vida

org.empresa.common.persistence.dao
org.empresa.common.utils

O repositorio depende inteiramente do dominio, e portanto da aplicação , e deve estar junto das classes de dominio como Cliente, Produto etc… (Aliás essa proximidade é desejável para poder se aproveitar do uso do modificador padrão de acesso). Ele pertence ao mesmo pacote que o modelo do dominio

org.empresa.aplicacao.domain.model

Alessandro_Lazarotti

Acredito que até mesmo especificar um DAO como “UsuarioDAO” possa ser de uma granulariedade dispensável. Costumo usar o DAO para abstrair persistência sem ter que conhecer implícitamente elementos do domínio.

As assinaturas podem ser a grosso modo: find(String query), persist(Object obj), delete(Object obj) e demais relacionadas.

Costumo deixar os detalhes do domínio para o repositório, eg: buscaUsuariosInativos(). Internamente o Repositorios se vira com o DAO ou qualquer outro meio para satisfazer os critério do domínio.

sergiotaborda

Acredito que até mesmo especificar um DAO como “UsuarioDAO” possa ser de uma granulariedade dispensável. Costumo usar o DAO para abstrair persistência sem ter que conhecer implícitamente elementos do domínio.

As assinaturas podem ser a grosso modo: find(String query), persist(Object obj), delete(Object obj) e demais relacionadas.

Costumo deixar os detalhes do domínio para o repositório, eg: buscaUsuariosInativos(). Internamente o Repositorios se vira com o DAO ou qualquer outro meio para satisfazer os critério do domínio.

Sim, essa é a prática atual que é mais reutilizável. Eu faço o mesmo. Mas infelizmente o pessoal ainda não entendeu bem a diferença então escolhi não dar esse passo adicional. É verdade que com o UsuárioDAO a diferença entre ele e o Repositorio fica mais ténue e que o repositorio só faz sentido com um DAO generico, mas …baby-steps…

wagnerfrancisco

Sergio, muito obrigado pelas explicações mais uma vez. De antemão lhe digo que não havia visto o artigo sobre Repository no teu blog. Aliás, existe algum livro que fale sobre ele também? Não encontrei no GoF, nem no Core J2EE Patterns, mas gostaria de estudá-lo. Esses conceitos ainda são muito abstratos pra mim, uma vez que estudo eles há pouco tempo e estou começando com essas implementações só agora.

Uma pergunta, pra complementar: um framework como o Hibernate abstrai algum destes “processos”?

Obrigado.

sergiotaborda

wagnerfrancisco:
Esses conceitos ainda são muito abstratos pra mim, uma vez que estudo eles há pouco tempo e estou começando com essas implementações só agora.

Uma pergunta, pra complementar: um framework como o Hibernate abstrai algum destes “processos”?

Os conceitos importantes são 3: DAO , Domain Store e Repository

DAO tem duas"facetas": Temos o DAO original que servia para colocar todo o SQL e fazer a ponte entre o banco e os objetos e ao mesmo tempo era plugável. Contudo ele continha regras de negocio e não apenas mapeamento O-R
Temos o DAO atual que apenas comtêm mapeamento e é reaproveitável para vários projetos e dominios.
Nenhum dos dois impoe um ciclo de vida no objeto persistente. Aliás não existe o conceito de objeto persistente com DAO.

Este padrão tinha dois defeitos: não tinha ciclo de vida e continha logica de negocio.

O Domain Store é o padrão que adiciona ciclo de vida ao processo. Ele usa um DAO “burro” sem ciclo e completa o processo.
O Repositorio é onde fica a logica de negocio.

Então vc usa um repositório para conter regras de negocio: ou seja, consturir pesquisas especiais e usa o DAO ou o Domain Store para executar essas pesquisas. Se usa o DAO os objetos retornados são genericos demais (tipo ResulSet) e o Repositorio tem que ostraduzir para objetos do dominio. Se usa o Domain Store ele ja faz essa tradução e de quebra controla o estado do objeto.

O Hibernate é uma implementação de Domain Store, assim como o JPA. Domain Store é um JEE Core Pattern

Repositorio é um padrão introduzido pelo Fowler e depois adotado pelo pessoal do DDD. O repositorio do Fowler não contém métodos de edição (save, etc) só de pesquisa. Tem uma pequena explicação no site de http://martinfowler.com/eaaCatalog/repository.html que é um cheirinho do livro Patterns of Enterprise Application Architecture.

O Domain Store é de certa forma uma evolução do DAO quando se afina a interface do DAO e se acrescentam responsabilidades
Do DAO ao Domain Store.

wagnerfrancisco

Então usando Hibernate a presença dos DAOs é dispensável, correto?

Se eu utilizar métodos add e remove no próprio Repositório, como foi sugerido pelo peerless e utilizar Hibernate, seria necessário mais alguma classe ou padrão entre o Repositório e o banco de dados?

No site do hibernate existe um artigo sobre a utilização do Hibernate com DAOs. Seria só pra centralizar toda a utilização dele num ponto só?

Obrigado.

sergiotaborda

wagnerfrancisco:
Então usando Hibernate a presença dos DAOs é dispensável, correto?

Sim.

Não.

Não. Seria para publicitar o Hibernate. O conceito de Hibernate dentro de um DAO é absurdo. O DAO é supostamente plugável. O Hibernate não é plugável. Logo, inserir uma coisa não plugável dentro de uma plugável é uma asneira.
Imagine que vc tem um DAO para o Banco XTO ficticio que não suporta JDBC e vc teve que criar tudo mão. Vc fez seu sistema e está tudo funcionando. Um dia o hibernate dá suporte a esse banco e vc pensar :" Crio um DAO com o hibernate lá dentro e dico livre para usar qq banco que o hibernate suporta, inclusive o XTO" … beleza, vc faz isso. Eis senão quando vc descobre que a performance do seu sistema caiu abruptamente. Vc investiga o problema e descobre que o hibernate está fazendo eager loading de tudo. Maior @#$@. Vc precisa resolver isso. Vc descobre o padrão “Open view in session” e resolve. Mas agora o seu DAO depende de um filtro de servlet que controla o session… hummm… gambiarra , não ?

Escolher usar hibernate é uma decisão de arquitetura , não de design. Isto porque ele não é completamente encapsulável. Pelo menos ainda não é. Esta é a minha opinião.

wagnerfrancisco

sergiotaborda, desculpe-me pela demora da resposta e obrigado por todos os esclarecimentos.

Vou implementar os repositórios com Hibernate e sem utilização dos DAOs. Vou dar uma olhada no Spring também, pra injetar os repositórios. Ainda tenho algumas dúvidas, mas aí acho que foge um pouco do que foi proposto no início do tópico.

feliperod

Cara,

Nem li tudo que escreveram aí porque me deu preguiça. hahahaha…

Mas pelo que vi no seu código, sugiro sumir com o ID do repositório. Não faz muito sentido ter ID no repositório, pois pra ele o interessante é o objeto completo.

Fica aí uma dica e se isso já foi mencionado, me desculpem. =)

Abração,

faelcavalcanti

feliperod:
Mas pelo que vi no seu código, sugiro sumir com o ID do repositório. Não faz muito sentido ter ID no repositório, pois pra ele o interessante é o objeto completo.
Não é id do repositório, apenas um identificador do tipo de chave primária sobre o bean associado. Geralmente isto é utilizado para um DAO generico, porém pode ser ainda customizado.

feliperod

Mas é desse ID do bean mesmo que estou dizendo que deve sumir do Repositorio. Lembre-se o repositório é um conceito de negócio e no negócio geralmente não existe ID. O campo ID é um campo estritamente de infraestrutura. Na verdade no negócio uma entity significa um conjunto único de dados. Só adicionamos o ID porque é uma best pratice de banco de dados, mas é meio bad smell ficar trabalhando com ID no meio do Domain Model.

C

:shock:

Identificadores existem em todas as entidades do negócio como forma de diferenciar cada uma, logo não entendi qual o seu ponto, você sugere traduzir o termo para algo que pertenca a linguagem do dominio ou abolir identificadores completamente do dominio?

pcalcado

Desculpa a sinceridade mas não ler um tópico e comentar é contribuir para piorar a qualidade do debate.

Muitas vezes identificadores fazem parte do domínio e mesmo que não façam eles vão fazer parte do critério de consulta de alguma forma, já que quando o usuário entra uma url como site.com.br/coisas/123 você tem que buscar por esse ID usando o repositório e criar um objeto para fazer QBE pode até esconder o ID mas acaba criando um problema de semântica (criar um objeto que você está procurando? isso não existe na linguagem do domínio).

Isso não quer dizer que você vai necessariamente ter um buscarPorId no Repositório -apesar que na maioria das vezes vai- porque este pode estar embutido em algum outro critério -formando um Query Object/Specification com semântica maior- mas esconder completamente IDs do domínio quase sempre é inviável.

faelcavalcanti

pcalcado:
-apesar que na maioria das vezes vai- porque este pode estar embutido em algum outro critério -formando um Query Object/Specification com semântica maior
não entendi quanto a citação pcalcado.

pcalcado

Nossa, ficou cnfuso mesmo. Deixa eu tentar reescrever:

Isso não quer dizer que você vai necessariamente ter um buscarPorId no Repositório (apesar que na maioria das vezes vai) porque esta busca pode estar presente em alguma outra, provavelmente formando um Query Object/Specification que tem semântica maior dentro do domínio que uma busca por id crua e genérica. Esconder completamente IDs do domínio, no entanto, quase sempre é inviável.

faelcavalcanti

pcalcado:
Nossa, ficou cnfuso mesmo.
melhorou quando eu reli. :smiley: mas é isto mesmo.

feliperod

Não estou sugerindo abolir os identificadores. Estou afirmando é que os identificadores são uma solução específica para infraestrutura e não para negócio. Por isso não deixa de ser um bad smell ficar passando os identificadores como parâmetro para metodos no domain.

No entando concordo quando o Phillip diz:

Mas repare que mais uma vez o motivo de precisar usar o buscaPorId foi porque ou a apresentação exige ou a infraestrutura exige. Existem exceções claro, mas eu nunca disse que não existe. =)

Primeiro, obrigado pela sinceridade. É sempre bom saber o que estão pensando dos nossos posts. Você pode ter razão, mas eu pedi desculpas antecipadamente. Além disso eu afirmei que não li TUDO que haviam postado. Mas li o tópico inicial e alguns outros posts. Não tenho essa mesma certeza de que piorei muito a qualidade do debate. Pelo contrário, acabou surgindo um tema que pode aperfeiçoar em muito o conhecimento de todos que estão lendo. Ou estou errado?

Grande Abraço,

C

Identificadores existem em muitas situações de negócio.

Novamente, não é excecao. Muitas vezes identificadores estão contemplados de alguma maneira no negócio.

Independente disso, ja que voce nao ve sentido em usar ids no repositorio eu gostaria de saber o que voce faria nesses casos onde se trata apenas de exigencia da apresentação/infra. Nao podemos esquecer que apesar de repositorios fazerem parte do dominio eles existem mais para suportar o dominio do que efetivamente agrupar regras de negocio.

feliperod

cmoscoso:
feliperod:

Não estou sugerindo abolir os identificadores. Estou afirmando é que os identificadores são uma solução específica para infraestrutura e não para negócio. Por isso não deixa de ser um bad smell ficar passando os identificadores como parâmetro para metodos no domain.

Identificadores existem em muitas situações de negócio.

Novamente, não é excecao. Muitas vezes identificadores estão contemplados de alguma maneira no negócio.

Independente disso, ja que voce nao ve sentido em usar ids no repositorio eu gostaria de saber o que voce faria nesses casos onde se trata apenas de exigencia da apresentação/infra. Nao podemos esquecer que apesar de repositorios fazerem parte do dominio eles existem mais para suportar o dominio do que efetivamente agrupar regras de negocio.

A resposta é simples como citado pelo próprio Phillip em alguns posts acima.

Só certifique-se se o ID é realmente necessário pelo negócio e não apenas porque tem ua URL que recebe o ID como parâmetro e vc não sabe mais como buscar algo. O importante é ter BOM SENSO. Não precisa criar uma parafernalha desnecessária, mas pode pensar em uma forma prática de resolver isso, partindo dos conceitos de Query Object e outros patterns. Claro, isso se quiser e puder usar DDD.

peerless

Na hora que inclui este ID estava pensando em como eu pego dados de um repositório qualquer em memória que implemente a interface “List”. myArrayList.get() - claro que a posição com o ID não tem nada ha ver -em momento-, mas ficou bom e fácil de buscar um bean pelo identificador ! Mas como pode ser visto, o ID é genérico, então pode ser um hashcode, a posição realmente dele em alguma lista ou any.*… tudo vai depender do seu negócio.

feliperod

Exatamente. Você está correto. Entendeu minha mensagem. Usou de Bom Senso. Mas vale lembrar que substituir o ID pelo hascode não resolve essa questão. Hashcode é apenas uma técnica para tratar objetos e não entidade de negócio.

Acho que a pergunta real é: O que faz de um objeto uma entity? Essa pergunta não é retórica e acrescentaria uma contribuição gigantesca se for respondida.

[editado novamente: CHEGA de propaganda]

Grande Abraço,

peerless

… que substituir o ID pelo hascode não resolve essa questão …

Vamos combinar que eu usei de exemplo!

feliperod

Por isso eu escrevi que vale lembrar. =)

A cortesia ainda tá valendo. =)

peerless

Ok. Eu sei a resposta, mas vou confessar que lembro de ter lido essa parte no livro. É a sua IDentidade.

feliperod

Tá certo. Mas acho que não expressei direito a pergunta.

[editado mais uma vez]

hehe

Edufa

Para não copiar nenhum definição, tentando com as próprias palavras.

Entity possui uma identidade.

Exemplo: uma pessoa seria uma Entity enquanto um valor monetário não (no caso seria um value object).

[editado]
PS: isso depende do domínio, num sistema financeiro esse exemplo pode mudar. Tem de observar no domínio quem deve ter uma identidade

feliperod

Bom, como a brincadeira da [EDITADO POR ALGUM MODERADOR …] acabou vou colocar a minha resposta pra meu desafio com o intuito de contribuir. Aliás até o desafio foi apagado então vou simplesmente postar a minha definição de uma entity:

Pra mim uma entity deve ser criada para representar um conjunto de dados únicos que, unidos não se repetem no sistema. Por isso não considero somente a identidade como um código numérico ou de qualquer espécie como uma definição de negócio. Na verdade eu acredito que o código numérico existe apenas para evitar que usemos vários dados ao invés de apenas 1.

Por exemplo, uma pessoa normalmente é uma entity, porque o conjunto é único. Um nome pode se repetir, um endereço pode ser o mesmo para duas pessoas, porém o conjunto. (Endereço, Nome, Telefone, Idade, Numero de Cueca, etc…) não se repete. Pra mim isso é a idedntidade. Esse tipo de situação é que define uma entity.

Bom, aí está minha contribuição.

Espero que isso também não seja [EDITADO]. A liberdade de expressão foi pra puta que pariu agora.

pcalcado

feliperod:
Bom, como a brincadeira da [EDITADO POR ALGUM MODERADOR …] acabou vou colocar a minha resposta pra meu desafio com o intuito de contribuir. Aliás até o desafio foi apagado então vou simplesmente postar a minha definição de uma entity:

feliperod:

Espero que isso também não seja [EDITADO]. A liberdade de expressão foi pra puta que pariu agora.

Não é brincadeira, Felipe, você foi avisado e tornou a repetir o erro. Boa parte das pessoas do GUJ trabalha para ou possui empresas de trinamento ou ferramentas e é obrigação da moderação não deixar o fórum virar propaganda. Sua liberdade de expressão está assegurada, assim como a liberdade do usuário em ter um fórum livre de propaanda não-solicitada.

Além do mais, liberdade de expressão pressupõe respeito com palavras então peço para que guarde seus palavrões para um lugar mais apropriado.

faelcavalcanti

poxa pessoal. pensem no peerless, se eu estivesse no lugar dele, estaria puto. gostaria de um diálogo construtivo. não sou moderador mas vamos deixar essa conversa mole para uma mp. critiquem-se entre si via mp. fico interessado com as idéias e toda vez quando volto para este post, só vejo decepção. me desculpe mas eu tinha que falar isto.

rodrigoallemand

sergiotaborda:
wagnerfrancisco:
Então usando Hibernate a presença dos DAOs é dispensável, correto?

Sim.

Divergência detected.
Vc acha que um GenericDAO pode suprir todas as necessidades de todo o seu sistema só por usar Hibernate?!
E as queries especializadas? E as regras aplicadas em banco?
Acho muito pouco provavel que isso aconteça na vida real, tendendo a zero!

peerless

Uma dúvida nas consultas, eu ñ precisaria de um repositório -FISICAMENTE- se eu tivesse um gerenciamento via anotações, por ex assim ?:

Entidade { private List<Message> messages; @Repository(select="select mensagens where dia = ?"); listaMensagensEnviadasNoDia(Date dia) { return messages; } }

ps: tá eu sei que é feio/chato/ruim ter sql dentro do código, mas considerar algo que poderia estar sendo mapeado fora… tipo como faz o BoxSQL :stuck_out_tongue:

sergiotaborda

rodrigoallemand:
sergiotaborda:

Repository = UsuarioRepository
DAO = UsuarioDAO
Implementação do DAO = JDBCUsuarioDAO (note o nome da tecnologia de persistencia no nome)

sergiotaborda:
wagnerfrancisco:
Então usando Hibernate a presença dos DAOs é dispensável, correto?

Sim.

Divergência detected.

Não vejo onde…

?

Repositorio!!!
Regas = Repositorio
Acesso = DAO

DAO = Data ACCESS Object e não Data RULES Object

feliperod

sergiotaborda:
wagnerfrancisco:
Então usando Hibernate a presença dos DAOs é dispensável, correto?

Sim.


Hibernate não é sinônimo de qualidade nos DAOs.Também não é indispensável.

rodrigoallemand:

Divergência detected.
Vc acha que um GenericDAO pode suprir todas as necessidades de todo o seu sistema só por usar Hibernate?!
E as queries especializadas? E as regras aplicadas em banco?
Acho muito pouco provavel que isso aconteça na vida real, tendendo a zero!

É possível um GenericDAO suprir muitas necessidades da sua aplicação. Já participei de situações em que um DAO genérico atendia 100% dos casos, com Hibernate. Também já criei DAOs com BoxSQL que atendem boa parte das situações, já que é possível passar quase tudo por parâmetro para um template, inclusive uma clausula where. Com Hibernate ou JPA, pode criar NamedQueries para resolver a questão de queries customizadas.

Se FISICAMENTE quer dizer que não precisa de uma implementação dentro do domain, está certo. Há casos em que podemos ter uma interface como repository que expressa os conceitos de negócio, mas a implementação fica na camada de infra-estrutura.

Feio é, mas isso não é limitação sua. É limitação da tecnologia. Organização de metainformações em java não é muito elegante. MAs pode usar o BoxSQL ou mesmo as NamedQuery do Hibernate. Mas eu prefiro o BoxSQL. (Aliás, vai um link aí pra página do projeto. que tá mudando de casa. O Java net é meio confuso na parte de iteração com os participantes.)

Grande Abraço,

rodrigoallemand

Bem, se uma hora vc fala que DAOs implementados necessitam da prefixação da tecnologia utilizada, como alguns posts depois vc confirma para o owner do tópico que, em se usando Hibernate, o DAO é dispensavel?

Remetendo a sua afirmativa de HibernateDAO desnecessário, a unica alternativa de vc acessar algum tipo de dado seria usando-se um DAO genérico, compartilhando-o para todas as entidades, certo? Ou vc pretende fazer isso de outra maneira que não as vias normais?

Ai, ai, ai… tentando…

Vc acha que o seu dominio e o seu banco vão ser sempre tão perfeitos que vc nunca precisará de uma especialização no acesso aos dados, ou vc sempre coloca essas informações no repositorio… Pense grande, e não em sisteminhas… em sistemas complexos vc vai precisar de um recurso de banco para livrar o seu dominio, seja por performance, seja por ineficiencia da linguagem/framework, etc.

Só pra alinhar o debate, eu sou de acordo com a estrutura que vc propos, só não entendi quando vc colocou que o Hibernate é unipresente para DAOs, independente da entidade.

sergiotaborda

rodrigoallemand:
sergiotaborda:

Não vejo onde…

Bem, se uma hora vc fala que DAOs implementados necessitam da prefixação da tecnologia utilizada, como alguns posts depois vc confirma para o owner do tópico que, em se usando Hibernate, o DAO é dispensavel?

Com DAO hibernate é dispensável. Sim. Logo, não faz sentido escrever HibernateDAO.
Quando me refiro a DAO genérico me refiro do ponto de vista que ele e independente do dominio , da entidade, etc… não que ele é independete da tecnologia de persistencia. Isso seria uma antitese do proprio padrão.

Continuo sem entender muito bem o que pertende levantar com a sua interrogação. Não sei se a explicação acima é suficiente.
Se não for , explique mais detalhadamente o seu ponto.

Se vc entender “normal=usar hibernate” então sim. DAO não deve ser implementado usando hibernate : isso é um facto. Se vc não o aceitar vc vai ter problemas na arquitetura. Mas lembre-se que DAO é diferente de Repositorio e normalmente quando se usa hibernate já se usa Repositorio por padrão, já que instintivamente vc encapsula o acesso ao hibernate em outra classe. Só que essa classe não e´um DAO, é um repositorio. Numa arquitura com Hibernate o DAO está dentro dele ( é o Dialect)

Um DAO genérico é aqule que vc implementa uma vez e usa em todas as aplicações independetemente do dominio.
Vc pode pensar que Hibernate é a unica forma de alcançar isso, mas não é.

Exactamente por isso não se usa Hibnernate. Usa-se DAO. E sim é possivel sempre abstrair qualquer tipo de acesso porque afinal não existem tantos assim ( SELECT, INSERT , DELETE , UPDATE). Problemas de performance não são responsabilidade do DAO.
Contudo vc pode usar alguns padrões como o Fastlane para ajudar. Se a querie é muito complexa o repositorio dá conta. Mesmo que a tenha que escrever na mão e contornar o DAO (isso não é ideal - poque é uma violação do contrato do DAO - mas funciona).

qualquer tipo de regra de dominio/negocio simples ou especial de acesso a dados não fica no DAO. Fica no repositorio. Logo, por definição, o DAO não contêm nenhuma regra do dominio, e por consequencia ele é genérico.

Pense assim, no Hibernate não existem regras de negocio. Vc utiliza o hibernate para criar as regras. A mesma coisa com o DAO. Ele é independente, desacoplado, reutilizável. Não contêm regras.


Só pra alinhar o debate, eu sou de acordo com a estrutura que vc propos, só não entendi quando vc colocou que o Hibernate é unipresente para DAOs, independente da entidade.

Não sei ao que se refere. Reli todo o thread enão entendo donde parte a sua duvida.
Nunca falei que o Hibernate é presente nos DAO (unipresente ? o que é isso ? quiz dizer onipresente ?).
Aliás, sempre defendi que: ou vc usa Hibernate ou vc usa DAO. Usar DAO baseado em Hibernate é asneira.
Independentemente de qual usar, vc precisa usa Repositorio, que é onde ficam as regras de negocio.

Não sei se ajudou…

rodrigoallemand

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…

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?

peerless

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?

fabim

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…

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 )

rodrigoallemand

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 )

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.

sergiotaborda

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…

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

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?

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.

sergiotaborda

rodrigoallemand:
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 )

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.

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.

C

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.

pcalcado

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 )

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.

sergiotaborda

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.

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)?

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!

sergiotaborda

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)?

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.

pcalcado

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.

wagnerfrancisco

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

sergiotaborda:
wagnerfrancisco:
Uma dúvida idiota de quem está esp…

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

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.

wagnerfrancisco

pcalcado:
wagnerfrancisco:

O controle de sessão, bem como autenticação num sistema, é serviço somente da camada de …

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.

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.

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.

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!

sergiotaborda

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

sergiotaborda:
wagnerfrancisco:
Uma dúvida idiota de quem está esp…

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

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?

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 …

tnaires

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?

pcalcado

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?

É 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.

Marcio_Duran

: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.

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.

pcalcado

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.

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.

Rubem_Azenha

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

tnaires
pcalcado:
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.
Certo. Só quero deixar claro que, quando eu falo que o ou repositório ou o DAO conhece sobre o negócio, quero dizer que um método de consulta específico do negócio é implementado no mesmo. Métodos como esses:
public interface EnqueteRepositorio {
    // Retorna todas as enquetes criadas por um usuário do sistema.
    List<Enquete> enquetesPorUsuario(Usuario u);
}

public HibernateEnqueteRepositorio implements EnqueteRepositorio {
    public List<Enquete> enquetesPorUsuario(Usuario u) {
        // Aqui eu utilizaria Session + Criteria
    }
}
sergiotaborda

Não precisa de um caso para entender a diferença. É como entender a diferença entre verbo e substantivo; não preciso lhe dar exemplo para explicar a diferença.

Talvez esteja pensando em implementação, que a de um e a de outro são iguais ou semelhantes. Tlv até sejam, mas a sua responsabilidade, o papel que têm no sistema, a frequencia de alteração, a reutilização, e mais importante que isso o principio de design por detrás de cada um é completamente diferente.

Não é porque vc chama DAO a uma classe que ela vira uma implementação de DAO. O mesmo para qq outro padrão.
Eu , particularmente, acho absurdo o exagero nos prefixo e sufixos ( tipo, ClienteVO). Arrisco a dizer que 90% dos objetos sufixados com DAO , hoje em dia, são na realidade implementações do padrão Repositorio. Especialmente se Hibernate ou JPA for usado.

O DAO com regras de negocio inclusas é algo do passado, que só faz sentido com vc trabalha com sistemas legados e codigo esparguete ( sem divisão de responsabilidade)

rodrigoallemand

Eu até já tive um caso onde o Repository não era uma Interface… mas era uma classe abstrata… que o DAO implementava… que uma fabrica retornava… no final, mesma coisa…

Antes nós faziamos…
Servlet -> Façade -> Service -> Factory -> DAO Interface -> DAO Impl -> DTO
Agora, seria algo parecido com…
Controller -> DomainFaçade -> [Service] -> Registry -> Repository -> DAO -> Entity <- TO | VO

Acho que isso é vicio antigo, não?!

tnaires

Saiu um ótimo artigo na InfoQ que fala sobre aspectos práticos do desenvolvimento com DDD:

Alessandro_Lazarotti
tnaires:
Certo. Só quero deixar claro que, quando eu falo que o ou repositório ou o DAO conhece sobre o negócio, quero dizer que um método de consulta específico do negócio é implementado no mesmo. Métodos como esses:
public interface EnqueteRepositorio {
    // Retorna todas as enquetes criadas por um usuário do sistema.
    List<Enquete> enquetesPorUsuario(Usuario u);
}

public HibernateEnqueteRepositorio implements EnqueteRepositorio {
    public List<Enquete> enquetesPorUsuario(Usuario u) {
        // Aqui eu utilizaria Session + Criteria
    }
}

Postei exatamente sobre isso aqui:
http://www.guj.com.br/posts/preList/94314/507424.java#507424

Rubem_Azenha

sergiotaborda:

Não precisa de um caso para entender a diferença. É como entender a diferença entre verbo e substantivo; não preciso lhe dar exemplo para explicar a diferença.

Talvez esteja pensando em implementação, que a de um e a de outro são iguais ou semelhantes. Tlv até sejam, mas a sua responsabilidade, o papel que têm no sistema, a frequencia de alteração, a reutilização, e mais importante que isso o principio de design por detrás de cada um é completamente diferente.

Não é porque vc chama DAO a uma classe que ela vira uma implementação de DAO. O mesmo para qq outro padrão.
Eu , particularmente, acho absurdo o exagero nos prefixo e sufixos ( tipo, ClienteVO). Arrisco a dizer que 90% dos objetos sufixados com DAO , hoje em dia, são na realidade implementações do padrão Repositorio. Especialmente se Hibernate ou JPA for usado.

O DAO com regras de negocio inclusas é algo do passado, que só faz sentido com vc trabalha com sistemas legados e codigo esparguete ( sem divisão de responsabilidade)

Eu compreendi que DAO é um conceito de persistência e Repository é um conceito de negócio (uma Collection pode ser um repository).

Eu entendo que nomenclatura é algo muito importante.

Mas para mim, a nome DAO e Repository representam coisas com propósitos muito parecidos. Então se eu ver uma objeto do tipo ***DAO e ***Repository em uma classe da camada de negócio, eu sei exatamente para que serve para praticamente a mesma coisa na grande maioria dos casos.

Talvez se o Repository precisar fazer uma regra, validação, processamento, etc, antes de acessar o mecanismo de persistencia valeria ter um repository encapsulando um DAO.

Alguém pode colocar um exemplo de um projeto real? (Não vale projeto da NASA :twisted: )

pcalcado

Qualquer projeto. Se sua classe de negócios precisa obtêr um objeto da persistência pra quem ele pede?

sergiotaborda

Vc está no bom caminho, mas se ainda acha que o cocneito de DAO e Repositorio são muito semelhantes precisa ir mais além. Tem que chegar no ponto onde entende que eles são completamente diferentes.

Isso vai ser uma dificultada já que a maioria dos projetos opta por implementar classes com papel de repositorio chamadas DAO e usando hibernate. Ou seja, confusão total.

Rubem_Azenha

java.sql.Connection :stuck_out_tongue:

Brincadeira. :stuck_out_tongue:

Geralmente para o DAO.

Ainda não entendi a confusão.

public interface AlgumaEntidadeRepository {
    public void save(AlgumaEntidade a);
    public void delete(AlgumaEntidade a);
    public void find(AlgumaEntidade a);
    public void List&lt;AlgumaEntidade&gt; findAll();
    public void List&lt;AlgumaEntidade&gt; findAllAlgumaEntidadeByAlgumAtributo(XYZ xyz);
}

e o meu DAO implementando a interface.

Qual a grande sacada aqui?

sergiotaborda

Rubem Azenha:

Ainda não entendi a confusão.

public interface AlgumaEntidadeRepository {
    public void save(AlgumaEntidade a);
    public void delete(AlgumaEntidade a);
    public void find(AlgumaEntidade a);
    public void List&lt;AlgumaEntidade&gt; findAll();
    public void List&lt;AlgumaEntidade&gt; findAllAlgumaEntidadeByAlgumAtributo(XYZ xyz);
}

e o meu DAO implementando a interface.

Qual a grande sacada aqui?

A sua interface é de um Repositório (que não faz sentido ser uma interface para começo de conversa, mas deixa para lá). A sua interface depende do dominio. Blz.
Agora, o DAO é um objeto que não depende do dominio. Essa é a sacada.

Mais detalhes aqui
Leia com atenção o topico e todas as referencias citadas nele.

pcalcado

Calma, baby steps. Agora leia isso aqui.

Criado 16 de maio de 2008
Ultima resposta 21 de jun. de 2008
Respostas 90
Participantes 17