en
· 3 min de leitura

Eu encontro a falha que ninguém encontra. Este é o método.

Não é intuição. É um procedimento repetível que assume que o sistema está mentindo e vai procurar onde.

auditcareer

Clientes me contratam para auditar sistemas que outras pessoas já revisaram. Os pull requests foram aprovados, os testes estavam verdes, um consultor assinou embaixo. E eu encontro alguma coisa. Muitas vezes algo sério. As pessoas chamam isso de dom. Não é. É um procedimento, e eu consigo escrevê-lo.

Assuma que o sistema está mentindo

Todo sistema conta uma história sobre si mesmo: o README, o diagrama de arquitetura, os comentários, o dashboard. A primeira regra é tratar tudo isso como hipótese, não como fato. O diagrama mostra uma fila entre dois serviços. A fila existe? É usada? Alguma coisa consome dela? Já encontrei filas desenhadas em diagramas que nunca foram implantadas, e retries descritos em comentários que nunca foram implementados. A história é onde as pessoas acreditam que o sistema está. A falha mora no vão entre a história e o código.

Rastreie uma requisição real, de ponta a ponta, na mão

Não um caminho feliz num teste. Uma requisição real dos logs de produção, com um ID real, seguida por cada serviço, cada escrita no banco, cada chamada externa, cada retry, até ela terminar ou se perder. Faço isso com um caderno aberto e anoto cada lugar em que uma decisão é tomada: um branch, um timeout, um bloco catch, um valor padrão. Leva horas. Toda falha séria que já encontrei apareceu nessa lista como uma decisão que ninguém lembrava de ter tomado.

Pergunte o que acontece na segunda vez

A primeira execução de qualquer coisa normalmente funciona. A segunda é onde os sistemas quebram. O que acontece se este webhook chegar duas vezes? Se este job reiniciar no meio? Se o usuário der dois cliques? Se o deploy rodar a migração de novo? Faço essa pergunta em cada escrita, cada chamada externa e cada tarefa agendada. Idempotência é onde se esconde a maior classe de corrupção silenciosa de dados, e quase ninguém testa porque os testes rodam uma vez só.

Leia os dados, não só o código

O código descreve o que o sistema deveria fazer. O banco registra o que ele de fato fez. Consulto a produção, somente leitura, e procuro o impossível: pedidos com total negativo, usuários com duas assinaturas ativas, eventos com timestamp anterior ao do pai, status que a máquina de estados diz que não podem coexistir. Cada linha impossível é um bug que já aconteceu. O code review deixou passar porque o código parecia certo. Os dados não se importam com a aparência do código.

Enquanto estou ali, leio cada bloco catch, porque cada um é um lugar em que o sistema decidiu seguir em frente sem a informação que acabou de perder. Um catch que loga e continua depois de uma confirmação de pagamento falhar não é tratamento de erro. É uma decisão de perder dinheiro em silêncio.

Reproduza antes de reportar

Um achado sem reprodução é uma opinião. Antes de qualquer coisa entrar no relatório, eu a disparo: um script que envia o webhook duplicado, uma query que mostra as linhas impossíveis, uma requisição com timestamp em outro fuso. Se não consigo fazer acontecer, digo isso e rebaixo a prioridade. É esse passo que transforma 'acho que tem um problema' em 'aqui está o problema, aqui está como ver, aqui está o que custa'. É também o passo que faz as pessoas consertarem em vez de discutirem.

As pessoas que construíram o sistema não são menos capazes do que eu. Estão mais perto da história. Elas desenharam o diagrama, lembram da intenção, e o cérebro delas preenche o vão entre intenção e código sem perceber. Eu não tenho intenção para proteger. Tenho uma lista de lugares onde sistemas falham, construída em mais de 600 projetos, e confiro cada um deles, toda vez, mesmo quando o sistema parece bem. Principalmente quando parece bem.