Estratégias de deploy de schema com migrations reversíveis

1. Fundamentos das Migrations Reversíveis

Migrations são scripts que alteram a estrutura do banco de dados ao longo do tempo. Uma migration reversível contém duas direções: up() (aplica a mudança) e down() (desfaz a mudança). Em ambientes de produção, a reversibilidade não é opcional — é uma necessidade operacional.

-- Exemplo de migration reversível (SQL)
-- Migration: adicionar coluna email_verified

-- UP
ALTER TABLE usuarios ADD COLUMN email_verified BOOLEAN DEFAULT FALSE;

-- DOWN
ALTER TABLE usuarios DROP COLUMN email_verified;

A diferença entre rollback automático e manual é crítica: ferramentas como Flyway ou Liquibase permitem rollback automático desde que o down() esteja bem definido. Rollback manual é arriscado e deve ser evitado em produção.

2. Modelagem de Migrations com Reversão Segura

Cada migration deve seguir uma estrutura padrão com up() e down(). A regra de ouro para o down() é: nunca perder dados permanentemente.

-- Migration v1.1: adicionar tabela de endereços

-- UP
CREATE TABLE enderecos (
    id SERIAL PRIMARY KEY,
    usuario_id INTEGER NOT NULL REFERENCES usuarios(id),
    rua VARCHAR(200),
    cidade VARCHAR(100),
    criado_em TIMESTAMP DEFAULT NOW()
);

-- DOWN
-- Backup antes de dropar
CREATE TABLE enderecos_backup_v1_1 AS SELECT * FROM enderecos;
DROP TABLE enderecos;

Versionamento semântico de schemas (v1.0, v1.1, v2.0) ajuda a rastrear mudanças e planejar reversões complexas.

3. Estratégias de Deploy em Múltiplos Ambientes

Um pipeline típico de deploy de schema segue: dev → staging → produção. Cada ambiente deve ter seu próprio conjunto de migrations versionadas.

# Estrutura de branches para migrations
main/
├── migrations/
│   ├── v1.0_initial.sql
│   ├── v1.1_add_enderecos.sql
│   └── v1.2_add_telefone.sql

# Tags para controle de versão
git tag v1.0-staging
git tag v1.0-production
git tag v1.1-staging

Testes automatizados de reversão são obrigatórios antes de qualquer deploy em produção:

# Script de teste de reversão (exemplo conceitual)
1. Aplicar migration v1.1 em staging
2. Verificar integridade dos dados
3. Executar rollback para v1.0
4. Verificar se dados foram preservados
5. Repetir o ciclo 3 vezes

4. Técnicas de Reversão Parcial e Total

Reversão de uma única migration (rollback específico):

-- Reverter apenas a migration v1.2
-- Executar apenas o down() da v1.2
ALTER TABLE usuarios DROP COLUMN telefone;

Reversão em lote (rollback de múltiplas versões):

-- Reverter da v1.3 para v1.0
-- Executar down() da v1.3
-- Executar down() da v1.2
-- Executar down() da v1.1

Reversão com validação de integridade referencial:

-- Verificar chaves estrangeiras antes de dropar tabela
SELECT COUNT(*) FROM enderecos WHERE usuario_id NOT IN (SELECT id FROM usuarios);
-- Se zero, pode dropar com segurança

5. Gerenciamento de Dados Durante Reversões

Preservação de dados críticos em down() é feita com backup temporário:

-- Estratégia de backup em down()
CREATE TABLE backup_usuarios_telefone AS 
SELECT id, telefone FROM usuarios;

ALTER TABLE usuarios DROP COLUMN telefone;

Para colunas com valores default ou nulos:

-- UP: adicionar coluna com default
ALTER TABLE usuarios ADD COLUMN plano VARCHAR(20) DEFAULT 'basico';

-- DOWN: preservar dados antes de dropar
UPDATE usuarios SET plano = NULL WHERE plano = 'basico';
ALTER TABLE usuarios DROP COLUMN plano;

Reversão com migração de dados (transformação de tipos):

-- UP: mudar tipo de coluna
ALTER TABLE usuarios ALTER COLUMN idade TYPE VARCHAR(3);

-- DOWN: converter de volta com validação
UPDATE usuarios SET idade = CAST(idade AS INTEGER)::TEXT 
WHERE idade ~ '^\d+$';
ALTER TABLE usuarios ALTER COLUMN idade TYPE INTEGER USING idade::INTEGER;

6. Ferramentas e Frameworks de Suporte

Flyway (Java/Spring):

-- Configuração de migration reversível no Flyway
-- Arquivo: V1_1__add_email_verified.sql

-- UP
ALTER TABLE usuarios ADD COLUMN email_verified BOOLEAN;

-- Arquivo: U1_1__add_email_verified.sql (undo)
-- DOWN
ALTER TABLE usuarios DROP COLUMN email_verified;

Liquibase (XML/YAML/JSON):

-- changeset.xml
<changeSet id="1" author="dev">
    <addColumn tableName="usuarios">
        <column name="email_verified" type="BOOLEAN"/>
    </addColumn>
    <rollback>
        <dropColumn tableName="usuarios" columnName="email_verified"/>
    </rollback>
</changeSet>

Alembic (Python):

# migration.py
def upgrade():
    op.add_column('usuarios', sa.Column('email_verified', sa.Boolean()))

def downgrade():
    op.drop_column('usuarios', 'email_verified')

ActiveRecord (Rails):

class AddEmailVerifiedToUsuarios < ActiveRecord::Migration[7.0]
  def change
    add_column :usuarios, :email_verified, :boolean, default: false
  end
end

Hooks de pré e pós-migration:

# Hook pré-migration: backup automático
before_migration:
  - pg_dump -U user -d database > backup_$(date +%Y%m%d).sql

# Hook pós-migration: validação
after_migration:
  - python validate_schema.py

7. Casos Complexos e Armadilhas Comuns

Reversão de migrations com índices ou constraints únicas:

-- UP: adicionar índice único
CREATE UNIQUE INDEX idx_email_unique ON usuarios(email);

-- DOWN: remover índice
DROP INDEX IF EXISTS idx_email_unique;
-- Cuidado: se houver duplicatas, o índice não pode ser recriado depois

Dependências entre migrations:

-- Migration v1.1: criar tabela dependente
CREATE TABLE pedidos (id SERIAL PRIMARY KEY, usuario_id INTEGER REFERENCES usuarios(id));

-- Migration v1.2: adicionar coluna em usuarios
ALTER TABLE usuarios ADD COLUMN ultimo_pedido_id INTEGER REFERENCES pedidos(id);

-- Ordem de reversão: v1.2 primeiro, depois v1.1

Reversão em sistemas com alta concorrência:

-- Usar lock de tabela durante reversão
LOCK TABLE usuarios IN ACCESS EXCLUSIVE MODE;
ALTER TABLE usuarios DROP COLUMN email_verified;
-- Libera lock automaticamente ao final da transação

8. Boas Práticas e Checklist Final

  • [ ] Revisão de código de down() por pares: outro desenvolvedor deve validar se o rollback não perde dados
  • [ ] Testes de estresse com reversões em staging: execute rollback e forward 10 vezes seguidas
  • [ ] Documentação de cada migration: inclua justificativa da reversão e riscos conhecidos
# Template de documentação de migration
Migration: v1.1_add_email_verified
Autor: João Silva
Data: 2024-01-15
Descrição: Adiciona flag de verificação de email
Justificativa de reversão: Se houver problemas de performance na consulta
Riscos: Perda de dados se usuários já estiverem verificados

Checklist final antes do deploy em produção:

  1. Backup completo do banco antes de qualquer migration
  2. Teste de reversão em staging com dados similares à produção
  3. Monitoramento de logs durante a execução
  4. Plano de contingência para rollback manual se automático falhar
  5. Comunicação à equipe sobre a janela de manutenção

Referências