Um bug em produção custa até 100 vezes mais que o mesmo bug pego no commit. Como projetamos sistemas que falham no desenvolvimento, não nos seus clientes.
Um bug encontrado no momento em que o desenvolvedor escreve a linha custa 1 unidade de esforço para corrigir. O mesmo bug em code review custa em torno de 5. Detectado em testes de staging, 25. Encontrado em produção, com cliente reclamando no WhatsApp, custa 100 ou mais. Esses números vêm de pesquisas clássicas de engenharia de software, da IBM aos anos 80 até estudos recentes da CISQ, e batem com o que vemos na prática todo dia.
Não é pessimismo nem perfeccionismo. É o motivo real pelo qual investimos pesado em testes antes, durante e depois da implementação. O custo do teste compensa com folga o custo do bug que ele evita.
Por que "vou testar depois" nunca acontece
A intenção sempre é boa: termina a feature, depois cobre com testes. A realidade é cruel. Termina a feature, vem a próxima, a anterior fica sem teste para sempre. Em seis meses você tem um sistema funcional que ninguém ousa mudar, porque qualquer ajuste pode quebrar três coisas que não foram cobertas.
A solução não é apelar para disciplina pessoal — é mudar a estrutura. Testes precisam estar dentro do fluxo de desenvolvimento, não como tarefa separada que pode ser pulada. Quando o teste é o critério que define se a feature está pronta, ele acontece. Quando é "extra", nunca acontece.
A pirâmide de testes que realmente funciona
Existe um modelo simples e robusto, conhecido como pirâmide de testes, que distribui o esforço de cobertura em três camadas. A proporção típica que adotamos em projetos médios é mais ou menos esta:
Testes unitários formam a base larga, em torno de 70% dos testes. Verificam unidades isoladas — uma função, uma classe, um cálculo. São rápidos (rodam em milissegundos), determinísticos (mesmo input gera mesmo output) e baratos. Rodam a cada commit, antes de qualquer pull request ser aberto. Encontram bugs de lógica e detectam regressão.
Testes de integração formam a faixa do meio, em torno de 20%. Verificam que as partes funcionam juntas — banco real, fila real, API real (ou mock fiel ao contrato). São mais lentos (segundos por teste), mais caros, mas pegam o que teste unitário não pega: contrato errado entre serviços, configuração faltando, race condition.
Testes end-to-end ficam no topo, em torno de 10%. Simulam o usuário de verdade: abrem o navegador, clicam, leem, conferem. São caros (minutos por teste), frágeis (uma mudança visual quebra) e indispensáveis para fluxos críticos — checkout, login, pagamento, cadastro. Não cobrem tudo, mas cobrem o que mataria o negócio se quebrasse.
Quem não testa, debugga em produção. Quem debugga em produção, perde cliente.
TDD: ferramenta, não religião
Test-Driven Development — escrever o teste antes do código — não é certificado nem filosofia. É técnica. Funciona muito bem quando o requisito é claro e você precisa garantir que um cálculo, uma regra de negócio ou uma transformação faça exatamente o que prometeu.
Não funciona quando você está explorando: tentando entender qual é a melhor forma de modelar um problema novo. Aí faz mais sentido prototipar, validar com o usuário e só depois cobrir com testes a versão que vai para produção. Dogma em engenharia geralmente custa caro.
Na Oryxi, TDD é regra para tudo que é financeiro, cálculo crítico, regra de negócio e fluxo de pagamento. É opcional para UI exploratória ou para protótipo que ainda vai ser descartado. Decidir caso a caso é parte do trabalho.
Code review com checklist real
Toda mudança passa por outro par de olhos antes de entrar na main. Não é burocracia, é a forma mais barata e eficaz de pegar bug que escapou do autor. Nosso checklist mínimo de review:
- O teste cobre o caso feliz, o caso de erro e os edge cases? Lista vazia, valor nulo, número negativo, string com unicode estranho.
- O código lida graciosamente com input inválido? Não trava, não vaza stack trace, retorna erro útil.
- Tem logs e métricas suficientes para diagnosticar em produção? Se isso quebrar às 3 da manhã, é possível entender o que aconteceu sem reproduzir localmente?
- Nomes claros? Variável diz o que ela é, função diz o que ela faz, sem precisar ler o corpo para entender.
- Nenhuma credencial, segredo ou URL hardcoded? Tudo via configuração, sem surpresa quando for para produção.
- Documentação atualizada onde precisa? Se a função pública mudou, o README e os comentários da API refletem.
Feature flags: deploy desacoplado de release
Subir código para produção e ativar uma feature para o usuário são duas decisões diferentes, e separá-las muda o jogo. Feature flags fazem isso.
Você deploya o código novo com a flag desligada — o código está em produção, mas inativo. Roda silenciosamente, validando que pelo menos não causa regressão. Ativa para 1% dos usuários (canary release). Observa métricas. Se taxa de erro sobe, desativa em segundos — sem rollback de deploy, sem downtime. Se está saudável, sobe para 10%, 50%, 100%, dentro de horas ou dias.
É a diferença entre lançar feature crítica com nervosismo às 23h de uma sexta-feira e lançar quarta-feira de manhã com café na mão. Ambos os deploys colocaram código novo em produção. Só um deles colocou risco real.
Os três testes que todo sistema crítico precisa
- Teste de carga: o sistema aguenta 3 vezes o pico esperado em produção? E 10 vezes no Black Friday ou na virada de mês do ERP? Identificar o ponto de quebra em ambiente controlado é muito mais barato que descobrir em produção com cliente reclamando.
- Teste de falha (chaos engineering): o que acontece se o banco cair por 30 segundos? E se a API externa retornar erro 500 em todas as chamadas? Boa engenharia degrada graciosamente — perde uma feature secundária, mantém o núcleo de pé. Engenharia ruim cai inteira junto com a primeira dependência.
- Teste de regressão: depois de cada mudança, as features antigas continuam funcionando? Sem isso, qualquer evolução vira loteria. Com isso, o time evolui o sistema todo dia com confiança.
Observabilidade: ver o bug antes do cliente reclamar
Testes garantem que o sistema faz o que prometeu no momento em que foi escrito. Observabilidade garante que você sabe quando ele para de fazer em produção. São complementares, não substituíveis. Três pilares clássicos:
Logs respondem "o que aconteceu". Estruturados (JSON, não texto livre), com identificador único de requisição que permite rastrear o caminho completo de uma operação. Buscáveis por filtro: por usuário, por endpoint, por código de erro.
Métricas respondem "quanto, com que frequência, qual a tendência". Latência percentual 95 (a experiência do usuário ruim), taxa de erro, throughput. Alertas baseados em desvio do normal, não em valor absoluto arbitrário.
Traces respondem "por onde a requisição passou e onde gastou tempo". Crítico em sistema distribuído com vários serviços conversando — quando algo está lento, o trace mostra exatamente qual etapa é o gargalo.
Observabilidade não é luxo. É a diferença entre acordar com cliente reclamando e descobrir o problema antes dele.
Garantia que faz sentido (e a que não faz)
Software complexo nunca está 100% livre de bug. Quem promete isso está mentindo ou não sabe o que está prometendo. O que dá pra prometer com honestidade — e é o que oferecemos por contrato — é:
- Cobertura de testes mínima nas regras críticas (90% ou mais), com relatório que você acompanha.
- Tempo máximo para resposta a bug, definido por SLA com níveis de severidade claros.
- Correção sem custo adicional dentro do período de garantia para qualquer defeito de implementação atribuível ao desenvolvimento original.
- Acesso completo ao código, aos testes, à documentação e à infraestrutura. Sem caixa-preta, sem ficar refém para evoluir.
- Pós-incidente público (para você): se algo der errado em produção, você recebe análise técnica honesta — o que aconteceu, por que aconteceu, o que mudamos para não voltar.
O que isso te economiza no fim das contas
Um cenário real (sem nome do cliente): em um sistema de cobrança, um bug afetou 2% das transações por 4 horas antes de ser detectado. Custo estimado: cerca de R$ 12 mil em vendas perdidas, mais um dia inteiro da equipe corrigindo, mais a confiança do usuário arranhada — esse último custo é difícil de mensurar mas se acumula.
Com a observabilidade certa e teste de carga prévio, esse bug teria sido detectado em staging, custando 30 minutos de um engenheiro corrigindo. Multiplique a diferença por 12 meses de operação e você entende por que sistema bem testado é, na prática, a opção mais barata — não a mais cara.
Pronto para um sistema que não te acorda às 3 da manhã?
Em Foz do Iguaçu, atendendo clientes em todo Brasil, Paraguai e Argentina, construímos software sob medida que aguenta o pico, o pico do pico e o dia em que tudo dá errado ao mesmo tempo. Não porque é mágica — porque foi desenhado, testado e operado com essa premissa desde o primeiro commit. Vamos conversar sobre o seu projeto sem compromisso.