Escolher o padrão de resiliência (capstone)

TL;DR

Fechamento em duas camadas. Primeiro, o mapa da família: do sintoma que você tem ao padrão que o trata, a tabela de quem paga cada sacrifício, e — a parte que mais importa — a ordem de composição, porque os padrões desta família interagem e empilhá-los sem somar produz falhas novas. Depois, o fechamento do galho-pai: seis famílias, noventa padrões, seis lentes diferentes. E a única conclusão que atravessa todas elas: um padrão não nomeia uma solução, nomeia um trade-off — e por isso a pergunta que dá acesso ao catálogo inteiro nunca é “qual padrão usar?”, mas “o que estou disposto a trocar?“.

Parte I — Escolher na hora do incidente

Do sintoma ao padrão

O que está acontecendoPadrãoNota
a dependência está lenta e minhas threads acabamTimeout02
falhas passageiras derrubam operações que funcionariamRetry (com backoff e jitter)03
a dependência está fora e insistir é desperdícioCircuit Breaker04
uma funcionalidade opcional derrubou uma essencialBulkhead05
a defesa disparou e o usuário vê erro 500Fallback06
um cliente consome a capacidade de todosRate Limiting07
a carga legítima excede a capacidade agoraLoad Shedding07
a origem não aguenta o volume de leituraCache-Aside08
instâncias doentes continuam recebendo tráfegoHealth Endpoint09
um job roda N vezes numa frota de N instânciasLeader Election10
preciso de resiliência uniforme em 4 linguagens (e num legado)Ambassador / Sidecar11
meu serviço exposto tem privilégio demaisGatekeeper12
a aplicação é gargalo de banda servindo arquivosValet Key12
o modelo do legado está contaminando o sistema novoAnti-Corruption Layer13
preciso substituir o legado sem parar a operaçãoStrangler Fig13

Quem paga cada conta

PadrãoSacrificaQuem paga
Timeoutrequisições que teriam sucesso se esperassemo usuário daquela requisição
Retrylatência; amplifica cargaa dependência já fraca
Circuit Breakerrequisições que talvez funcionassemusuários durante a janela aberta
Bulkheadutilização de recursoso orçamento de infraestrutura
Fallbackcorreção — resposta pior de propósitoo usuário, muitas vezes sem saber
Rate Limitinguso legítimo acima da cotaclientes na cauda
Load Sheddingrequisições escolhidas para morrerquem tem menor prioridade
Cache-Asidefrescorquem lê dado desatualizado
Health Endpointprecisão do diagnóstico (check raso)quem depura sem informação
Leader Electiondisponibilidade durante a reeleiçãoa função, não o sistema
Ambassador/Sidecarlatência, recursos, proximidade dev↔comportamentoquem depura
Gatekeeperum salto e um componente a maislatência e operação
Valet Keycontrole fino durante o acessoauditoria e revogação
ACLesforço sem valor de negócio visívelo time, continuamente
Strangler Figconviver com dois sistemas por muito tempoo custo operacional dobrado

A leitura transversal: o Retry é o único padrão cujo custo recai sobre outra pessoa — a dependência que já está mal. Todos os demais gastam alguma moeda sua. É por isso que ele exige mais disciplina que os outros doze.

A ordem de composição

Os padrões se aninham, e a ordem muda o comportamento de formas não óbvias. A composição convencional, de fora para dentro:


graph TD
    B["<b>Bulkhead</b><br/>quantas dessas podem existir em paralelo"] --> C["<b>Circuit Breaker</b><br/>vale a pena tentar agora?"]
    C --> R["<b>Retry</b><br/>tenta de novo, com recuo"]
    R --> T["<b>Timeout</b><br/>cada tentativa termina"]
    T --> X["chamada"]
    C -.->|"aberto"| F["<b>Fallback</b><br/>o que responder"]

    style B fill:#4A90D9,color:#fff
    style C fill:#4A90D9,color:#fff
    style R fill:#F5A623,color:#000
    style T fill:#4A90D9,color:#fff
    style F fill:#4A90D9,color:#fff

A lógica de cada nível: o timeout é o mais interno porque delimita cada tentativa; o retry envolve tentativas; o breaker observa o resultado do conjunto e decide se vale começar; o bulkhead limita quantas dessas operações existem ao mesmo tempo.

Inverter tem consequências concretas. Retry por fora do breaker faz as tentativas contornarem a decisão dele — o breaker abre e o retry tenta assim mesmo. Breaker contando cada tentativa individual em vez do resultado da operação abre muito mais cedo do que o limiar configurado sugere. E timeout por fora do retry, sem orçamento total, deixa o usuário esperando a soma de todas as esperas.

Três somas que causam incidentes

Multiplicação de retries. Cliente 3× · gateway 3× · aplicação 3× = 27 chamadas no alvo. Cada configuração é razoável isolada; o produto não é. Escolha uma camada e desligue nas outras — e lembre que o mesh é uma camada que costuma ser esquecida nessa conta.

Timeouts incoerentes. Se o de fora é menor que o de dentro, o serviço interno trabalha por respostas descartadas. Os timeouts devem decrescer para dentro, e a versão correta do padrão é propagar o prazo, não configurar valores locais.

Defesas que se anulam. O retry esconde falhas do breaker, que nunca abre. O fallback silencioso esconde a falha das métricas, e ninguém sabe que o sistema opera degradado. Duas defesas mal casadas podem ser piores que uma só.


Parte II — Fechando o galho-pai

Esta é a última nota da última família. O catálogo está completo: noventa padrões em seis famílias, cada uma com uma lente própria.

#FamíliaNotasFonteA lente
1Clássicos (GoF)23Gang of Four (1994)cross-linguagem — quando a linguagem dissolve o padrão
2Acesso a Dados15Fowler PoEAAcross-ORM — Active Record × Data Mapper
3Integração Empresarial14Hohpe & Woolfcross-ferramenta — smart endpoints, dumb pipes
4Aplicação Corporativa14Fowler PoEAAarqueológica — era × hoje, e a ressurreição
5Arquitetura de Eventos10Fowler (4 estilos)acoplamento — o que o evento carrega
6Nuvem e Resiliência14Azure · Nygardsacrifício — o que se abre mão

O que o catálogo inteiro ensina

Um padrão não nomeia uma solução — nomeia um trade-off. É a conclusão que atravessa as seis lentes, e cada família a descobriu por um caminho diferente. No GoF, a linguagem moderna dissolve metade dos padrões, porque o que eles compravam (indireção) passou a ser gratuito. Em Acesso a Dados, Active Record e Data Mapper não competem: otimizam para casos opostos. Em EIP, toda armadilha é a mesma — inteligência demais no cano. Em Eventos, desacoplamento não é quantidade, é a escolha de qual dependência ter. Aqui, todo padrão sacrifica algo explicitamente.

Cinco leituras que decorrem disso, e que valem mais que qualquer padrão individual:

1. Sem o atrito, o padrão é cerimônia. Cada entrada deste catálogo existe contra uma pressão específica: descasamento objeto-relacional, latência de rede, transação longa demais para o banco, falha parcial. Aplicar um padrão sem ter o atrito é pagar o custo sem receber o benefício — e é a origem do sistema pequeno com arquitetura de sistema grande. A pergunta é sempre a mesma: que pressão isto alivia no meu caso?

2. O contexto muda, e os padrões voltam. A família 4 mostrou isso com clareza: a nuvem inverteu a recomendação de 2002 sobre estado de sessão, o file-based routing ressuscitou o Page Controller que os frameworks MVC tinham enterrado, e o BFF é Remote Facade com outro nome. Um padrão “datado” é uma decisão tomada sob restrições que não estão no código — antes de removê-la, reconstrua a restrição e verifique se ela ainda vale. Às vezes vale ainda; às vezes voltou a valer.

3. Padrões movem problemas, não os eliminam. O Remote Facade não faz menos trabalho — faz do lado certo da rede. O CQRS não simplifica o sistema — separa dois usos e acrescenta um pipeline. O Circuit Breaker não conserta a dependência — troca desperdício por rejeição. Reconhecer para onde o problema foi é o que permite antecipar onde ele vai reaparecer.

4. O nome é metade do valor. Boa parte do que este catálogo entrega não é técnica: é vocabulário. Dizer “isto é um Front Controller” ou “estamos com um problema de dual-write” encerra em cinco segundos uma discussão que duraria meia hora — e permite que a conversa comece do trade-off em vez de começar da descrição. Num legado, nomear o que você encontrou é o primeiro passo para decidir o que fazer com aquilo.

5. A seção que mais importa é “quando NÃO usar”. Foi a decisão de design do galho, e ela se confirmou em todas as famílias. Todo mundo ensina quando aplicar; o que separa o sênior é saber quando o custo excede o benefício — e essa informação quase nunca está no texto original do padrão, porque quem cataloga um padrão está entusiasmado com ele.

Como usar este catálogo daqui em diante

Ele é de consulta, não de leitura linear. Três portas de entrada:

  • Pelo sintoma — os mapas de escolha ao fim de cada família (família 4, família 5, e a Parte I desta nota) partem do problema que você tem.
  • Pelo que você encontrou no código — o mapa de reconhecimento da família 4 vai do artefato (web.xml com servlet único, classes XxxVO, coluna VERSION) ao padrão.
  • Pelo tema — os index.md de cada família.

Como explicar em inglês

“If I had to compress the whole resilience family into one idea: none of these patterns is free, and the expensive mistake is stacking several without adding up what each one costs. A timeout sacrifices requests that would have succeeded, a circuit breaker sacrifices requests that might have worked, a bulkhead sacrifices utilisation, a fallback sacrifices correctness. Retry is the odd one out — it’s the only pattern whose cost lands on someone else, the dependency that’s already struggling, which is why it needs the most discipline. Composition order matters too: timeout innermost because it bounds an attempt, then retry, then the breaker observing the whole operation, then the bulkhead limiting concurrency. And where I’d start on a system with none of this is timeouts on every remote call and health checks with correct semantics — the two cheapest interventions with the biggest reduction in risk.”

PTEN
ordem de composiçãocomposition order
amplificaçãoamplification
orçamento totaloverall budget
trade-off explícitoexplicit trade-off
cerimôniaceremony / accidental complexity
catálogo de consultareference catalogue

O que vem a seguir

Isso fecha a família Nuvem e Resiliência e o galho-pai Padrões de Projeto — as seis famílias, completas. O catálogo passa a ser material de consulta e manutenção: revisitado quando um padrão aparece no trabalho, atualizado quando o contexto muda o suficiente para mudar um trade-off.

Veja também

Fontes

  • Michael NygardRelease It! (2ª ed., 2018) — a fonte central desta família e a origem do vocabulário de estabilidade.
  • Google SRE BookAddressing Cascading Failures e Handling Overload — a composição das defesas e o custo do trabalho desperdiçado.
  • MicrosoftCloud Design Patterns — o catálogo que dá nome à família.
  • Gamma et al. · Fowler · Hohpe & Woolf · Evans · Richardson — as fontes canônicas das seis famílias deste galho.