Qual é o problema com o DAO?

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.

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?

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?

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.

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.

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 :)[code]public interface DomainStore {

public <E> E save(E instance);
public <E> void delete(E instance);
public <E> QueryResult<E> query(Criteria<E> criteria);

} [/code]O tal do query que eu não sabia bem como ficaria.

[quote=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 :)[code]public interface DomainStore {

public <E> E save(E instance);
public <E> void delete(E instance);
public <E> QueryResult<E> query(Criteria<E> criteria);

} [/code]O tal do query que eu não sabia bem como ficaria.[/quote]

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

[quote=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).[/quote]
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.

[quote=Rodrigo Sasaki][quote=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).[/quote]
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í?
[/quote]

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)

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.