Engenharia & Método · 6 min
Nossa calculadora estava quebrada, e ninguém tinha percebido
Testamos a própria ferramenta no site ao vivo e descobrimos que toda execução estava sendo recusada pelo servidor, em silêncio, há um tempo indeterminado. A causa era uma diferença de um bit de informação entre duas partes do mesmo sistema, e nenhum teste automatizado estava olhando para a fronteira entre elas.
Por Diogo Kammers · 17/09/2026
O teste que devia ser óbvio, e quase não aconteceu
Depois de publicar uma calculadora nova no site, o passo seguinte deveria ser simples: usá-la, do jeito que um visitante usaria. Ao fazer isso, o formulário respondeu normalmente na tela, mas por trás dele, a chamada que deveria registrar aquela execução no banco de dados voltou com erro 400. E o contador de execuções da ferramenta continuava em zero.
O detalhe mais relevante, mais do que o bug em si, é que sem esse teste manual no ambiente real o defeito continuaria invisível indefinidamente. A gravação da execução é intencionalmente best-effort: se falhar, não trava nem avisa quem está usando a calculadora. Ninguém veria um erro na tela. A única forma de descobrir era medir o resultado esperado (o contador subindo) e notar que ele não subia.
Onze testes passando, e o defeito nenhum deles via
A causa era uma discrepância pequena entre duas partes do mesmo fluxo. O componente da calculadora enviava um dos campos como número (1 ou 0), porque o formato compartilhado entre as seis calculadoras do site tipa todas as entradas como número. O lado do servidor, porém, esperava esse campo especificamente como valor booleano (verdadeiro ou falso). Dois lados da mesma fronteira, cada um assumindo um formato diferente, e nenhum teste olhando para os dois ao mesmo tempo.
Os onze testes existentes até então passavam sem problema, porque cada um testava um lado isolado, com o tipo que aquele lado já esperava. O componente era testado como se comunicasse corretamente com o servidor. O servidor era testado como se recebesse o formato que ele mesmo definia. A fronteira entre os dois nunca foi exercitada de ponta a ponta.
A correção deu um dono só ao formato
Em vez de ajustar só o ponto que quebrou, criamos uma função única responsável por produzir o formato que viaja até a rota do servidor, usada nos dois lugares do código que antes montavam esse objeto manualmente e de forma independente. O esquema de validação do servidor passou a exigir exatamente o formato que essa função produz, não o que parecia razoável a cada lado de forma isolada.
Dois testes novos travam essa fronteira especificamente: um garante que a saída da função de formatação sempre passa na validação do servidor, outro garante que o esquema recusa o formato antigo (número), que era exatamente o que estava quebrando antes.
O motivo de o erro ficar invisível por padrão
A calculadora afetada foi a Calculadora de Reclamação por Cliente, que contrasta satisfação declarada com reclamação formalmente registrada (o campo que quebrava, distribuidoraDeEnergia, existe porque parte da base de comparação vem do setor de energia). Na época do incidente, era uma de seis calculadoras gratuitas publicadas no site, todas compartilhando o mesmo hook de registro, e todas tipando as próprias entradas como número por convenção, porque é o formato que a maioria dos campos usa. Foi a única das seis que precisava de um campo booleano, e por isso foi ela quem expôs a costura.
A gravação de execução ser best-effort não é acidente de arquitetura, é decisão deliberada: uma calculadora gratuita não pode travar nem mostrar erro técnico para quem só quer o resultado na tela. O preço dessa decisão é que qualquer falha na gravação fica, por padrão, invisível para todo mundo, inclusive para quem mantém o site. A única forma de saber se a gravação está funcionando de verdade é olhar o dado do lado do servidor depois de usar a ferramenta, não confiar que a interface funcionando significa que o resto do sistema também está.
Por que isso importa além dessa calculadora
A lição que ficou vai além de um campo booleano específico: testar cada lado de uma fronteira de dados separadamente, com o tipo que cada lado já assume estar correto, não prova que os dois lados concordam entre si. Prova só que cada um é consistente consigo mesmo. Depois desse incidente, qualquer novo campo compartilhado entre componente e servidor passou a exigir um teste que atravessa a fronteira inteira, não um teste de cada lado isolado.
Veja as outras peças desta série: o cache de borda que derrubou a produção duas vezes, a migração que estourou o tempo limite do Postgres, e o guardrail contra o git add -A que misturou o trabalho de duas sessões.
Esse artigo faz parte do hub Engenharia & Método.