Database migrations em times grandes: evitando conflitos de merge
1. O Problema dos Conflitos de Merge em Migrations
1.1. Causas comuns: numeração sequencial, dependências implícitas e alterações simultâneas
Em times grandes, múltiplos desenvolvedores trabalham simultaneamente em diferentes branches. O uso de numeração sequencial para migrations (ex: 001_create_users.sql, 002_add_email.sql) gera conflitos frequentes quando duas pessoas criam a migration 003 ao mesmo tempo. Dependências implícitas entre migrations — como uma migration que referencia uma coluna criada em outra — também causam quebras silenciosas. Alterações simultâneas no mesmo schema (ex: dois times modificando a tabela orders) levam a conflitos complexos de resolver.
1.2. Impacto no fluxo de desenvolvimento: bloqueios, retrabalho e perda de dados
Conflitos de merge em migrations podem bloquear deploys por horas, exigir retrabalho manual para renumerar arquivos e, em casos extremos, causar perda de dados se uma migration for aplicada na ordem errada. Times relatam que até 30% dos merges em projetos com muitas migrations envolvem algum tipo de conflito.
1.3. Diferença entre conflitos de schema e conflitos de dados
Conflitos de schema envolvem definições estruturais (colunas, tabelas, índices) e geralmente são resolvidos com merge de arquivos. Conflitos de dados ocorrem quando migrations de seed ou transformação de dados competem pelo mesmo registro — estes são mais perigosos e exigem coordenação cuidadosa.
2. Estratégias de Versionamento para Evitar Conflitos
2.1. Timestamps vs. sequenciais: vantagens do uso de carimbo de data/hora
Substituir numeração sequencial por timestamps (ex: 20250101120000_create_users.sql) reduz drasticamente conflitos, pois dois desenvolvedores raramente geram o mesmo timestamp. Ferramentas como Flyway e Alembic suportam nativamente esse formato.
-- Exemplo de nome de migration com timestamp
20250101120000_create_users.sql
20250101123045_add_email_to_users.sql
20250101124510_create_orders.sql
2.2. Prefixos por equipe ou módulo: isolando namespaces de migração
Atribuir prefixos por equipe (ex: team_a_001, team_b_001) ou por módulo (billing_001, auth_001) isola os namespaces. Cada equipe gerencia sua sequência independentemente, eliminando conflitos entre times.
-- Estrutura de diretórios com prefixos por módulo
migrations/
billing/
billing_001_create_invoices.sql
billing_002_add_tax_column.sql
auth/
auth_001_create_users.sql
auth_002_add_roles.sql
2.3. Hash-based versionamento: garantindo unicidade sem coordenação central
Usar hashes (SHA-256 do conteúdo) como identificador único garante que migrations diferentes sempre tenham nomes distintos. O hash é calculado automaticamente e não requer coordenação.
-- Exemplo de migration nomeada por hash
migrations/
a1b2c3d4_create_users.sql
e5f6g7h8_add_email_index.sql
3. Boas Práticas de Estruturação de Migrations
3.1. Migrações atômicas e reversíveis: cada migration foca em uma única mudança
Cada migration deve fazer exatamente uma alteração (ex: adicionar uma coluna, criar uma tabela) e ser reversível. Isso facilita rollbacks e reduz dependências.
-- Migration atômica: adicionar coluna
-- UP
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
-- DOWN
ALTER TABLE users DROP COLUMN phone;
3.2. Separação entre schema e dados: migrations de estrutura vs. migrations de seed
Mantenha migrations de schema (DDL) separadas de migrations de dados (DML/seed). Schemas mudam com menos frequência e podem ser versionadas de forma mais rigorosa.
-- migrations/schema/20250101_create_users.sql
CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT);
-- migrations/seed/20250101_insert_admin_user.sql
INSERT INTO users (name) VALUES ('admin');
3.3. Uso de diretórios por sprint ou release: organização temporal e lógica
Organize migrations em diretórios por sprint (ex: sprint_01, sprint_02) ou release (v2.0, v2.1). Isso facilita a revisão e o rollback de releases inteiras.
migrations/
release_v2.0/
001_create_users.sql
002_add_email.sql
release_v2.1/
001_add_phone.sql
4. Ferramentas e Automação para Prevenção de Conflitos
4.1. Linters e validadores de migrations: detecção de duplicatas e dependências quebradas
Ferramentas como flyway-validator ou alembic-check detectam migrations duplicadas, dependências circulares e quebras de schema antes do merge.
# Comando de validação com Flyway
flyway validate -url=jdbc:postgresql://localhost/mydb
4.2. Hooks de pre-commit e CI: checagem automática de ordem e integridade
Configure hooks de pre-commit que verificam se as migrations estão em ordem cronológica e se não há duplicatas. Na CI, execute validações completas.
# .pre-commit-config.yaml
repos:
- repo: https://github.com/flyway/flyway
rev: v9.0.0
hooks:
- id: flyway-validate
4.3. Ferramentas de migração distribuída (ex: Flyway, Alembic, Liquibase) com suporte a merge
Flyway suporta migrations baseadas em timestamp e resolução automática de conflitos. Alembic permite ramificação e merge de branches de migração. Liquibase usa changelogs XML/YAML que facilitam merges.
# Exemplo de changelog Liquibase com merge-friendly structure
databaseChangeLog:
- include:
file: migrations/v1.0/changelog.xml
- include:
file: migrations/v1.1/changelog.xml
5. Processos de Revisão e Coordenação Entre Times
5.1. Pull requests específicos para migrations: revisão obrigatória e checklist
Crie PRs exclusivos para migrations, com checklist obrigatório: (1) migration é reversível? (2) nome segue convenção? (3) não há dependências quebradas?
5.2. Reuniões de alinhamento de schema: comunicação cross-team sobre mudanças impactantes
Realize reuniões semanais de alinhamento de schema onde times compartilham mudanças planejadas. Isso evita que dois times modifiquem a mesma tabela simultaneamente.
5.3. Feature flags e migrations condicionais: evitando bloqueios em deploys simultâneos
Use feature flags para controlar quando uma migration é aplicada. Migrações condicionais (ex: IF NOT EXISTS) permitem que o mesmo script seja executado múltiplas vezes sem erro.
-- Migration condicional
ALTER TABLE users ADD COLUMN IF NOT EXISTS phone VARCHAR(20);
6. Estratégias de Merge e Resolução de Conflitos
6.1. Merge hierárquico: resolver conflitos de migrations antes de outros arquivos
Resolva conflitos de migrations primeiro, antes de outros arquivos de código. Isso evita que problemas de schema bloqueiem o merge de funcionalidades.
6.2. Rebase vs. merge: quando usar cada um para minimizar conflitos
Use rebase para branches curtos com poucas migrations — isso mantém um histórico linear. Use merge para branches longos com muitas migrations, pois rebase pode causar retrabalho excessivo.
6.3. Ferramentas de diff específicas para SQL: visualizando mudanças de schema
Ferramentas como pgdiff ou sqldiff mostram diferenças entre schemas de forma clara, facilitando a identificação de conflitos.
# Comparando schemas com pgdiff
pgdiff --source old_schema.sql --target new_schema.sql
7. Monitoramento e Rollback em Produção
7.1. Logs e métricas de execução de migrations: identificando falhas em tempo real
Implemente logging detalhado de cada migration executada, incluindo tempo de execução, status e erros. Use métricas para detectar migrations lentas ou falhas recorrentes.
7.2. Estratégias de rollback seguro: downgrade automático e manual
Mantenha scripts de downgrade para cada migration. Em produção, prefira rollbacks automáticos com validação prévia em staging.
-- Script de downgrade automático
-- DOWN
ALTER TABLE users DROP COLUMN phone;
7.3. Testes de integração com migrations: validação em ambiente de staging antes do deploy
Execute todas as migrations em staging com dados de teste realistas antes de aplicar em produção. Automatize testes que verificam a integridade dos dados após cada migration.
Referências
- Flyway Documentation: Versioned Migrations — Documentação oficial sobre versionamento de migrations com timestamps e estratégias de merge.
- Alembic Documentation: Branching and Merging — Guia completo sobre como usar branches e merge em migrations com Alembic.
- Liquibase Documentation: Best Practices for Large Teams — Boas práticas recomendadas pela Liquibase para times grandes, incluindo organização de changelogs.
- Martin Fowler: Database Migration — Artigo clássico sobre evolução de banco de dados e estratégias para evitar conflitos.
- GitLab: Database Migration Guidelines — Guia de estilo e boas práticas para migrations adotado pelo GitLab, incluindo revisão e CI.
- PostgreSQL: ALTER TABLE Documentation — Documentação oficial sobre comandos DDL usados em migrations, com exemplos de condicionais.