Um requisito não-funcional importante na engenharia de software é a escolha do repositório de dados da aplicação. A princípio, isso não constitui um grande problema. Afinal, durante a construção do sistema, é sulficiente se adaptar a infra-extrutura já existente no estabelecimento que irá usar o sistema. Se não houver um parque de informática definido, é comum escolher um banco de dados gratuito que normalmente atende a maioria das situações ou, mesmo, comprar licenças de uso de algum banco de dados comercial.

O problema começa na manutenção do sistema. A empresa decide, por exemplo, mudar o banco de dados padrão. Isso pode acontecer por vários motivos: contenção de custos, limitações do banco de dados atual, mudança da plataforma, etc. Aí pode ser um transtorno para os desenvolvedores: migrar os dados e modificar o sistema para se adaptar à nova situação. Sem falar nas mudanças e reinstalações que poderão ocorrer nas máquinas dos usuários. E se forem muitos usuários?! E se for pra ontem?! E se o pessoal pra fazer essas mudanças for limitado?! Veja que o desgaste gerado por esta “mudança” pode crescer de maneira exponencial. Eu já passei por isso. Posso garantir que os problemas envolvidos podem exigir várias noites de pesquisas e aprendizado instantâneo para poder continuar merecendo a confiança dos seus superiores. Fui obrigado a mudar duas vezes de plataforma de desenvolvimento em menos de dois anos. Hoje cheguei a conclusão que só existem duas plataformas que se adaptam bem a quase todos os cenários no mundo da micro-informática: .NET ou Java.

Pensando nisso decidi postar algumas considerações visando atingir o tão sonhado grau de indepêndencia de banco de dados.

Vamos analisar a seguinte situação:

Acesso direto a base

Note o seguite:

  1. A aplicação desktop faz acesso direto a base de dados. Todas a regras de negócio e persistência de dados são feitas diretamente pela aplicação. Essa arquitetura é muito utilizada pelos programadores Delphi, VB e similares.
  2. Numa aplicação que utiliza servidor WWW, o browser faz requisições ao servidor que por sua vez acessa a base diretamente, da mesma forma que uma aplicação desktop. Os sites no servidor web contém regras de negócio e são responsáveis pelo acesso aos dados. Isso é comum para programadores ASP, JSP, PHP, ColdFusion e similares.

Uma maneira de atingir a indepêndencia de banco neste contexto é utilizar somente instruções SQL ANSI para persistir dados. Mesmo assim isso possui alguns incovenientes. Numa aplicação desktop que está instalada em várias máquinas, qualquer mudança na regra de negócio implicará em reinstalação em todas as máquinas que fazem uso dessa aplicação. Se forem muitos usuários? Se os usuários não sabem instalar sistema? Certamente o help desk vai ter trabalho dobrado pra implantar a nova versão. Utilizando servidor WWW isso ameniza e muito o problema. Basta atualizar o servidor e tudo bem. Todos os usuários terão a nova versão no seu browser. Mas a depender de como essas páginas foram criadas os programadores terão que atualizar a regra ou as configurações de banco em cada página do site. Sem falar que nem sempre é possível desenvolver com instruções SQL ANSI apenas. Uma função de banco, uma VIEW, procedure ou trigger precisa ser reescrita no momento que o banco for trocado.

Quando eu utilizava o Delphi ou o PHP optei pela seguinte solução: Minhas aplicações serviam apenas como GUI. As regras de negócio e a persistência de dados era responsabilidade das procedures de banco. Usava também usuários de banco, functions, roles e views. Triggers não utilizava por serem um tipo de procedures.

Fig02 Acesso a base por procedure

Quando tinha que mudar alguma regra, apenas fazia nas procedures. Mudanças na GUI eram mínimas. Assim não precisava reinstalar as aplicações Delphi toda vez que mudasse alguma regra da aplicação. No PHP, da mesma forma. Só mudava a página se houvesse extrema necessidade. Era ótimo a princípio. Mas… E a independência de banco??? Assim a situação só piora o problema. Ganha de um jeito, na manutenção da regra e help desk, mas perde na independencia de banco, ou seja, teria que reescrever todas procedures caso mudasse o banco. Conclusão: abandonei completamente o uso das procedures, views, roles, functions, usuários de banco e tudo mais que dependa diretamente do banco de dados. Minhas aplicações tiveram que ser reescritas completamente em outra arquitetura.

Uma solução padrão para o problema da independência de banco é utilizar um padrão de projeto chamado DAO. Isso mesmo, PADRÃO DE PROJETO. Padrão DAO faz parte de um conjunto de padrões que resolvem problemas recorrentes. Mas isso é outra história…

Acesso a base por um DAO

Cria-se um meio, que normalmente é uma classe da orientação a objetos, por onde a aplicação fará todas as chamadas ao banco, de forma que mudar o banco significaria apenas mudar alguns atributos dessa classe. Ou seja, a classe DAO iria se moldando de acordo com algumas informações passadas no seu construtor. É possivel que alguns métodos precisem ser adaptados por causa do SQL. Mas utilizar SQL ANSI diminue bastante esta necessidade. Eu comecei a fazer isso também. O problema maior é que construir uma classe dessas não pode ser um trabalho solitário. A programação da classe cresce muito. Afinal, para que fique boa, todas as possibilidades do SQL tem que estarem previstas: inserts, updates, deletes e selects e para todos os bancos de dados envolvidos. Se não, pode-se construir uma classe DAO com menos recursos e ir aprimorando a medida que necessidades surjam.

Uma solução que eu considero muito boa é construir uma classe DAO que faça uso de algum framework de persistência.

Fig04 Acesso a base por um DAO e persistência

A responsabilidade de persistir os dados fica para o framework que normalmente já vem preparado para utilizar vários bancos de dados, enquanto a classe DAO da aplicação apenas herda essas características. Eu aconselho a utilização de um framework muito bom, tanto para o Java quanto para .NET: o Hibernate.

O Hibernate consegue ser independente de banco de dados devido a algumas características principais:

  1. através de mapeamento de entidades do SGBD como classes da linguagem e via arquivos XML;
  2. ampliando a linguagem SQL para HQL (Hibernate Query Language). Esta linguagem manipula objetos e coleções que, depois, o próprio framework converte para SQL que o SGBD entende. Essa conversão é feita utilizando os arquivos XML de mapeamento, configurações de dialeto do banco e drivers de comunicação. Também pode-se utilizar outras formas de montagem do SQL, por exemplo, utilizando métodos de classes. Esses métodos recebem parâmetros que montam o SQL também utilizando os arquivos XML de mapeamento, configurações de dialeto do banco e drivers de comunicação;

Parece complicado mas não é. Inclusive tudo isso é muito produtivo. Desenvolver aplicações sobre essa ótica aumenta bastante a produtividade. Linhas de cada tabela do banco tornam-se objetos e as colunas, propriedades desses objetos. O resultado dos selects do SQL é visto como coleções de objetos e os DML’s são vistos como metódos das classes de regra de negócio. É responsabilidade do framework converter tudo isso para o SQL que o banco entenda, e essa conversão deve ser de acordo com o dialeto do banco escolhido e definido em algum arquivo de configuração.

Dessa forma mudar de SGBD significa migrar os dados de um banco pra outro, mudar a configuração de dialeto e alterar, se for o caso, os arquivos XML de mapeamento das entidades. Posso garantir que poucas modificações são necessárias para migrar um sistema do SQL Server para Oracle, se voce utilizar um framework de persistência como Hibernate durante o desenvolvimento. Se a migração for, por exemplo, do Firebird para Oracle ou vice-versa as modificações se resumem a uma ou duas linhas no arquivo de configuração, além, claro, da migração dos dados.

Bom, é isso. Espero que este pequeno artigo seja útil e sirva como roteiro pra quem deseja programar com independência de banco.

About these ads