Qual é o problema com o DAO?

9 respostas
S

Para não desvirtualizar o um outro topico do forum que é muito válido e devemos incentivar abri este tópico para endereçar a pergunta que o Rodrigo Sasaki me fez lá.
Acho que vale a pena um tópico disto porque é uma assunto que toca a todos.

O problema do DAO é que já morreu. É um padrão que tem uma utilidade especifica mas que virou bala de prata. Todos os projetos insistem em ter uma camada de DAO mesmo quando não precisam.
A desculpa clássica é : se eu mudar a forma de persistencia, é só mudar o DAO. Em tese isto é válido, mas apenas se todas as regras estão na camada do DAO. Quando o DAO começou a ser usado ele servia para isolar as regras de acesso ao banco e quando digo regras me refiro às queries não à tencologia. Hoje em dia as pessoas querem usar annotations jpa , hibernate, noSQL que utilizam sempre algum tipo de metamodelo. O metamodelo é uma coisa muito poderosa porque o programador programa declarativamente e não imperativamente. A programação declarativa é importante pois acelera o desenvolvimento pois algum já fez um framework para executar a parte imperativa. O uso de metadados é uma das top mecanicas para desenvolver software robusto e não é por acaso que o vemos em todo o lugar agora. Então o velho DAO que usavamos no EJB2.1 às 8 anos para encapsular as chamadas ao JDBC não tem mais utilidade. O DAO é uma instancia do padrão Service ( O nome é Data Access Object, mas poderia ser Data Access Service) em que existe uma interface e várias implementações para cada entidade. E a ideia é que isso gera uma familia de serviços de dados que depois temos que encapsular num abstract factory. Isso é muito bonito, mas na prática ninguém faz isso. Na prática a camada de DAO é apenas mais uma camada de indireção que não traz vantagens. Com as tecnologias modernas não é mais necessário usar o DAO.

O uso extensivo do DAO em todos os projetos e em todos os exemplos em todos os sites e revistas levam à ideia que é uma padrão fundamental. O mesmo vimos como o Singleton. Porque são padrões simples de entender, mas difíceis de implementar e realmente utilizar de fato, geram essa falsa sensação que o design está bem feito. Não é o uso do padrão X ou Y que faz um bom design. São regras mais abstratas como o DRY , a separação de responsabilidade, a inversão de controle , e um monte de outros princípios do design. Se dados estes princípios e a tecnologia e os constrangimentos o DAO for a melhor solução, ótimo. Mas hoje em dia não estamos mais no mesmo nível de constrangimentos e tecnologia que estávamos no tempo do EJB 2.1. Hoje não faz mais sentido usar o DAO.

hoje todo o mundo insiste em usar o DAO com o JPA ou hibernate por trás. Isso é um bom isolamento de fato ? Não. Porque essas tecnologias funcionam com base no metamodelo e metamodelos está nas classes de entidade, não no DAO.
Se tiver um sistema usando hibernate como base com DAO vc até consegue migrar para JPA porque é compativel, mas tenta migrar para noSQL ou JDBC puro. Não dá. O JPA e o Hibernate têm uma lógica interna de contexto (padrão unitOfwork) que o jdbc não tem. Quando vc dá save no hibernate não é a mesma coisa que no jdbc. No jdbc não tem fetch lazy. Então modelo conseptual que está sendo usado, embora dizendo que usa DAO é o modelo e um objeto que conhece as entidades e o metamodelo do dominio, que sabe ligar as entidades entre si de forma automática, etc… isso é o DomainStore.

Não ha necessidade de criar uma camada DAO em projetos modernos. Outras coisas como Strategy ou Template Method podem resolver a maior parte do pontos de diferença. O resto é 99,99% sempre a mesma coisa e é nisso que o JPA e semelhantes se baseiam.

O problema não é com o DAO em si, é como a forma que as pessoas o usam. Da forma errada. Da mesma forma que o pessoal insiste com singleton, por exemplo. Mas ninguem ouve falar em Memento por exemplo que resolve uma pá de problemas relacionados a persistencia e é usado dentro do hibernate, por exemplo. Foi um foco da midia especializada ha 8 anos atrás que deu essa ideia que o DAO é um padrão sem o qual a sua arquitetura não está completa. Não. Ha muitos outros padrões mais uteis e que o pessoal simplesmente ignora. Por quê ? porque não tiveram na midia e portanto são menos conhecidos e as pessoas não lembra deles. Não é possivel usar o que desconhecemos. Mas usando os principios de design vc consegue cehgar em muitos padrões sem saber o que é um padrão. Os padrões nada mais são que receitas prontas da aplicação dos principios a certos cenários, o problema é que as pessoas esqueceram os principios e só olham as receitas. E nem sempre isso dá certo.

O problema do DAO é que ele já morreu, mas as pessoas continuam usando. É como vestir vintage. Não. Em software não existe vintage, sempre temos que evoluir.

9 Respostas

D

Achei interessante a abordagem, mas, qual a posição prática disto? Coisas como “o hibernate permite alterar o banco de dados sem afetar meu projeto” nunca me soaram como bom argumento, pois dificilmente muda-se o sgbd no meio do projeto. Sim, evoluímos muito do EJB 2.1, o 3.1 é simplesmente fantástico, simples e direto, como ramones. Mas há ainda quem prefira o Steve Ray Vaughn ou mesmo o Pink Floyd.
Morto? Assim como o if no java?

Então vamos aos fatos, dê exemplos de como podemos substituir o DAO de uma forma elegante e atual.

Lógico que você não é o ViniGodoy, nem pretende ser, mas, por que não faz como o próprio e mostra como fazer?

R

Ah, entendi, o problema então não está no padrão em si, mas na sua aplicação no tempo atual, em outras palavras, ele é ultrapassado.

No exemplo de JPA que você deu, sua sugestão seria (naqueles 99,99% dos casos), simplesmente usar o EntityManager?

W

drsmachado, veja este link do Sérgio:

http://www.javabuilding.com/architecture/arquitetura-com-domainstore-repositorio-e-query-object.html

Tem exemplos de código com a abordagem dele.

Rodrigo Sasaki, veja este tópico:

http://www.guj.com.br/java/289087-repository--dao

Ao término do tópico eu fiz a mesma pergunta (se a ideia era usar diretamente o EntityManager).

Acho que se ler a thread e o link dá pra entender perfeitamente (inclusive a nível de implementação) como fazer o que o Sérgio propõe.

S

O wagner já deu os links.

Não vale jogar a criança fora com a água. O fato da camada de indireção do DAO ser ultrapassada, não singifica que o resursos de camada de indireção tenha que ser abandonado, bem pelo contrário.

Usar “diretamente” qualquer coisa é ruim por principio (Acoplamento), mas nem sempre vale a pena desacoplar. Por exemplo, vc chama System.gc() e pronto, não precisa inventar uma API para isso.
Mas em geral desacoplar é uma boa ideia. Agora, o ponto é que ha que pesar o quanto custa fazer o desacoplamento e quanto custa no futuro fazer o mesmo desacoplamento.
Coisa simples, usar interfaces. Isto é simples e promove muito desacoplamento. Nâo custa muito fazer , o IDE se vc soube usar. Então programar para interfaces é simples e é uma boa forma padrão de desacoplar. Mas o acoplamento às vezes é lógico e não fisico, ou seja, está na forma como a api é usada e não na api em si. Podemos desenhar uma api que abstrai o jdbc, mas só podermos usar primitivos estamos amarrados ao modelo do jdbc, não estamos realmente desacoplando nada.
E quanto custa no futuro colocar uma interface ? Não muito mais que no inicio, por é um simples “extract interface” Mas nem sempre é assim. Se a sua API é usadas por outros , é uma api publica (tipo as da apache ou google) ao publicar objetos em vez de interfaces vc engessa a evolução do design e a implementação das coisas.

Então, usar o EntityManager diretamente é bom ou mau ? Depende. Se vc só o usar em uma camada especifica não dever ser muito problema, mas a longo prazo quanto custa mudar ?

O custo de manutenção é muito maior que o de desenvolvimento de 40% a 80% então construir uma aplicação é simples e barato comparado com mantê-la a funcionar. O cara usou o EJB 2.1 à 8 anos. tinha a aplicação redondinhas. Otimo. Veio o EJB 3 e um monte de inovações que no EBJ 2.1 eram feitas meio que na gamb. Quanto custa migrar ? Depende de quanto o cara isolou as responsabilidades ( SRP). Se o cara deixou tudo no EJB já era. Mas se ele usou um design compartimentado onde o EJB era só um invocador remoto e não usada ejb-entity então é simples. O ponto é que ninguem não usada ejb-entity e todos eram com DAO. Migrar isso para EntityManager é possivel , mas caro.

Eu pessoalmente isolaria o Entitymanager, simplesmente porque isolaria as queries. E quanto cusata isso ? apenas uma interface uma implementação. Ou seja, o preço básico. Barato. Isolar as queries é que é a parte dificil/chata mas uma vez feito as vantagens são absurdas. E é uma coisa que dá para fazer no inicio e poupa muito custo de manutenção.

R

Ah, entendi. Então utilizar algo como Repositorio + DomainStore é preferível, mais organizado se for pensar orientado ao domínio.

entendi os pontos agora, nunca tinha visto esse design, muito bacana, eu fiquei pensando como seria implementado, mas quando vi o código abaixo já foram sanadas as dúvidas :)
public interface DomainStore {
 
    public <E> E save(E instance);
    public <E> void delete(E instance);
    public <E> QueryResult<E> query(Criteria<E> criteria);

}
O tal do query que eu não sabia bem como ficaria.
S
Rodrigo Sasaki:
Ah, entendi. Então utilizar algo como Repositorio + DomainStore é preferível, mais organizado se for pensar orientado ao domínio. entendi os pontos agora, nunca tinha visto esse design, muito bacana, eu fiquei pensando como seria implementado, mas quando vi o código abaixo já foram sanadas as dúvidas :)
public interface DomainStore {
 
    public <E> E save(E instance);
    public <E> void delete(E instance);
    public <E> QueryResult<E> query(Criteria<E> criteria);

}
O tal do query que eu não sabia bem como ficaria.

É ai que entra a API do easy criteria (a meu ver). Porque se vc tem uma api "de mercado" que é desacoplada dos outros frameworks , vc consegue usar este padrão em menos de 10 minutos ( o tempo que demorar a escrever aquela interface e a sua implementação.
Mas criar uma api de criteria é muito simples : é o uso direto do padrão Composite. O que é difícil é criar um bom, fluente e simples CrtieriaBuilder que ajudar escrever como se fosse sql ( ou hql).

R

sergiotaborda:
É ai que entra a API do easy criteria (a meu ver). Porque se vc tem uma api “de mercado” que é desacoplada dos outros frameworks , vc consegue usar este padrão em menos de 10 minutos ( o tempo que demorar a escrever aquela interface e a sua implementação.
Mas criar uma api de criteria é muito simples : é o uso direto do padrão Composite. O que é difícil é criar um bom, fluente e simples CrtieriaBuilder que ajudar escrever como se fosse sql ( ou hql).

Aí que o Hibernate (como JPA também) quebram as pernas da galera, né.

Eu entendi o repositório, você tem lá suas queries, e quem realmente acessa o banco é o seu DomainStore, maravilha.

Agora e se precisar mudar de SQL pra HQL? ou teria que ter ainda mais um nível de abstração aí?

Obs: Agora suas sugestões para o EasyCriteria fizeram mais sentido pra mim.

S

Rodrigo Sasaki:
sergiotaborda:
É ai que entra a API do easy criteria (a meu ver). Porque se vc tem uma api “de mercado” que é desacoplada dos outros frameworks , vc consegue usar este padrão em menos de 10 minutos ( o tempo que demorar a escrever aquela interface e a sua implementação.
Mas criar uma api de criteria é muito simples : é o uso direto do padrão Composite. O que é difícil é criar um bom, fluente e simples CrtieriaBuilder que ajudar escrever como se fosse sql ( ou hql).

Aí que o Hibernate (como JPA também) quebram as pernas da galera, né.

Eu entendi o repositório, você tem lá suas queries, e quem realmente acessa o banco é o seu DomainStore, maravilha.

Agora e se precisar mudar de SQL pra HQL? ou teria que ter ainda mais um nível de abstração aí?

A ideia é não precisar disso.
Mas para as coisas que não dá, então ai realmente vc não usaria o DomainStore e partiríamos para outro tipo de coisa. Mas ai vc estaria amarrando o sistema de novo.
Uma ideia seria vc informar um tipo especial de query (named query) em que vc dá um nome e parametros e o domainstore descobre o que vc quer fazer. Vc configura isso préviamente na sua implementação do domainsotre. Assim um query “AchaTudoXPTO” seria interpretado pelo HibernateDomainStore como um HQL que vc configuraria e pelos outros de outra forma. Um simples padrão Strategy com um Map daria conta do recado.

Agora, SQL ? ai vc está pedindo para ter problema. O conceito aqui é Orientação a entidades, não a tabelas. coisas como reports, por exemplo, não é para fazer com domainstore. Até dá, mas o overhead é grande. O Hiberante tem algumas métodos especiais para isso, mas em geral, relatórios complexos são muito orientados a tabelas e ai uma padrão especifico ou o uso de namedQuerys como expliquei antes (mas implementados nativamente talvez … ). Depende muito dos seus constrangimentos de volume de dados e performance. Eu geral eu gosto de usar criteria mesmo para coisas mais complexa usando o java mesmo para soldar as pontas (ou seja, ás vezes faz mais do que uma pesquisa ).

Veja que o fato de ferramentas domo jpa e hibernate deixarem vc fazer sql tem mais a ver com a demanda do mercado e o facilitismo do que com um bom design. Mas hey! por isso que são apis famosas. Como diria alguem que conheci, “se não pode fazer gamb as pessoas não usam” .

Mas com uma abstração geral como o DomainStore é muito simples vc criar ganchos e extenções para o que vc precisar. Afinal vc controla o codigo, antes de chegar na api final que vc estiver usando por baixo e pode usar mais do que uma ao mesmo tempo se for preciso (tipo hibernate para o basico e JBDC para relatorios complexos)

R

Entendi, eu usei SQL como exemplo só para apresentar uma alternativa ao HQL, ou a qualquer outra coisa que não seja um dos dois.

Mas entendi os pontos, bastante interessante essa discussão.

Criado 12 de dezembro de 2012
Ultima resposta 12 de dez. de 2012
Respostas 9
Participantes 4