Vale a pena abstrair?

Um post do Paulo sobre abstração de DAOs me fez lembrar de escrever sobre este assunto.

Durante muitos anos, eu fui adepto do desacoplamento e da abstração a todo custo. Eram factories com interface, que eram implementadas por uma abstract factory, que achava a própria implementação delas através de properties (sim, isso foi antes dos containers de DI, era uma boa prática pra época) e que sempre produziam interfaces e por aí vai. Os DAOs tinham interfaces e suas factories também e tudo era lindo.

Isso foi há pouco mais de 5 anos e hoje faz uns 2 anos e meio que parei com isso. Por quê? Bem, a análise do que eu havia feito naquela época me mostrou que ter esse princípio como norma geral é uma péssima idéia. Vou tomar como exemplo o casos dos DAOs.

No começo, isso fazia algum sentido, porque a idéia dos DAOs era permitir que você trocasse de banco de dados. Se seu sistema usava só JDBC puro e não havia triggers e afins no banco, no caso da remota possibilidade de trocar de banco, havia alguma vantagem nisso. Agora, quantos de vocês já viram isso acontecer? Mesmo quando acontece, dependendo das diferenças de funcionalidades utilizadas dos dois bancos e da forma como a abstração foi implementada, uma reescrita de tudo acaba sendo necessária. Além disso, nos grande maioria dos casos em que a mudança não ocorre, o quanto isso atrasa o ciclo de desenvolvimento? E aquele monte de interfaces inúteis, que só servem para deixar seu deploy mais lento e seu code completion mais poluído? Fora o fato de fazer os juniors entenderem por que isso é necessário. Obviamente, eu não estou considerando aqui o caso de produtos “genéricos” ou ferramentas que realmente tem que funcionar com mais de um banco desde o primeiro dia e, mesmo assim, estou supondo que o Hibernate ainda não existia.

Quando o Hibernate e seus semelhantes surgiram, aí as coisas passaram a fazer muito menos sentido. O problema principal que era poder usar outros bancos foi coberto. Aí as pessoas começaram a raciocinar: e se eu quiser trocar o Hibernate? Bem, se você quiser fazer isso, provavelmente sua aplicação inteira vai acabar mudando, a menos que você vá mudar para EJB 3 (o que, por sinal, não faz sentido na maioria dos casos). Escondendo o Hibernate você perde acesso a funcionalidades avançadas e outras delas “vazam” pelo código, como o uso de Transfer Objects para evitar a carga lazy de algumas propriedades e coisas do tipo.

O fato é que nos últimos anos todos nós ouvimos que devemos fazer a coisa mais simples que funciona. E os sistemas não funcionariam sem essa parafernalha toda? Então, por que estamos construindo algo de que não sabemos se vamos precisar? Da próxima vez que achar que precisa de interfaces ou abstrair uma implementação, verifique o custo-benefíio antes de sair codificando.

13 Responses to “Vale a pena abstrair?”

  1. Fabio Kung disse:

    Também acho que aquele monte de parafernália trazida pelo Abstract Factory inútil. Tudo isso *deve* ser trocado por injeção de dependências.

    Aí não temos mais “um monte” de interfaces no código. Apenas a interface DAO e suas filhas (o que eu tb discordo um pouco, como você pode ver aqui.

    Eu discordo no ponto de não abstrair o framework de ORM. Acho útil abstrair não para trocar fácil de banco de dados, mas sim para otimizações que possam ser necessárias. É comum acontecerem casos que você precisa abrir mão das vantagens do ORM e acessar o banco direto via jdbc, ou persistir o objeto em um lugar diferente (num arquivo xml, por exemplo) porque o banco é legado e você não pode criar outra tabela).

    Além disso, pelo menos para mim, na prática abstrair o ORM não têm sido muito trabalhoso tampouco tem limitado o que posso fazer com ele.

  2. Michael Nascimento Santos disse:

    Fabio,

    Na prática, o ideal é modificar esses casos de exceção a medida que surgem e não o contrário. Além disso, não entendi muito bem como que a otimização JDBC geraria outra implementação DAO ao invés de substitui-la.

  3. Rubem Azenha disse:

    Michael, o problema é que o pessoal as vezes pode usar isso como desculpa para fazer as coisas mal feitas…

    No caso o DAO por exemplo, eu prefiro usar DAOs, com interface, abstraido e tudo mais. A questão não é só “e se a gente trocar de banco” mas também da testabilidade e da manutenabilidade (existe essa palavra?) da aplicação. Se você colocar no teu objeto de negócio a session direto do Hibernate, como você vai fazer os seus testes unitários? E se der um problema? Será que é no
    DAO ou na classe de negócio? Com o código isolado, fica *bem* mais fácil encontrar o problema, bem mais fácil de dar manutenção, bem mais fácil de reaproveitar.

    É claro que para uma aplicação simples, sem muitas pretenções, pode-se usar a session direto, ou até a Connection, sem Hibernate mesmo.

    Mas para aplicações mais sérias, com finders mais complexos, isolar num DAO vai deixar o código mais testável, mais fácil de manter e mais organizado.

  4. Gyowanny disse:

    Todos os argumentos são válidos, mas e se eu não quiser usar Hibernate? Se vocês só trabalharam a vida toda com aplicações de grande porte, usando JEE e tudo o mais, com certeza um framework de mapeamento O/R se faz necessário, mas já tive casos, com aplicações JSE de médio porte, onde o Hibernate deixou a aplicação pesada e então fez-se necessário utilizar o acesso a JDBC direto, ou seja, se eu tivesse abolido as interfaces DAO da aplicação o esforço para efetuar essa mudança seria muito maior, sem contar que eu perco a liberdade de poder usar outros frameworks de persistência.
    Alguns esquecem que um dos requisitos básicos para um sistema bem projetado é a existência de acomplamento fraco ou abstração entre as camadas , principalmente na camada em questão

  5. kalecser disse:

    Se não abstrair o acesso aos dados, seja ele via framework OR ou não, é impossível testar unitariamente o código, é impossível entregar uma funcionalidade sem modelar a parte de acesso a dados e a sua aplicação terá, de cara, uma dependência estática ainda mais gosmenta que as ditas interfaces e abstrações, o banco de dados :P

  6. Emerson disse:

    Eu uso a abstração para ler de duas fontes de dados de maneira transparente. Ex: Aqui onde trabalho usamos oracle e arquivos VSAM do mainframe. Determinado Business Object pode ser persistido ou em VSAM ou no Oracle. Pode ser feito um create() de um VSAM ou da base Oracle. Isso tudo por motivos que não vem ao caso aqui, porém é a nossa necessidade. Para nós é util essa abstração. Abraço ….

  7. Emerson disse:

    No meu caso como é Oracle e VSAM o Hibernate não resolve meu problema heheh.

  8. No meu caso, não é apenas abstrair o banco de dados, mas abstrair o acesso aos dados. Definir uma interface é mesmo desnecessario se vc já usa um ORM da vida, mas ao menos no meu caso, acho valido criar um componente para eu dizer: ei, me dê os dados e não me preocupar se ele usa criteria, hql, jdbc ou o que seja. A responsabilidade é dele, quero apenas os dados.

    É justamente aí que talvez DAOs tenham uma utilidade que não seja necessariamente abstrair O banco de dados mas sim o acesso aos dados. É mais sobre Separation of Concerns do que sobre ter que mudar o tipo de repositorio.

    valeuz…

  9. Eu to com o Michael e não abro mão. Kung, você pode muito bem encapsular essas chamadas a JDBC direto e geração de XMLs dentro do seu DAO, não precisa abstrair o hibernate em uma segunda camada….

    Rubem, o Michael não tá falando em não usar o DAO! Interfacear o DAO é interessante para os testes sim! mas além disso você já está pagando um preço caro…

  10. Fabio Kung disse:

    Eu estava justamente falando sobre a abstração do Hibernate dentro dos DAOs. Não em criar outra camada de abstração (eu ODEIO o HibernateTemplate do Spring – isso além de odiar o Spring :D).

    Acho que estamos falando a mesma coisa de formas diferentes. Quando eu falei sobre as chamadas a JDBC direto ou geração de XMLs, estava falando sobre novas implementações de seus DAOs, convivendo pacificamente com as implementações sobre o Hibernate / Toplink / iBatis…

    Enfim, o que eu quero dizer é: não concordo com nada que não implemente a interface DAO (ou similares) usando Session / EntityManager.

  11. Tetsuo disse:

    Ixi, falou mal do Spring, tá no sal!!! hehe

    Bem, quanto aos DAOs, eu acho que eles são úteis pra isolar o Hibernate, mantendo tudo quanto é HQL e Criteria em um só lugar, e não espalhado pelo sistema. Isso não requer interfaces (apesar delas serem úteis pra criar mocks de teste) e não aumenta estrondosamente a quantidade de código, apenas move um código que deveria existir de uma forma ou de outra. (obs.: mocks de DAOs são mesmo necessários, sendo que podemos simplesmente usar algum banco em memória, como o HSQLDB?)

    A coisa fica complicada é quando alguém quer criar uma *abstração* sobre o Hibernate, fazendo de conta que tanto faz ser Hibernate, JDBC, iBatis, LDAP, XML, ou qualquer outra coisa. Das duas uma: ou ele nivela por baixo e perde as vantagens de se usar o framework, ou ele usa as features avançadas e torna a ‘abstração’ totalmente amarrada com o Hibernate. E por ‘amarrada’ não quero dizer que ele vá usar HQL diretamente (já que isto está ‘abstraído’), mas sim o lazy-loading, cache e relacionamentos, só pra citar o básico.

    Então, já que é pra usar Hibernate, USE-O, não minta pra si mesmo. Mas não precisa espalhar imports org.hibernate.* por todo o código pra fazer isso :)

    Quanto ao HibernateTemplate do Spring, ele não tenta abstrair o Hibernate, apenas facilita o seu uso. Mas claro, como o Hibernate já é uma abstração sobre JDBC, e tem uma API razoavelmente simples, um outro facilitador talvez seja desnecessário. (Já o JdbcTemplate é muitíssimo útil :))

  12. [...] Blog do Mister M Michael Nascimento Santos em pt-BR « Vale a pena abstrair? [...]

  13. [...] Obviamente não estou pregando a total extinção de todos esses patterns (muito menos o DAO!), apenas lembrando que devemos medir muito bem a necessidade de criar mais classes e mais abstrações, em vez de atacar o problema com mais simplicidade, como o Michael Nascimento também já blogou (duas vezes). [...]