01
A janela não some, ela é trocada por compatibilidade
A migração com janela é simples por um motivo específico: durante a parada existe apenas uma versão do código e uma versão do schema, e por isso o schema pode mudar de forma incompatível sem consequência. Tirar a janela não elimina esse problema, apenas obriga a resolvê-lo de outro jeito. Sem parada, existe pelo menos um intervalo em que a versão antiga e a versão nova do código conversam com o mesmo banco ao mesmo tempo, seja porque o deploy é gradual, seja porque um pod demora a terminar de drenar, seja porque um worker de fila só reinicia quando termina o lote atual.
Daí sai a regra que governa tudo o que vem depois e que é o verdadeiro conteúdo do padrão: cada deploy precisa ser compatível com o deploy imediatamente anterior, tanto no schema quanto no código. Não é compatibilidade com a versão de seis meses atrás, o que seria caro demais, e não é compatibilidade só com a versão final, o que seria justamente o erro. É a vizinhança de dois passos. Uma vez aceita essa restrição, o número de passos deixa de ser negociável: adicionar uma coluna nova, preencher a coluna, passar a ler dela e só então remover a antiga são quatro deploys porque nenhum par consecutivo entre eles quebra, e não porque alguém gosta de burocracia.
MIGRACAO COM JANELA (uma versao viva de cada vez)
[app v1 + schema v1] --- PARADA --- [app v2 + schema v2]
40 min sem
atender ninguem
EXPANDIR / MIGRAR / CONTRAIR (duas versoes vivas por deploy)
D1 expandir schema aceita v1 e v2 app v1 roda intacto
(coluna nova, anulavel)
D2 escrita app escreve nos dois leitura ainda no antigo
dupla campos backfill roda em lotes
D3 leitura app le do campo novo escrita continua dupla
rollback = trocar a flag
D4 contrair app para de escrever no coluna antiga sem leitor
antigo, coluna removida ponto sem volta
^ em nenhum instante existe um par (app, schema) incompativelVale nomear o custo dessa escolha em vez de escondê-lo, porque ele é real e aparece no planejamento de sprint. Uma mudança que caberia em um pull request vira quatro, espalhados por dias ou semanas, e nesse meio tempo o código carrega uma complexidade temporária que precisa ser removida depois. Times que ignoram a última etapa acumulam colunas mortas, escritas duplas esquecidas e flags permanentes, e o preço disso é pago em toda leitura futura daquele arquivo. A contração não é opcional, é a metade da migração que ninguém agenda.