A Faca de Dois Gumes das Feature Flags: Quando Boas Intenções Dão Errado
Sou grande fã de Feature Flags (também chamadas de Feature Toggles). Pra quem não conhece, são basicamente chaves condicionais no código que permitem fazer deploy de uma funcionalidade nova _sem_ liberar ela pros usuários de imediato. Isso viabiliza:
- Deploys mais seguros (dark launching, canary releases)
- Testes em produção
- Kill switches instantâneos pra features com bug
- Segmentação granular de usuário (por geografia, conta, etc.)
Mas aqui vai o ponto crítico: feature flags brilham quando são de vida curta. São ferramentas táticas, não arquitetura permanente. Infelizmente, já vi times usarem elas sem cuidado — ignorando gestão de ciclo de vida e riscos operacionais. Vamos destrinchar os anti-padrões.
Red Flag 1: Tratar Flags como Configuração Permanente
O Pecado: usar flags pra customizações de cliente de longo prazo (ex.: flag_customer_x_ui_flow). O Custo:
- Dívida técnica infla conforme flags obsoletas se acumulam
- Proliferação de flags deixa o código imprevisível (
if flag_a && !flag_b && flag_c...) - Complexidade de teste explode combinatoriamente
A Correção: → Converter isso em "configurações de comportamento" guardadas no banco. Armazene ajustes tipo customer_x_ui_flow_enabled no seu próprio banco. Benefícios:
- Propriedade: sem lock-in de fornecedor nem indisponibilidade de terceiros
- Auditabilidade: rastreie mudanças via logs da própria aplicação
- Performance: evite chamadas HTTP em tempo de execução pro serviço de flags
Red Flag 2: Ignorar os Modos de Falha de Terceiros
O Pecado: assumir que seu serviço de flags (LaunchDarkly, Split, etc.) vai estar _sempre_ disponível. O Desastre: quando o serviço de flags cai:
- Aplicações podem quebrar (se o SDK der timeout)
- Flags assumem valor padrão de forma imprevisível (ex.: desligando _todas_ as features)
- Usuários enfrentam comportamento inconsistente
A Correção: → Implemente degradação graciosa:
try {
featureEnabled = await featureFlagClient.getFlag("new-checkout");
} catch (error) {
// Assume comportamento seguro durante indisponibilidades
featureEnabled = false;
}
→ Faça cache local do estado das flags pra sobreviver a quedas curtas → Teste cenários de falha (desligue seu serviço de flags no staging!)
Red Flag 3: Flags Imortais
O Pecado: flags que nunca morrem ("isso é código temporário!"). A Consequência:
- Configuration drift: flags apodrecem conforme os requisitos mudam
- Riscos de segurança: flags esquecidas expõem features inacabadas
- Sobrecarga cognitiva: engenheiro novo enfrenta "arqueologia de flag"
Uma Mentalidade Melhor: Na minha empresa anterior, chamávamos elas de "Rollout Flags" — um truque de nomenclatura deliberado:
- Flags _precisam_ ter um plano de remoção definido de antemão (ex.: "remover após 90 dias")
- Flags eram amarradas a marcos de rollout (não a "features" abstratas):
flag_enable_checkout_phase_1→ remover após 95% de rolloutflag_migrate_legacy_billing→ remover após migração de dados
Isso nos forçou a:
- Automatizar a limpeza de flags (ex.: CI falha se flag tem mais de 60 dias)
- Tratar flags como andaime transitório, não como bloco de construção
Minhas Regras de Ouro
- Vida Curta > Permanente: flags são como sutura cirúrgica — remova assim que o ferimento cicatrizar.
- Dono da Própria Configuração: comportamento específico de cliente? Use seu banco de dados, não um fornecedor de flags.
- Planeje pra Falha: o que acontece quando seu serviço de flags explode?
- Nomeie com Intenção: "Rollout Flags" > "Feature Flags" (semântica molda comportamento!).
Feature flags são poderosas — mas com grande poder vem grande dívida técnica. Pode com força, projete na defensiva, e mantenha seu jardim de flags arrumado.