Migrações de Ganso para Alterações Suaves no Banco de Dados

Olá, amigo!

Hoje, vamos falar sobre o que são migrações de banco de dados e por que elas são tão importantes. No mundo de hoje, não é surpresa que quaisquer mudanças em um banco de dados devem ser feitas com cuidado e de acordo com um processo específico. Idealmente, esses passos estariam integrados em nosso pipeline de CI/CD para que tudo funcione automaticamente.

Aqui está nossa agenda:

  1. Qual é o problema?
  2. Como resolvemos isso?
  3. Um exemplo simples
  4. Um exemplo mais complexo
  5. Recomendações
  6. Resultados
  7. Conclusão

Qual é o Problema?

Se sua equipe nunca lidou com migrações de banco de dados e você não tem certeza de por que elas são necessárias, vamos esclarecer isso. Se você já conhece o básico, sinta-se à vontade para pular.

Desafio Principal

Quando fazemos mudanças “planejadas” e “suaves” no banco de dados, precisamos manter a disponibilidade do serviço e cumprir os requisitos de SLA (para que os usuários não sofram com inatividade ou lentidão). Imagine que você quer mudar o tipo de uma coluna em uma tabela com 5 milhões de usuários. Se você fizer isso “de frente” (ou seja, simplesmente executar ALTER TABLE sem preparação), a tabela pode ficar bloqueada por um tempo significativo — e seus usuários ficariam sem serviço.

Para evitar tais dores de cabeça, siga duas regras:

  1. Aplicar migrações de uma maneira que não bloqueie a tabela (ou pelo menos minimize os bloqueios).
  2. Se precisar alterar o tipo de uma coluna, muitas vezes é mais fácil criar primeiro uma nova coluna com o tipo correto e depois excluir a antiga.

Outro Problema: Controle de Versão e Rollbacks

Às vezes é necessário reverter uma migração.

Fazer isso manualmente — acessando o banco de dados de produção e mexendo nos dados — não é apenas arriscado, mas também provavelmente impossível se você não tiver acesso direto. É aí que as ferramentas de migração dedicadas são úteis. Elas permitem que você aplique alterações de forma limpa e as reverta, se necessário.

Como Resolver? Use as Ferramentas Certas

Cada linguagem e ecossistema tem suas próprias ferramentas de migração:

  • Para Java, Liquibase ou Flyway são comuns.
  • Para Go, uma escolha popular é goose (a que vamos ver aqui).
  • E assim por diante.

Goose: O Que É e Por Que É Útil

Goose é uma utilitário Go leve que ajuda a gerenciar migrações automaticamente. Ele oferece:

  • Simplicidade. Mínimas dependências e uma estrutura de arquivos transparente para migrações.
  • Versatilidade. Suporta diversos drivers de BD (PostgreSQL, MySQL, SQLite, etc.).
  • Flexibilidade. Escreva migrações em SQL ou código Go.

Instalando o Goose

Shell

 

Como Funciona: Estrutura de Migração

Por padrão, o Goose procura por arquivos de migração em db/migrations. Cada migração segue este formato:

Shell

 

  • NNN é o número da migração (por exemplo, 001, 002, etc.).
  • Depois disso, você pode ter qualquer nome descritivo, por exemplo init_schema.
  • A extensão pode ser .sql ou .go.

Exemplo de uma Migração SQL

Arquivo: 001_init_schema.sql:

SQL

 

Nosso Primeiro Exemplo

Alterando o Tipo de uma Coluna (String → Int)

Suponha que temos uma tabela users com uma coluna age do tipo VARCHAR(255). Agora queremos alterá-la para INTEGER. Veja como a migração poderia ser (arquivo 005_change_column_type.sql):

SQL

 

O que está acontecendo aqui:

  1. Migração de Subida

    • Nós alteramos a coluna age para INTEGER. A cláusula USING (age::INTEGER) diz ao PostgreSQL como converter os dados existentes para o novo tipo.
    • Observe que essa migração falhará se houver algum dado em age que não seja numérico. Nesse caso, você precisará de uma estratégia mais complexa (veja abaixo).
  2. Down migration

    • Se fizermos rollback, retornamos age para VARCHAR(255).
    • Novamente usamos USING (age::TEXT) para converter de INTEGER de volta para texto.

Os Segundos e Complexos Casos: Migrações em Múltiplas Etapas

Se a coluna age puder conter dados bagunçados (não apenas números), é mais seguro fazer isso em várias etapas:

  1. Adicione uma nova coluna (age_int) do tipo INTEGER.
  2. Copie os dados válidos para a nova coluna, lidando com ou removendo entradas inválidas.
  3. Exclua a coluna antiga.
SQL

 

Para permitir um rollback adequado, a seção Down apenas reflete as ações em reverso.

Automatização é a Chave

Para economizar tempo, é realmente conveniente adicionar comandos de migração a um Makefile (ou qualquer outro sistema de construção). Abaixo está um exemplo de Makefile com os principais comandos do Goose para o PostgreSQL.

Vamos assumir:

  • O DSN para o banco de dados é postgres://user:password@localhost:5432/dbname?sslmode=disable.
  • Os arquivos de migração estão em db/migrations.
Shell

 

Como usar?

1. Criar uma nova migração (arquivo SQL). Isso gera um arquivo db/migrations/002_add_orders_table.sql.

Shell

 

2. Aplicar todas as migrações. O Goose criará uma tabela schema_migrations no seu banco de dados (se ainda não existir) e aplicará quaisquer novas migrações em ordem ascendente.

Shell

 

3. Reverter a última migração. Apenas desfaça a última.

Shell

 

4. Reverter todas as migrações (use com cautela em produção). Reset completo.

Shell

 

5. Verificar o status da migração.

Shell

 

Exemplo de saída:

Shell

 

Resumo

Ao usar ferramentas de migração e um Makefile, podemos:

  1. Restringir o acesso direto ao banco de dados de produção, fazendo alterações apenas através de migrações.
  2. Acompanhar facilmente as versões do banco de dados e revertê-las se algo der errado.
  3. Manter um histórico único e consistente de alterações no banco de dados.
  4. Realizar migrações “suaves” que não quebrarão um ambiente de produção em execução em um mundo de microsserviços.
  5. Obter validação extra — cada alteração passará por um processo de PR e revisão de código (supondo que você tenha essas configurações em vigor).

Outra vantagem é que é fácil integrar todos esses comandos em seu pipeline de CI/CD. E lembre-se — segurança acima de tudo. 

Por exemplo:

YAML

 

Conclusão e Dicas

As principais ideias são tão simples:

  • Mantenha suas migrações pequenas e frequentes. Elas são mais fáceis de revisar, testar e reverter se necessário.
  • Use a mesma ferramenta em todos os ambientes para que dev, stage e prod estejam em sincronia.
  • Integre migrações no CI/CD para que você não dependa de uma única pessoa executando-as manualmente.

Dessa forma, você terá um processo confiável e controlado para mudar a estrutura do seu banco de dados — um que não quebre a produção e permita que você responda rapidamente se algo der errado.

Boa sorte com suas migrações!

Obrigado pela leitura!

Source:
https://dzone.com/articles/goose-as-crucial-tool-for-your-service