Quando estamos desenvolvendo software, seja ele um produto com desenvolvimento contínuo (como o Wordpress, por exemplo) ou um sistema customizado para um cliente nos deparamos com um problema no mínimo chato de resolver: gerenciar as versões do banco de dados (tabelas, procedures, etc) que evoluem ao longo do projeto. Vou apresentar a vocês em um artigo com duas partes uma solução que tem me trazido paz e segurança nos últimos tempos e que talvez possa te ajudar também.
O problema
Controlar o código fonte que é compilado pela nossa ferramenta de trabalho é uma tarefa que já foi bem complicada, mas que se tornou relativamente fácil com a evolução dos próprios editores de código (Visual Studio) e dos repositórios de código (TFS, SVN, CVS, etc). No entanto, não podemos dizer o mesmo dó código fonte que utilizamos para nossa aplicação acessar bancos de dados. Na maioria da vezes esse código não é compilado e por mais que existam checagens de sintaxe os erros tendem a aparecer na hora que estamos desenvolvendo a versão 2.1 do sistema e precisamos recuperar versão 1.5 para corrigir bugs. Isto, quando esse controle é feito de alguma forma e esse processo é possível, pois na maioria das vezes tudo que as pessoas mantém são os dados no próprio SGBD sem nenhum controle de versão.
Gerenciar a versão do banco de dados quer dizer que no momento em que eu recuperar a versão XYZ do meu sistema também vou conseguir recuperar os artefatos de banco (tabelas, procedures, triggers, etc) correspondentes a esta versão, restaurando desta forma o sistema em um ponto estável tanto do ponto de vista de estrutura quanto do ponto de vista de dados.
Além dos pontos falhos óbvios que essa falta de controle apresenta existe mais um problema que considero grave e que, inclusive prejudica a aplicação de práticas ágeis como integração contínua e testes automatizados. Existindo a necessidade de efetuar esse controle de maneira manual fica impraticável a execução dessas práticas, pois para executá-las durante todo o tempo tudo (incluindo os scripts de banco de dados) que compõe o sistema deve permitir automatização.
As opções existentes
É claro que não posso falar por toda a comunidade de desenvolvimento Microsoft, mas a grande maioria dos projetos que já participei ou conversei a respeito com outros colegas de plataforma tinha pouquissimo (não confiável) ou nenhum controle deste tipo. Geralmente as pessoas efetuam este tipo de controle de duas formas:
Como se fosse código-fonte normal - Scripts de create table, procedures e demais artefatos são mantidos em diversos arquivos SQL (ou em um linguição) no repositório de código e o desenvolvedor utiliza eles na hora em que precisa avançar ou restaurar uma versão. O maior problema desta técnica é que como o desenvolvedor não precisa efetivamente gerar scripts de banco de dados para modificar o banco, pois pode faze-lo pela ferramenta RAD com arrasta-estica-e-puxa dificilmente ele gera esses scripts depois da primeira vez e mais raramente ainda ele gera esses scripts de maneira correta. No final, temos uma salada de scripts: alguns utilizando alter table, outros modificando um script de create já existente, diversas versões da mesma procedure e possívelmente nenhum daqueles scripts de carga feitos pelo joãozinho no começo do projeto. Dessa forma, é impossível ir para a versão de banco de dados desejada de maneira fácil e sem dores de cabeça.
Mantendo tudo no banco de dados - A maioria dos desenvolvedores, infelizmente, se preocupa pouquissimo com o futuro do projeto e estão preocupados apenas com suas tarefas atuais. Dessa forma, qualquer atalho para terminar uma tela mais rápido é bem vindo, mesmo que este atalho cause um grande problema no futuro. Por este motivo, muitas pessoas mantem a estrutura de banco de dados apenas no SGBD. Alguns projetos inclusive não tem nem um modelo de dados em uma ferramenta como o ErWin ou DBDesigner por exemplo. Agora vamos imaginar que por algum motivo o banco de dados de desenvolvimento foi pro espaço. Se não tiver alguém da equipe que mantem um backup local o projeto está perdido. Possívelmente milhões $$$ perdidos por preguiça e falta de organização.
A Microsoft tentou no Visual Studio Team System Database Edition com o projeto de banco de dados (somente para SqlServer) uma alternativa a essas maneiras, mas infelizmente não obteve sucesso. A idéia é manter um projeto que por meio de um banco de dados local simula a compilação dos scripts diminuindo os erros de deploy. No entanto, todo este processo é lento, obriga o desenvolvedor a ter um SqlServer instalado localmente e tem uma série de limitações como não poder acessar outros bancos diferentes do banco com qual o sistema trabalha e de outros providers (Oracle, MySql, etc.). Ainda não testei o VSTS 2010, mas não acredito que seguindo esta receita seja possível obter muito sucesso.
A solução
Para resolver este problema, o ideal seria que pudéssemos tratar dos objetos de banco da mesma maneira que tratamos os objetos do nosso sistema. Objetos que compilam efetivamente nos oferecem mais segurança, ainda mais se estes forem construidos utilizando uma API simples e padronizada que possibilite o deploy em bancos distintos. Melhor ainda se o desenvolvedor não precisar ter muito trabalho para efetuar este controle, pois se o processo exigir muito trabalho ninguém irá utilizá-lo.
No próximo post, vou falar sobre o Migrator.NET que oferece essas características que apresentei no paragráfo anterior de uma maneira rápida e fácil de usar. :)