No more DAO’s

Um dos padrões de projetos mais conhecidos e mais utilizados ainda hoje é o DAO (Data Access Object). Padrão este que teve um papel fundamental há muitos anos, e que ainda hoje em determinados projetos de software desempenha muito bem seu trabalho. Contudo, isto não o torna, de maneira alguma, um padrão que todo arquiteto deveria implementar obrigatoriamente em qualquer aplicação.

Todo design pattern existe para resolver um problema comum de software, e não apenas para ser utilizado como uma receita de bolo em qualquer projeto. E com DAO não seria diferente. A finalidade do DAO é prover uma interface com operações para acesso a dados que abstraiam os detalhes do mecanismo de persistência (seja um banco de dados, ou não), ponto final.

Sua utilização há alguns 5 ou 6 anos atrás fazia todo sentido pois naquela época ainda erámos obrigados a trabalhar com JDBC puro e frameworks de persitência bem precários. Isto é, não tinhamos bons frameworks que abstraíssem de maneira satisfatória o acesso aos dados da aplicação (99% das vezes um banco de dados).

Por isso todo projeto de software daquela época implementava seu próprio DAO para evitar a mistura de código de negócios com código SQL (e mais alguns objetos de persistência), e assim diminuir o acoplamento entre as camadas (layers).

O problema é que hoje em dia com todos os consagrados frameworks para persistência ainda temos arquitetos implementando seu próprio DAO em todo e qualquer projeto de software que eles ponham as mãos. Mesmo que na arquitetura tenha-se adotado algum framework ORM (como JPA ou Hibernate) ainda assim temos os benditos DAO’s espalhados pela aplicação.

Sempre que vejo um projeto que adotou algum ORM (muitas vezes JPA) para persistência e me deparo com o famigerado DAO eu pergunto para o arquiteto da solução qual motivo o levou a colocar uma layer a mais na aplicação sobre o JPA. E como sempre recebo a seguinte resposta:

“Ah! para abstrair a camada de persistência. Assim se futuramente for necessário mudar de JPA para qualquer outra tecnologia, como JDBC puro, vai ser bem simples, pois bastaria criarmos outra implementação.”

Este tipo de argumento demonstra puro e simplesmente senso comum. Arquitetos que pensam assim pararam no tempo e não acompanharam a evolução das tecnologias ORM para plataforma Java. Outros mesmo atualizados seguem o senso comum. Pois é muito mais cômodo e simples para estas pessoas repetirem sempre a mesma “solução” em cada novo projeto do que se manterem atualizadas e avaliarem outras possíveis soluções.

O mais interessante disso tudo é que basicamente foi criada outra camada genérica para abstrair algo que por si só já é nossa abstração. O que estou querendo dizer, e que certamente foge ao senso comum, é que você não precisa de outra camada, o JPA já abstrai a persistência para você, ele além de muitas outras coisas já está atuando como nossa DAO layer.

A partir do momento que um arquiteto cria esta camada genérica ele está abrindo mão de features importantes de qualquer framework para persistência que ele venha a adotar. Todos os frameworks de persistência seguem filosofias e possuem features diferentes que agregam valor ao software de uma maneira ou de outra, mas que por termos esta camada de abstração não poderemos utiliza-las, caso contrário estaríamos detonando com a “portabilidade” da camada.

Quando adotamos um framework ORM como o JPA/Hibernate, não importa o motivo, já temos que ter em mente que nossa aplicação (principalmente o domain model) estará “mergulhada” nas features do framework, como anotações, contexto de persistência, lazy loading, dirty checking etc. Simplesmente mudar a implementação do DAO -como muitos acreditam- não garantirá que nossa aplicação continuará funcionando.

Ter esta camada extra de abstração (seu próprio DAO) pode matar o que de melhor seu framework ORM pode te oferecer, já que sua aplicação deverá funcionar independente da implementação utilizada. Por isso reflita se é melhor ter um full-ORM com um half-DAO do que ter um switchable-DAO com um half-ORM. Eu, particularmente, prefiro um full-ORM.

Antes que algum fanático por DAO venha aqui me crucificar, eu não tenho nada contra DAO layers, assim como também não acho que JPA tenha vindo para mata-lo. Mas acredito que este design pattern tem o seu lugar e deveria ser utilizado adequadamente, e não como uma camada obrigatória na aplicação.

Não existe uma receita de bolo para quando utilizar seu DAO genérico particular ou não. Cada projeto tem suas peculiaridades e estas devem ser analisadas com seus devidos cuidados. Mesmo eu achando que hoje em dia (a não ser que você esteja implementando o framework caseiro da sua empresa) não precisamos de tanta preocupação quanto a isso.

Para o caso especifico do JPA, utilize diretamente o EntityManager no lugar da sua abstraçao de DAO genérica, principalmente se você estiver implementando CRUDs, e utilize DAO’s onde for realmente necessário e fizer sentido. Bem mais simples, e bem menos artefatos na tua aplicação para manter.

Enfim, esse tipo de discussão sobre abstrair um framework ORM com uma camada DAO não vem de hoje, datam de meados de 2005 ou até menos. Meu conselho é que você não crie uma camada a mais para tentar abstrair o que por si só já é sua abstração. Trabalhe com o que o framework ORM te fornece, de preferência da melhor forma possível.

33 thoughts on “No more DAO’s

  1. Considerando um Domain Model, alguns padrões [como Repository] tiram a implementação direta do EntityManager que já elimina toda a necessidade de um DAO Caseiro.
    Mas eu não tenho nada contra um EntityManager direto no código de controller por exemplo principalmente para CRUDs.

  2. Rafael, Muito legal a explanação, mas eu te pergunto, e para sistemas que já vem sendo construido a muito tempo.. Projetos que estão em produção a muito tempo como migrar?? Todos nós sabemos que migração de framework em java é uma MERDA!!! Eu penso que se o projeto é novo devemos usar o que tem de melhor para resolver o problema. Claro, não precisa nem falar que para cada problema uma solução, mas como estava dizendo, temos que ter cuidado apenas com o legado.. O legado é o que paga as minhas contas!!! kkk.. :)

    Muito bom o post mas quis deixar um outro ponto de vista!!

    Abração

  3. @Pantoja
    Como disse no post, uma DAO layer faz sentido para sistemas legados, não há problemas nisso. O DAO tem seu papel e deve ser utilizado quando necessário. Contudo, migrar um legado de anos para alguma nova tecnologia de persistência é algo que, na minha opinião, não vale a pena.

    Enfim, é preciso avaliar.

  4. Discordo do artigo.

    JPA não abstrai a camada de persistência, ele abstrai JDBC\SQL. JPA é uma implementação de camada de pesistência, não tem como ele abstrair nada, principalmente para buscas…

    Imagine espalhar pelo seu código: List l = em.createQuery(“select x from y where y.a = ? and y.b = ?).setParameter(1, “‘asd”).setParameter(2, “asdasd”);

    Eu não gostaria de manter um código assim, preferiria um XDao ou XRepository.findXByAB();

    Acho bem ofensivo você afirmar categoricamente que quem usa DAO parou no tempo ou apela para o senso comum. Tanto eu como vários colegas que são excelentes profissionais utilizam DAO nos seus projetos por que realmente acreditam que agregam valor ao projeto.

    A questão nem é tanto “se mudar a camada de persistencia, basta mudar a implementação”. Eu também não acredito nisso principalmente quando falamos de Hibernate\JPA. A questão é deixar código que é de persistência fora da camada de visualização ou da camada de negócios.

    É claro que se sua aplicação é um CRUD simples talvez você possa deixar, mas o problema é que esses CRUDs crescem e aí você tem um problema para dar manutenção depois.

    Eu concordo com você que não existem receita de bolo, mas existem princípios que vale a pena considerar.

  5. @Rubem

    Uma consulta especifica com determinados parâmetros e semântica faz parte do negócio :-). Se ela for complicada e estiver dificultando a legibilidade do código então acredito que vaila a pena utilizar-se de um Repository (ou mesmo DAO) ou ainda mais simples, quebra-la em um método que expresse a devida intenção.

    Eu, em nenhum momento, inferi que arquitetos que usam DAO pararam no tempo. O que eu disse (e aconselho que você releia) foi que arquitetos que se usam daquele argumento (texto em cinza) para manterem uma camada a mais na aplicação pararam no tempo. Este tipo de argumento é um senso comum desde 2003, que veio com o JEE Patterns e ainda hoje é usado como desculpa por várias pessoas.

    Quanto a CRUDs, eu sinceramente não sei o que você quer dizer com “CRUDs crescem”. Como um CRUD cresce em complexidade? Tem certeza que a funcionalidade é um CRUD? :-)

    Rubem, não confunda princípios com senso comum. Evitar código de negócio misturado com código de persitência é uma coisa, ter sempre um DAO para separa-los é outra coisa.

    Ah! Um DAO é um pattern. Não há uma única maneira de implementa-lo. Para Java existem várias soluções e frameworks que implementam DAO de diversas maneiras, no post eu citei algumas bem conhecidas.

  6. Greetings, Human!

    Ótimo post! Entretanto, faria notar que a DAO também ajuda a abstrair o ORM, e isso é bastante útil. Se nos libertamos do SQL, o HQL ainda não é tão prático quanto um LINQ ou uma list comprehention da vida, e acho válido isolá-lo.

    Entretanto, acho que mais concordamos que discordamos, no sentido de que vejo sua proposta como “vamos pensar antes de sair pondo DAO (ou qualquer outra coisa) ‘no automático’ nos projetos”.

    Até!

  7. Concordo que DAO é uma pattern e sempre devemos analizar qual pattern se encaixa melhor no contexto.
    Essa questão do DAO é bem controversa hoje em dia, fico feliz que a discussão agora não seja DAO X Repositories (eu uso uma interface repository mais semânticas um DAO para implementar, na maioria dos casos) :)

    O fato é que não acho legal expor o mecanismo de ORM pro resto da aplicação, alias, não gosto de expor o uso de nenhum framework. Pelo que você falou você também não gosta.

    Mas que outros mecanismos você usa para abstrair a ferramenta de persistência do resto da sua aplicação, quando você decide não usar DAO? ActiveRecord?

  8. Ótimo post Ponte.
    Eu acredito também que não há necessidade
    sempre no uso do DAO, podemos utiliza-lo em
    casos específicos, como já foi citado.
    No mais parabéns pelo Post!

  9. A grande maioria dos projetos que trabalhamos são CRUDs e essa grande maioria utilizam-se de DAO. Isso que não faz sentido. Acredito que em poucos casos um DAO realmente se faz necessário.

    É como o Rafael disse: Uma consulta especifica com determinados parâmetros e semântica faz parte do negócio :-). Se ela for complicada e estiver dificultando a legibilidade do código então acredito que vaila a pena utilizar-se de um Repository (ou mesmo DAO) ou ainda mais simples, quebra-la em um método que expresse a devida intenção.

    Achei que eu era “louco” por achar que um DAO não é requisito na arquitetura de um sitema.

    Parabens pelo post

  10. A muito tempo compartilho desta visão Ponte, principalmente quando estamos tratando de projetos novos em que o container já é capaz de injetar uma implementação do EntityManager nas nossas proprias services.
    Acho que não é preciso misturar uma chamada ao EM direto de um controller por exemplo, ao inves disso costumo implementar em um Bean de negocio a interface do EM e injetar como atributo deste bean de negocio o proprio, assim mantenho a camada ORM desacoplada do restante da aplicação e encapsulada em um Bean de negocio.

    Muito bom o POST!

  11. Aquelas desculpas de “se você quiser mudar…” para mim tb são erradas e exageradas, quam acha que mudar um banco ou uma forma de persistencia é simples assim, está absurdamente enganado.

    No entanto, para as formas de consulta para um dao que retorna objetos que é o caso de jpa/hibernate, apenas os dados de entrada são relevantes e não os de saída, já que são objetos, ou seja, se passa dados ou objetos e a consulta retorna geralmente um tipo de objeto ou coleção do mesmo, e isso pode muito bem ser substituido por um metodo com os parametros corretos para deixar claro a consulta.

    O que é mais claro? um metodo como “consultarUsuariosAdministradores” ou uma sequencia de chamadas a api de persistencia com jpql no meio?

  12. Você tocou num ponto interessante o “senso comun”, pois muitos padrões de arquitetura são reusados apenas como chavões. O DAO em específico passa por uma questão bem FILOSÓFICA do sistema: “o que é parte da camada de negócio e o que é um tratamento genérico/abstração dos dados”. Pode existir tratamentos feitos nos dados específicos de uma aplicação que podem se tornar um componente para empresa utilizar como um DAO em outro projeto, no geral é importante manter o DAO mesmo com um ORM “somente” quando você tem componentes mais avançados/legados em relação a ele, por exemplo quando a JPA não suportava “critétrios” eu criei uma abstração com suporte a isto antes do seu lançamento, hoje posso atualizar para JPA mais nova sem o “sofrimento” que o Natanael citou, mas no geral o seu conselho é o certo, ainda há hoje quem crie uma Interface+DAO para cada Entidade! Absurdo 😛

  13. Bom o Artigo!

    Eu costumo fazer uma camada acima do meu Hibernate, para que na implementação tenha somento o seguinte:

    DaoPessoa.salvar(pessoa);

    E mais nada, o DaoPessoa abre sessão, transação, persiste e fecha tudo!

    Ou isso:

    ArrayList pessoas = DaoPessoa.recuperar(id);

    Mas não sei isso é um DAO… COmo disseram, andam dado nome de tudo por ai de DAO.

  14. Bom post,

    Explicação sucinta e clara, para esse pattern DAO ainda muito usado, principalmente para quem usou em projetos a dupla JPA/Hibernate, e ainda insiste em usar essa layer so para seguir um padrão de desenvolvimento.

    Parabéns!!!!!

  15. IMHO, acho que a utilização da API do mecanismo de mapeamento objeto relacional (ex: Hibernate / JPA) deve ficar na implementação de um repositório. Quando falo de repositório, estou me referindo ao conceito dentro do escopo da DDD (Domain Driven Design). A camada de negócio e aplicação usam a interface do repositório.

    Para mais informações:

    http://domaindrivendesign.org/

    Livro: Domain-Driven Design: Tackling Complexity in the Heart of Software (Hardcover) – Eric Evans

  16. Pelo visto o nome DAO levando o crédito sobre tudo que se manipula dados, ex: DAO ou Repository???

    Assim sendo, eu prefiro manipular dados como uma camada separada ou como um Helper do Service. Não acho interessante incluir nos services as necessidades de manipulação de dados, digamos sobre manipulação, principalmente buscas, que envolvem *QL.

    Mais sou o adepto do ActiveRecord, infelizmente no java direto não dá, mais nada melhor que esta no mundo do GORM ou algo do tipo.

    [s]

  17. Legal o post Rafael.

    Mas só para refletir, e indo na mesma direção dos comentários do George Queiroz e Eldon: e quanto a Forte Coesão e Baixo Acoplamento? Não levando em consideração que DAO e Repository abstraem a implementação do ORM, se elas apenas abstraíssem para o Controller a camada de dados já estaria fazendo seu papel, não acha? Em equipes e projetos bem estruturados e divididos, colocar uma equipe para trabalhar com os Controllers e outra com a camada de dados, usar o DAO ou Repository já seria uma mão na roda. Mesmo em equipes pequenas, onde talvez não haja uma divisão clara das partes do projeto, no mínimo seria mais clara a divisão entre controle e dados e facilitaria a manutenção.
    Concordo com você que precisamos sempre avaliar os problemas e usar os padrões que melhor os resolvam. Mas a ideia desse post de que usando JPA elimina a necessidade de camadas de dados é, no mínimo, arriscada.
    Meus 2 centavos.

  18. Concordo com o CMilfont, para CRUD não faz muito sentido, porém o uso de classes que encapsulem um EntityManager facilitam no reuso de HQLs que sejam muito executadas pelo código.

  19. Se há muito de HQLs, pq não criar um método dentro da própria classe que vai fazer a busca? Por exemplo, por que não um método Funcionario.listDesempregados (Funcionario é um Entity) que use esse HQL?

    O mais engraçado do povo que cria DAO de modo automático, é a repetição dos métodos. Criam um save no Entity, que chama o save do DAO, que chama o save do EntityManager. Ridículo. Isso quando basta chamar o save do EntityManager, que ao contrário do que disseram acima, JPA é sim uma abstração do modelo objeto relacional.

    Acho que às vezes falta pras pessoas aprenderem um pouco com outras linguagens, como Ruby. Eu adoro Java, mas mexer com outras linguagens sempre abre a mente para soluções diferentes.

  20. Engraçado, porque uso Spring e eu gosto muito do “tal do” HibernateTemplate.

    O bom é que ele encapsula a complexidade de controle da sessão (exemplo simples).

    Mas se eu não usasse Spring certamente gostaria de encapsular esse tipo de coisa. Vamos dizer que não desse o nome de DAO.

    Imaginando um EntityManager injetado em 2 Controllers, por exemplo, e nessas 2 classes eu precisasse da mesma consulta. Acho que devo isolar isso em algum lugar!

    Não concordo sair chamando tudo de DAO, a menos que realmente seja um DAO. Mas concordo em encapsular coisas pra poder reusá-las e me dá menos trabalho

  21. A frase cinza citada é o velho problema da “bola de cristal” do papel do arquiteto – aquele que define o alicerce do sistema.

    O arquiteto deve definir o que é palpável ou fortemente provável e não algo altamente improvável. Caso contrário “criamos Robocops que acabam ajudando velhinhas a atravessar a rua”.

    Quantos sistemas que utilizam Hibernate/DAO que precisaram ser trocados por TopLink ou iBatis ou JDBC puro? É provável que não apareça nenhum. 😉

    Dito isso, ainda, vejo que JPA 1.0 não é uma especificação madura o suficiente para ser utilizada diretamente no código, como já é o Hibernate. Duas questões me vem rapidamente: não possuir definição para delete-orphan, bem como não tem API para Criteria.

    O que tenho visto são sistemas de utilizando Hibernate/Session com DAO e utilizando anotações JPA para mapeamento. Ou seja, se preparando pro futuro padrão de mercado sem perder as funcionalidades presentes.

    Com JPA 2.0 será diferente, pois ela atende a maior parte das funcionalidades ORM. Então acredito que o padrão DAO caia em desuso.

    Ah, com relação às queries de consulta espalhadas? Basta anota-las na entidade via @NamedQuery e voilá! Tchau DAO!

  22. Acho que o mais interessante de se usar:

    xhtml -> jsfBean -> VendasEJBRepositoryManagerBusinessXuxaFezPorno(sei lá o que vc chama o cara que tem a logica de negócio) -> DAO -> JPA -> DataBase

    é que o seu VendasEJBRepositoryManagerBusinessXuxaFezPorno consegue manipular as relaçoes entre as entities e as mudanças nos comportamentos dos objetos ‘quase’ como se estivessemos brincando num metodo main estupido.

    ex:

    @Stateless
    class VendasEJBRepositoryManagerBusinessXuxaFezPornoBean implements VendasEJBRepositoryManagerBusinessXuxaFezPorno {

    @EJB
    VendasDAO vendasDao;

    void finalizar(Venda venda){

    venda = vendaDAO.get(venda.id);// eu nao quero saber como alguem busca uma venda no database!
    produtos = venda.getProdutos();//lazy load ( isso é o ‘quase’ do inicio do comentario

    for (Produto p : produtos){
    if (!disponivel()) throw DeuPauNaVendaExcpetion(“pau”);
    }

    // e por ai continua
    }

    boolean disponivel(Prdito p){ return blablabla}
    }

    eu prefiro chamar myDAO.findAlgumaCoisaNessesCriterios(); a partir do meu Repositorio do que colocar a maneira como essa alguma coisa eh achada diretamente no meu Repositorio.

    Os meus Repositorios sao Homens de Negocio que nao se preocupam em como as coisas sao achadas, salvas, deletadas.

    Eles simplesmente decidem QUAIS e COMO as coisas vao ser feitas.
    Por isso eu ainda continuo com DAOs.

    Obrigado

  23. interessante, então o JPA é um “dao” na verdade? e o que se diz no post é que não faz sentido ter um dao dentro de outro?

  24. Oi raneves,

    É por aí mesmo, mas claro que existem exceções, e vai o bom senso e experiência do desenvolvedor saber quando ter uma abstração (DAO, Repository etc) a mais para resolver determinado problema.

    No mais, para CRUDs, eu não vejo a necessidade da utilização de DAOs para abstrair o que por si só já é uma abstração (JPA/Hibernate).

  25. Boa matéria sobre assunto, já tinha lido sobre a discussão entretanto não me recordo de terem comentado sobre o fato de ter um CRUD e apenas por isso utilizar um DAO. Eu mesmo acreditei que isso já era algo default (if CRUD true = frameowrk ORM +DAO).

    De qualquer forma tenho uma visibilidade sobre a utilização do JPA e os comentários vieram a calhar.

  26. eu acho q tudo depende. No meu ultimo projeto eu optei por usar JDBC + DAO, pois era uma solução muito particular, não era algo mais abrangente onde se espera crescimento da aplicação. Não quis usar JPA e Hibernate por achar que elevaria o grau de complexidade do projeto sem necessidade. o DAO cuida dos CRUDs e em caso de mudanças de sgbd, etc, as modificações ficariam minimas, com pouco impacto sobre o projeto de formas global.

    creio que existem zilhoes de soluções, o que é importante é verificar onde se encaixa cada coisa e quando precisaremos de um ou outro recurso

Leave a Reply

Your email address will not be published. Required fields are marked *