🌿 Strangler Fig Pattern
A migração mais segura que existe: o novo sistema cresce ao redor do antigo, como uma figueira estranguladora. Cada nova feature vai para o sistema novo, cada módulo migrado é redirecionado. O sistema antigo encolhe gradualmente até desaparecer. Zero big-bang, zero downtime.
💡 Como Funciona
- •Proxy/Router layer — Um proxy roteia requests entre sistema antigo e novo
- •Migração gradual — Um módulo por vez é reimplementado no novo sistema
- •Rollback safety — Se algo falhar, o proxy volta a rotear para o antigo
- •Feature parity tracking — Dashboard mostra % do tráfego já migrado
📊 Caso Real: The Guardian
Martin Fowler documentou o padrão no caso do The Guardian:
- Sistema antigo: Monolito Java legado com 10+ anos
- Sistema novo: Scala/Play Framework
- Estratégia: Cada seção do site migrada individualmente (esportes, cultura, notícias)
- Timeline: Anos, não meses — e isso é esperado
- Resultado: Zero downtime durante toda a migração
⚠️ Por que Reescritas Big-Bang Falham
Dados do Standish Group mostram que 70% das reescritas big-bang falham:
- •O sistema antigo continua recebendo features durante a reescrita
- •O novo sistema nunca alcança feature parity
- •O budget acaba antes da migração completar — ficam com dois sistemas
💡 Dica Prática
Comece pelo módulo com menor acoplamento e maior dor. Se o módulo de busca é lento e tem interface clara, migre primeiro. Vitórias rápidas criam momentum e confiança no processo.
🔀 Branch by Abstraction
Mudar implementação sem mudar interface. Introduza uma abstração entre consumidores e a implementação que vai mudar. Troque a implementação por trás da abstração. Remova a abstração quando a migração estiver completa. Ninguém que usa o componente percebe a mudança.
🛠️ 4 Passos do Branch by Abstraction
Criar abstração
Introduza uma interface entre os consumidores e a implementação atual. Todos passam a usar a interface.
Implementar nova versão
Crie a nova implementação atrás da mesma interface. Rode ambas em paralelo.
Comparar e validar
Compare resultados das duas implementações. Shadow traffic: requests reais vão para ambas, só a antiga responde ao usuário.
Switchover e cleanup
Aponte para a nova implementação. Remova a antiga. Opcionalmente, remova a abstração se não for mais necessária.
📊 Caso Real: Flickr
O Flickr migrou de MySQL para PostgreSQL usando Branch by Abstraction — criaram uma interface de “data store”, rodaram ambos em paralelo por semanas comparando resultados, e fizeram o switch quando tinham 100% de confiança que os resultados eram idênticos.
💡 Dica Prática
Branch by Abstraction funciona melhor quando a interface já existe naturalmente. Se você precisa criar uma abstração muito forçada, talvez Strangler Fig seja mais adequado. Escolha a estratégia que se encaixa na arquitetura atual.
🐦 Canary Releases
Testar em produção com rede de segurança. Deploy da nova versão para um pequeno percentual de usuários (1-5%). Monitorar métricas. Se tudo estiver ok, aumentar gradualmente. Se não, rollback instantâneo. Staging não pega tudo — produção tem dados, carga e comportamentos únicos.
💡 Progressive Rollout
- •1% — Deploy inicial. Monitorar error rate, latência, conversão por 1-24h
- •5% — Se métricas ok, expandir. Volume suficiente para detectar edge cases
- •25% — Volume significativo. Se sobreviver aqui, provavelmente está ok
- •100% — Rollout completo. Manter versão anterior pronta para rollback por 24-48h
📊 Caso Real: Google Gmail
O Google faz canary de toda mudança no Gmail:
- 0.1% dos usuários primeiro, por 24 horas
- Automatic rollback se error rate > baseline
- 1.8 bilhões de usuários protegidos de bugs que staging não pegou
- Observabilidade extrema — métricas, logs, traces em cada stage
✓ O que FAZER
- ✓Definir automatic rollback triggers antes do deploy
- ✓Monitorar business metrics além de métricas técnicas
- ✓Manter versão anterior pronta para rollback instantâneo
✗ O que NÃO fazer
- ✗Fazer canary sem observabilidade adequada
- ✗Pular de 1% para 100% porque “parece ok”
- ✗Fazer canary em sexta-feira à tarde
🏗️ Database Migration Strategies
O problema mais difícil de migração. Código é stateless — você reescreve e deploya. Banco de dados é stateful — tem dados reais, schemas complexos e dependências que não aparecem no diagrama. Migrar banco errado é a decisão mais cara para reverter.
💡 Estratégias de Migração de Banco
- •Dual-write — Escrever nos dois bancos simultaneamente durante a transição
- •Shadow traffic — Enviar reads para ambos, comparar resultados, servir do antigo
- •Schema versioning — Migrações backward-compatible, nunca breaking changes diretas
- •Expand-contract — Adicione nova coluna, migre dados, remova antiga (3 deploys)
📊 Caso Real: GitHub
O GitHub migrou de MySQL para Vitess (MySQL sharded) sem downtime para 100M+ repositórios:
- Dual-write por 6 meses, comparando resultados antes de cortar
- Shadow reads validavam consistência entre os dois sistemas
- Zero downtime — usuários nunca perceberam a migração
- Rollback plan testado semanalmente durante todo o processo
⚠️ Armadilhas de Migração de Banco
- •Stored procedures — Lógica de negócio escondida no banco que ninguém lembra
- •Implicit schemas — JSON columns sem validação; dados em formatos inesperados
- •Data volume — Migrar 1TB de dados leva tempo; planeje janelas de manutencão
💡 Dica Prática
Regra de ouro para migrações de schema: nunca faça breaking changes em um único deploy. Use o padrão expand-contract: (1) adicione nova coluna, (2) migre dados e código, (3) remova coluna antiga. Três deploys, zero downtime.
🚩 Feature Flags
O botão de liga/desliga em produção. Feature flags são lógica condicional que ativa ou desativa funcionalidades sem deploy. Permitem trunk-based development, A/B testing e kill switch para features problemáticas. Desacoplam deploy de release.
💡 Tipos de Feature Flags
- •Release flags — Ativa/desativa features novas. Vida curta (dias a semanas)
- •Experiment flags — A/B testing. Mostrar variante A ou B para grupos diferentes
- •Ops flags — Kill switches para situações de emergência. Vida longa
- •Permission flags — Funcionalidades por segmento (beta users, plano premium)
📊 Caso Real: Facebook (Gatekeeper)
O Facebook deploya código 3x por dia para 3B+ usuários — tudo atrás de feature flags:
- Gatekeeper — Sistema interno de feature flags com milhões de configurações
- Kill switch — Se algo quebra, desliga o flag em segundos, sem rollback de deploy
- Gradual rollout — Nova feature para 1% → 10% → 50% → 100%
- Targeting — Flags por país, dispositivo, segmento de usuário
✓ O que FAZER
- ✓Definir lifecycle para cada flag (data de remoção)
- ✓Tratar flags antigos como dívida técnica
- ✓Testar ambos os estados (flag on e flag off) na CI
✗ O que NÃO fazer
- ✗Acumular centenas de flags sem limpeza
- ✗Aninhar flags: if flag_a AND flag_b AND flag_c
- ✗Usar flags para lógica permanente de negócio
📐 Architecture Fitness Functions
Testes automatizados para sua arquitetura. Fitness functions verificam se a arquitetura continua atendendo seus atributos de qualidade: latência < 200ms? Zero dependências circulares? Cobertura > 80%? Sem fitness functions, degradação arquitetural é invisível até explodir.
💡 Tipos de Fitness Functions
- •Structural — Regras de dependência entre camadas (ArchUnit, NetArchTest)
- •Performance — Budgets de latência, throughput e bundle size na CI
- •Security — Scan de dependências vulneráveis, checagem de secrets no código
- •Observability — Todo endpoint tem health check? Todos os erros têm correlation ID?
📊 Exemplos Práticos
- ArchUnit (Java) —
noClasses().that().resideInPackage("..controller..").should().dependOnClassesThat().resideInPackage("..repository..") - Bundle size check — CI falha se o JavaScript bundle ultrapassar 200KB gzipped
- API response time — Testes de contrato que validam p95 < 200ms
- Dependency graph — Alertas se dependências circulares forem introduzidas
💡 Dica Prática
Comece com 3 fitness functions simples: (1) nenhuma dependência circular, (2) bundle size < threshold, (3) nenhuma dependência com vulnerabilidade crítica. Rode na CI. Adicione mais conforme a maturidade do time cresce.
🔮 Evolutionary Architecture
Projetada para mudar. Evolutionary Architecture suporta mudanças incrementais guiadas em múltiplas dimensões. Não é “arquitetura que prevê o futuro” — é “arquitetura que aceita que não prevemos o futuro” e por isso facilita a adaptação contínua.
💡 Princípios da Evolutionary Architecture
- •Guided incremental change — Mudanças pequenas e frequentes, não revoluções
- •Last Responsible Moment — Adie decisões irreversíveis até ter informação suficiente
- •Fitness functions — Testes automatizados que guardam a integridade da arquitetura
- •Sacrificial architecture — Aceitar que partes do sistema serão substituídas é libertário
📊 Caso Real: Netflix — 7 Migrações em 15 Anos
A Netflix fez 7 grandes migrações arquiteturais, cada uma incremental:
- 2007 — Datacenter próprio (monolito)
- 2009 — Início da migração para AWS
- 2012 — Microsserviços (centenas de serviços)
- 2016 — Edge computing (Open Connect CDN)
- 2019 — Serverless parcial para workloads específicos
- 2022+ — IA/ML integrada no pipeline de encoding e recomendação
Nenhuma foi big-bang. Cada migração levou anos e foi guiada por fitness functions e métricas de negócio.
💬 Kent Beck
“Make the change easy, then make the easy change.”
Primeiro, refatore para que a mudança seja simples. Depois, faça a mudança simples. Dois passos pequenos em vez de um salto arriscado.
💡 Dica Prática
Pergunte-se regularmente: “Se precisássemos trocar [componente X] amanhã, quanto custaria?” Se a resposta é “meses de trabalho”, você tem acoplamento excessivo. Evolutionary architecture mantém o custo de mudança baixo e previsível.
📋 Resumo do Módulo
🏆 Parabéns! Você completou a Trilha 2!
Você agora domina os frameworks, trade-offs e estratégias para tomar decisões arquiteturais com confiança. De frameworks de decisão a ADRs, de análise de trade-offs a migrações seguras — você tem o toolkit completo do arquiteto.
Próxima trilha: Na Trilha 3, você vai aprender como IA e Large Language Models estão transformando a arquitetura de software — e como projetar sistemas que integram IA de forma segura e escalável.