BT

Disseminando conhecimento e inovação em desenvolvimento de software corporativo.

Contribuir

Tópicos

Escolha a região

Início Artigos Como versionar seu databases para DevOps

Como versionar seu databases para DevOps

Pontos Principais

  • Database schema, incluindo índices, precisam estar no controle de versão.

  • Os dados que controlam a lógica de negócios, como tabelas de pesquisa, também precisam estar no controle de versão.

  • Os desenvolvedores precisam criar de uma maneira fácil os databases locais.

  • Shared database should only be updated via a build server.

  • Database compartilhado só deve ser atualizado através de um servidor em desenvolvimento.

Um ambiente robusto DevOps requer integração contínua para os componentes do sistema. Mas frequentemente, o database é omitido, conduzindo a problemas de versões de produção frágeis e práticas de desenvolvimento que tornam a vida dos novos programadores mais difíceis.

Neste artigo, vamos discutir os únicos aspectos de databases, tanto relacionais quanto no NoSQL, em um ambiente bem-sucedido com integração contínua.

Controle de versão para schema

A primeira questão a ser abordada é o controle de versão e os schemas. Não é correto que os desenvolvedores apliquem alterações no database. Isso seria o mesmo que editar arquivos JavaScript diretamente no servidor em produção.

Ao planejar seu controle de versão do database, certifique-se de checar tudo. Isso inclui, mas não se limita a:

  • Tabelas ou coleções;
  • Constraints;
  • Indexes;
  • Views;
  • Stored Procedures, Functions, and Triggers;
  • Configuração do database.

Você deve estar pensando: "Estou usando um banco de dados sem esquemas para não precisar de controle de versão". Mas mesmo assim, é preciso levar em conta os índices e as definições gerais das configurações do database. Se o seu esquema de indexação em QA for diferente no database de produção, será muito difícil executar testes de desempenho significativos.

Existem dois tipos básicos de controle de versão para databases, que chamaremos de "whole-schema" e "change script".

Controle de versão Whole-Schema

O controle de versão whole-schema é aquele no qual o controle de versão se parece com o que é desejado que o banco de dados seja. Ao usar esse padrão, é possível ver todas as tabelas e views dispostas exatamente como deveriam, o que pode facilitar a compreensão do database sem a necessidade de implementá-lo.

Um exemplo de controle de versão whole-schema para o SQL Server é o SQL Server Data Tools (SSDT). Nesta ferramenta, todos os objetos do banco de dados são expressos em termos de scripts CREATE. Isso pode ser conveniente quando se deseja criar um protótipo de um novo objeto usando o SQL e colar o rascunho final diretamente no projeto de banco de dados sob o controle de versão.

Outro exemplo de controle de versão whole-schema são as Entity Framework Migrations. Ao invés de scripts SQL, o database é representado principalmente por classes C#/VB. Mas novamente, é possível obter uma boa imagem do banco de dados navegando no código-fonte.

Trabalhando com o controle de versão whole-schema, você geralmente não escreve diretamente os scripts de migração. As ferramentas de implantação descobrem para você quais alterações são necessárias e comparam o estado atual do banco de dados com a versão idealizada no controle de versão. Isso permite que você faça as alterações no banco de dados e veja essas alterações de uma maneira mais rápida. Ao usar esse tipo de ferramenta, raramente altero o banco de dados diretamente e, em vez disso, permito que a ferramenta faça a maior parte do trabalho.

Ocasionalmente, as ferramentas não serão suficientes, mesmo com scripts pré e pós-implantação. Nesses casos, o script de migração gerado precisará ser modificado manualmente por um desenvolvedor ou DBA, que pode interromper seu esquema de implantação contínua. Isso geralmente acontece quando há grandes alterações na estrutura de uma tabela, pois o script de migração gerado pode ser ineficiente nesses casos.

Outra vantagem do controle de versão whole-schema é o suporte a análise de código. Por exemplo, se você alterar o nome de uma coluna, mas esquecer de alterá-la em uma view, o SSDT retornará um erro de compilação. Assim como a tipagem estática em linguagens de programação, que detecta muitos erros e impede que você tente implantar scripts quebrados.

Controle de versão Change Script

A outra opção de controle de versão é o "change script". Em vez de armazenar os próprios objetos de banco de dados, você armazena a lista dos passos necessários para criar os objetos de banco de dados. O que eu usei com sucesso no passado é o Liquibase, mas todos funcionam da mesma forma.

A principal vantagem da ferramenta de change script (alteração de script) é ter o controle total do script e ver o resultado no final da migração. Isso facilita a execução de alterações complexas, como das tabelas quando são divididas ou combinadas.

Infelizmente, existem várias desvantagens nesse estilo de controle de versão. A primeira é a necessidade de escrever as alterações dos scripts. Você terá mais controle, só que consome muito tempo. É muito mais fácil adicionar uma propriedade a uma classe C# do que escrever o script ALTER TABLE manualmente..

Isso se torna ainda mais problemático ao trabalhar com coisas como SchemaBinding. Para quem não está familiarizado com o termo, isso habilita alguns recursos avançados do SQL Server, bloqueando o schema da tabela. Se você fizer alterações no design de uma tabela ou view, primeiro remova o SchemaBinding de qualquer view que toque na tabela ou view. E se essas views forem vistas pelo schema-bound e por outras views, também é necessário desconectá-las temporariamente. Todo esse clichê, embora seja fácil gerar com uma ferramenta whole-schema de controle de versão, e é difícil de se executar manualmente.

Outra desvantagem das ferramentas de alterações de script é que elas tendem a ser opacas. Por exemplo, se quiser conhecer as colunas em uma tabela sem implementá-la, precisará ler todos os scripts de alteração que tocam na tabela.

Qual controle de versão utilizar?

Ao iniciar um novo projeto de database, sempre escolho o controle de versão whole-schema, quando disponível. Isso permite que os desenvolvedores trabalhem mais rápido e não requer conhecimento para usar, desde que tenha uma pessoa para configurá-lo corretamente.

Para databases existentes, especialmente os que estão em produção há vários anos, a alteração do script pelo controle da versão geralmente é mais apropriada. As ferramentas whole-schema fazem certas suposições sobre o design do banco de dados, enquanto as ferramentas de alterações de script funcionam com qualquer banco de dados. Além disso, as ferramentas whole-schema são mais difíceis de construir, portanto, podem simplesmente não estar disponíveis para um database específico.

Gestão de Dados

As tabelas podem ser amplamente classificadas como "managed", "user" ou "hybrid", dependendo da natureza dos dados que contêm. A maneira como são tratadas essas tabelas é diferente dependendo da categoria em que se enquadram.

Tabelas Gerenciadas

Um erro comum ao colocar databases em um controle de versão é esquecer os dados. Invariavelmente, haverá "tabelas de pesquisa" que contêm dados que os usuários não devem modificar. Por exemplo, pode conter lógica de unidade de tabela para regras de negócios, os vários códigos de status de máquina ou apenas uma lista de pares de valores-chave que correspondem a uma enumeração no código do aplicativo.

Os dados neste tipo de tabela devem ser tratados como código fonte. As alterações precisam passar pelo mesmo processo de revisão e QA (Controle de qualidade) que você usaria para qualquer outra alteração de código. E é especialmente importante que as alterações sejam implementadas automaticamente com outras implantações de aplicativos e databases, caso contrário essas alterações poderão ser acidentalmente esquecidas.

No SQL Server Data Tools, eu trato usando um script pós-implantação. Neste script, preencho uma tabela temporária com a aparência dos dados e em seguida uso uma instrução MERGE para atualizar a tabela real.

Se a sua ferramenta de controle de versão não lida bem com isso, você poderá criar uma ferramenta autônoma para executar as atualizações de dados. O importante não é como você fará isso, e sim se o processo será fácil de usar e confiável.

Tabelas de Usuários

Tabelas de usuário são aquelas tabelas em que o usuário pode adicionar ou modificar os dados. Para nossos propósitos, isso inclui as tabelas que podem modificar diretamente (por exemplo, nome e endereço) e as tabelas modificadas indiretamente por suas ações (por exemplo, recibos de remessa, logs).

Dados reais do usuário quase nunca são adicionados diretamente ao controle de versão. No entanto, é uma boa prática ter dados reais disponíveis para desenvolvimento e teste. Isso pode estar direto no projeto do banco de dados, armazenado em outros lugares como no controle de versão, ou se particularmente grande, mantido em um compartilhamento de arquivos separados.

Tabelas Híbridas

Uma tabela híbrida é aquela que armazena dados gerenciados e do usuário. Existem duas maneiras de particionar.

Uma partição de coluna é quando os usuários podem modificar algumas colunas, mas não outras. Nesse cenário, você trata a tabela como uma tabela gerenciada normal, mas com a restrição, você nunca atualiza uma coluna controlada pelo usuário.

A partição de linha é quando você tem certos registros que os usuários não podem modificar. Um cenário comum que encontrei é a necessidade de valores codificados na tabela usuários. Em sistemas maiores, posso ter uma ID de usuário separado para cada micro-serviço que possa realizar as alterações independentemente de qualquer pessoa. Por exemplo, um usuário pode ser chamado de "Importador de dados bancários".

A melhor maneira que encontrei para gerenciar tabelas híbridas particionadas por linha é através de chaves reservadas. Quando defino a coluna identity/auto-number, defino o valor inicial como 1.000, deixando os usuários de 1 a 999 para serem gerenciados por meio do controle de versão. Isso requer um banco de dados que permita definir manualmente um valor em uma coluna identity. No SQL Server, isso é feito através do comando SET IDENTITY_INSERT.

Outra opção para tratar esse cenário é ter uma coluna chamada "SystemControlled" ou algo do tipo. Quando definido como 1/true, isso significa que a aplicação não permitirá modificações diretas. Se definido como 0/false, os scripts de implantação saberão ignorá-lo.

Databases para desenvolvedores individuais

Depois de ter o schema e os dados sob controle de versão, e o próximo passo é começar a configurar os databases individuais para cada desenvolvedor. Assim como cada desenvolvedor deve ser capaz de executar sua própria instância de um servidor web, e o desenvolvedor que estiver modificando o design do database precisará ser capaz de executar sua própria cópia.

Esta regra é quebrada frequentemente, em detrimento da equipe de desenvolvimento. Invariavelmente, os desenvolvedores que fazem alterações em um ambiente compartilhado interferem em outros databases. Podem até entrar em "duelos de implantação", no qual dois desenvolvedores tentam implantar alterações no database. Quando isso acontece com uma ferramenta whole-schema, a ferramenta revertem alternadamente as alterações e os desenvolvedores nem percebem. Se estiverem usando uma ferramenta de script de alteração, o database pode ser colocado em um estado indeterminado, no qual os scripts de migração não funcionam mais e precisem ser restaurados a partir dos backups..

Outra questão é o schema drift. É quando o database de desenvolvimento não corresponde mais ao que está no controle de versão. Com o tempo, os databases tendem a acumular tabelas que não são de produção, scripts de teste, views temporárias e outros itens a serem limpos. Isso é muito mais fácil quando cada desenvolvedor tem seu próprio banco de dados e pode redefinir quando quiser.

Por último e mais importante é que os serviços e desenvolvedores UI precisam de uma plataforma estável para escrever seu código. Se o database compartilhado estiver constantemente em fluxo, não funcionam eficientemente. Em uma empresa em que trabalhei, não era comum ver os desenvolvedores gritarem: "os serviços caíram novamente" e depois passar uma hora jogando videogame enquanto o database era restaurado.

Desenvolvimento compartilhado e databases de integração

A regra número um para o desenvolvimento compartilhado ou database de integração é que não se deve modificar diretamente o banco de dados. A única maneira de atualizar um database compartilhado é através do servidor e do processo de integração e implementação contínua. Isso não apenas evita o schema drift, como também permite atualizações agendadas para reduzir interrupções.

Como regra geral, permito que o database compartilhado do desenvolvedor seja atualizado sempre que um check-in for feito na branch relevante. Isso pode ser um pouco perturbador, mas geralmente é gerenciável. E você precisa de um local para verificar os scripts de implantação antes que eles atinjam a integração.

Para meus bancos de dados de integração, costumo agendar as implantações uma vez por dia, juntamente com serviços. Isso fornece uma plataforma estável na qual os desenvolvedores da interface do usuário possam trabalhar. Poucos coisas são tão frustrantes para os desenvolvedores da interface do usuário, como não saber se o código que de repente começa a falhar foi um erro ou um problema nos serviços/banco de dados.

Segurança do database e controle de versão

Um aspecto frequentemente esquecido no gerenciamento de databases é a segurança. Especificamente, quais usuários, funções e tabelas que terão acessos as views e stored procedures. No pior cenário, a aplicação obtém acesso total ao database. Podendo ler e gravar em todas as colunas de todas as tabelas, mesmo nas que não tem nenhum interesse em tocar. As violações de dados geralmente resultam na exploração de falhas de uma aplicação com menos utilidade e com mais direitos de acesso do que o necessário.

A principal objeção para bloquear o database é "não sabemos o que irá parar". Como nunca foi bloqueado antes, os desenvolvedores literalmente não têm idéia de quais permissões a aplicação precisa.

A solução é colocar as permissões no controle de versão desde o ínicio. Dessa forma, quando o desenvolvedor que for testar a aplicação, falhará desde o início se as permissões estiverem incorretas. Isso significa, que quando chegar ao QA, todas as permissões serão resolvidas e não haverá adivinhação ou risco de uma permissão negada.

Conteinerização

Dependendo da natureza do seu projeto, a conteinerização do seu database pode ser um passo opcional. Para ilustrar o motivo, vou apresentar dois casos de uso.

Para o nosso primeiro caso de uso, o projeto possui uma estrutura de branches bem simples: existe uma branch "dev" que alimenta a branch da QA, que por sua vez alimenta a Staging e finalmente a Production. Isso pode ser tratado por quatro databases compartilhados, um para cada estágio na pipeline.

No segundo caso de uso, temos um conjunto das principais feature branches. Cada feature branch é subdividida em uma branch de desenvolvimento e uma de QA. Essas features precisam passar pela QA antes de se candidatarem ao merge na branch principal, ou seja, cada feature principal precisa do seu próprio ambiente de teste.

No primeiro caso, a conteinerização é provavelmente perda de tempo mesmo que seus serviços Web precisem de containers. Para o segundo caso, a conteinerização de algum tipo é crítica. Se não forem containers reais (por exemplo, Docker), pelo menos os scripts de implantação que possam gerar novos ambientes conforme necessário (por exemplo, AWS ou Azure) ao criar novas ramificações principais de recursos.

Sobre o autor

Jonathan Allen começou a trabalhar em projetos de MIS para uma clínica de saúde no final dos anos 90, trazendo-os do Access e Excel para uma solução empresarial em degraus. Depois de passar cinco anos escrevendo sistemas de negociação automatizados para o setor financeiro, ele se tornou consultor em uma variedade de projetos, incluindo a interface do usuário para um armazém de robótica, a camada intermediária do software de pesquisa de câncer e as necessidades de big data em uma grande companhia de seguros imobiliários. Em seu tempo livre, ele gosta de estudar e escrever sobre artes marciais do século XVI.

Avalie esse artigo

Relevância
Estilo/Redação

Conteúdo educacional

BT