O que realmente diferencia uma solução boa de uma solução que só parece boa
a principal característica de uma solução é
Eu já vi tanta documentação bonita que me perco. Templates lindos, diagrams coloridos, que parecem saindo de um livro de estratégia. A maioria desaparece na segunda semana de implementação. O problema é que a principal característica de uma solução é nenhuma dessas coisas. Ela é algo chato. Algo que ninguém quer escrever no blog porque não é sexy. Vou te contar quando aprendi isso na marra. Tinha contratado um consultor para montar uma arquitetura de microsserviços pra gente. Ele fez um deck de 40 slides com todas as decisões erradas que nunca deveriam ser tomadas. Quando chegou a hora de colocar no ar, o sistema travou em 3 minutos de carga. Porque o consultor não tinha pensado em uma coisa simples: resiliência. Ou seja, o que acontece quando um dos serviços cai? Ninguém tinham pensado nisso. O próprio consultor não sabia responder quando perguntei.
Então vamos ao ponto. A característica principal não é performance. Não é escalabilidade. Não é modularidade. É capacidade de sobreviver a falhas. Sempre. Eu chamei isso de tolerância a falhas nos primeiros anos, mas isso é impreciso. Sobrevivência inclui algo mais. Inclui capacidade de rollback, de degradar graceful, de monitorar o que está acontecendo sem precisar de um toolchain de milionário. Vou dar um exemplo prático. Tenho um sistema rodando há dois anos. A primeira versão foi feita pensando em performance pura. O desenvolvedor principal era obcecado por latência. Resultado: qualquer falha em um serviço secundário derrubava todo o sistema. Demoramos três semanas pra consertar porque o código estava tão acoplado que qualquer mudança exigia um redeploy completo. Aprendi que performance sem resiliência é só uma questão de tempo até dar pau.
Insight contra-intuitivo número um: começar otimizando para escalabilidade horizontal geralmente piora a situação inicial. Você precisa dominar a resiliência antes. Sistemas que escalam mas não sobrevivem a falhas locais são piores do que sistemas lentos mas estáveis. Eu tenho visto isso acontecer com tanta frequência que já nem me emociono mais. Um colega meu construiu um sistema que escalava para 10.000 requisições por segundo, mas quando o banco de dados tinha um lock, tudo travava. Porque ele não tinha pensado em circuit breakers. Insight contra-intuitivo número dois: monitoramento excessivo pode mascarar problemas reais. Eu já vi times que tinham mais de 200 métricas configuradas e ainda assim não sabiam quando algo estava ruim. Porque eles estavam olhando para números errados. A métrica certa é tempo médio até recuperação. Se seu sistema leva 4 horas pra se recuperar de uma falha, você tem um problema. Não importa quantos dashboards bonitos você tenha.
Vamos falar de implementação. O primeiro passo é definir o que é falha aceitável. Não é sobre fazer tudo perfeito. É sobre saber até onde você pode ir antes de ter que admitir que algo deu errado. Eu uso uma técnica simples: listar todas as dependências externas e classificar cada uma como crítica ou não-crítica. Críticas têm SLA rígido. Não-críticas podem cair sem derrubar o sistema todo. Depois vem o circuit breaker. Isso não é apenas um padrão de código. É uma filosofia de design. Se um serviço não responde em X segundos, você corta a conexão e retorna um fallback. Simples. Na prática, eu configurei timeouts de 2 segundos para serviços externos e 500ms para internos. Qualquer coisa além disso é considerado falha. E quando um serviço começa a falhar consistentemente, o circuit breaker abre e você recebe um aviso. Não é mágica. É só seguir o fluxo.
👉 Clique no botão abaixo para saber mais sobre o assunto!
O erro mais comum que eu vejo: confundir retry com resiliência. Tentar novamente 5 vezes não é uma estratégia. É uma forma de aumentar o caos. Se um serviço está caindo, retry apenas sobrecarrega o sistema. Você precisa de backoff exponencial com jitter. E mesmo assim, depois de 3 tentativas, você abandona e vai pro fallback. Não insista. O serviço provavelmente está ruim. Outro ponto que muita gente esquece: logging estruturado. Não é sobre salvar logs. É sobre salvar logs que possam ser analisados depois. Use timestamps, IDs de request, e contextos claros. Quando eu comecei a implementar isso, perdi cerca de 2 horas por semana entendendo o que estava acontecendo. Agora, qualquer problema é resolvido em 15 minutos porque os logs contam a história completa.
Vamos falar de testing. O teste de resiliência não é o mesmo que teste de carga. Você precisa simular falhas reais. Desligar serviços, introduzir latency artificial, simular timeout. Eu uso uma ferramenta chamada chaos monkey, mas qualquer coisa que quebre o sistema propositalmente funciona. O importante é fazer isso em ambiente controlado antes de ir pra produção. Limitação importante: resiliência tem custo. Cada circuit breaker, cada fallback, cada retry logic consome recursos. Eu recomendo começar com o mínimo necessário. Não tente ser resiliente para tudo. Foque nos pontos críticos. O resto pode esperar.
Também precisa considerar o fator humano. Resiliência não é só código. É processo. Quando algo cai, quem responde? Qual é o escalation path? Eu vi times que tinham ótimos sistemas técnicos mas levavam 4 horas pra tomar uma decisão porque não tinham definidos papéis claros. Documente isso. Tenha um runbook que qualquer pessoa consiga seguir. Uma métrica que eu acho útil: MTTR (Mean Time To Recovery). Quanto tempo leva pra voltar ao após uma falha. Meu objetivo sempre foi menos de 5 minutos para falhas críticas. Não é fácil. Mas com prática, você consegue. E quando consegue, o resto do time começa a levar responsabilidade séria.
Se você está começando do zero, não tente construir um sistema super-resiliente de uma vez. Comece pequeno. Identifique o ponto único de falha. Coloque um fallback. Teste. Repita. A resiliência é construída em camadas, não de uma vez. E lembre-se: a principal característica de uma solução é ela continuar funcionando quando as coisas dão errado. O resto é detail.