Rodrigo Kumpera Weblog

Meus achados sobre tecnologia

DAOs e abstraction leakage

April 10th, 2007 · 4 Comments

Lendo esse artigo do Phillip, me lembrei de um problema com o padrão DAO que todos sempre fogem de discutir. Um DAO existe para abstrair o mecanismo de persistência da aplicação, simples assim. Porém é uma falsa promessa, entregue cheia de mentiras e contratos escondidos. Quando a interface do DAO é definida, implicitamente fica definida toda semântica e capacidades do mecanismo de persistência da implementação. Isso fica evidente em qualquer exemplo do padrão.

Um DAO pode ser implementado como um Table Data Gateway ou um Data Mapper. Porém esse fato é escondido dos seus clientes. Em termos práticos isso significa usar JDBC diretamente para o primeiro, e Hibernate para o outro. Isso não deveria causar diferença na forma que o cliente usa, certo? Bom, existem, e são significativas.

Na construção da interface de um DAO, inconscientemente pensamos na forma que sua principal fonte de persistência funciona. Os clientes vão, por sua vez, assumir que o comportamento e a performance seguem o contrato definido pela implementação original. No final encontramos alguns problemas resultantes de tal percepção, primeiro que não é possível trocar a implementação sem alterar o código cliente e segundo que, ao trocar, a performance se torna inaceitável.

O código do cliente precisa ser alterado se, por exemplo, o DAO foi originalmente construído com Hibernate, usando de todos seus recursos, e troca-se por uma implementação somente com JDBC. Alguns recursos como lazy-loading e flush-on-commit são complexos para serem implementados diretamente pela camada de DAO e como provavelmente não fazem parte do contrato, causarão um abstraction leak e o cliente ficará na mão.

No caso da troca de mecanismos de persistência fundamentalmente diferentes, como de banco relacional para LDAP ou arquivos texto, algumas características de desempenho do contrato do DAO que o cliente assumia passam a ser inválidos. Sistemas de diretórios tem sérios problemas para consultas usando produto cartesiano ou agregação e arquivos textos são péssimos para busca. Agora imagine o cliente trocando a implementação do DAO e descobrindo que recuperar um objeto segundo sua identidade, isto é, a chave primária, passa a ser lento a ponto de inutilizar o sistema.

O padrão Data Access Object funciona muito bem para abstrair o acesso ao mecanismo de persistência, mas não tem utilidade para abstrair suas capacidades, então, ao projetar um sistema usando DAOs, defina bem a qual tipo de armazenamento serão construídos – seja um framework de ORM, bancos relacionais ou sistemas hierárquicos.

Tags: Programming

4 responses so far ↓

  • 1 felipe cruz // Apr 10, 2007 at 3:37 pm

    Opa!

    Concordo com você.. mas me lembro que antigamente(antes de o hibernate ser famoso) muito material na internet nos fazia acreditar que o DAO servia para abstrair a implementação de SGBD(quase não se levava em consideração formas de persistência alternativas como ldap ou arquivo texto), tanto que eram utilizadas aquelas fabricas que nos retornavam aqueles OracleDAOImpl ou SqlServerDAOImpl nos exemplos clássicos de DAO que achavamos no google.

    Na verdade muita gente se deixou levar por esse mito de esconder a implementação, parcialmente verdadeiro, já que na verdade poderia esconder a implementação desde que as implementações todas fossem JDBC..

    Como você disse, DAO abstrai o mecanismo de persistencia mas não suas capacidades..

  • 2 Bruno // Apr 10, 2007 at 3:55 pm

    Rodrigo,

    já trabalhei em um projeto onde a arquitetura usava DAOs para abstrair a persistência. No caso, a promessa era a de haver uma implementação específica para o banco de dados hierárquico e, futuramente, ser possível trocá-la implementando uma relacional. Eu me questionava se isso faria sentido uma vez que todo o projeto era “otimizado” para extrair vantagens do banco hierárquico.

    Minha pergunta é: há alguma solução, mesmo sem utilizar DAOs?

    Abs.

  • 3 Diego Pires Plentz // Apr 10, 2007 at 8:33 pm

    Bruno, uma solução que atenda 100% à todos casos não existe, pois como no exemplo de alteração de perfomance que o Rodrigo citou, fica realmente inviável manter a mesma capacidade de consultas.

    Porém, como no caso dos recursos do Hibernate, como o lazy-loading e flush-on-commit, esses sim podem ser evitados, mas devemos avaliar muito bem antes de decidir por não usar tais recursos, uma vez que eles são muito úteis e que muito raramente alterar a forma de persistência de um sistema será uma realidade.

  • 4 kumpera // Apr 10, 2007 at 11:42 pm

    Bruno, concordo com o Diego que com DAO é dificil definir uma interface capaz de funcionar bem com banco hierárquico e relacional. Provavelmente seria necessario usar somente recursos comuns, o mínimo múltiplo comum a ambas tecnoligias.

    A parte que costuma dar mais problemas é busca, então em vez de definir a métodos com critérios explícitos, utilizando uma abstração semelhante a Criteria do Hibernate, por exemplo, seria possivel transferir para a implementação do DAO boa parte da decisão de como recuperar as informações.

Leave a Comment