en
· 3 min de leitura

Seiscentos projetos depois: o que se repete

Depois de mais de 600 projetos construídos, revisados ou auditados, as falhas pararam de me surpreender. A lista curta que sempre volta.

auditcareer

Em algum ponto depois do quingentésimo projeto, parei de me surpreender. Não porque os sistemas pararam de falhar, mas porque continuaram falhando do mesmo punhado de jeitos, independentemente de linguagem, framework, tamanho do time ou setor. Um marketplace, um app de agendamento de clínica, uma plataforma de logística e um backend de fintech não compartilham quase nada na superfície e quase tudo por baixo. Aqui está a lista. É curta porque a verdade é curta.

A lista

  • Nenhum timeout nas chamadas de saída, então uma dependência lenta derruba o sistema inteiro junto
  • Queries sem limite, um endpoint de listagem que funciona com mil linhas e morre com um milhão
  • Escritas que não são idempotentes, então todo retry, clique duplo ou webhook reenviado cria uma duplicata
  • Erros capturados e engolidos, então o sistema segue em frente num estado que ninguém entende
  • Segredos em arquivos de configuração, em repositórios, em logs, em mensagens de erro enviadas ao cliente
  • Backups que existem e nunca foram restaurados, o que significa que são uma hipótese
  • Uma única pessoa que sabe como o deploy funciona, e o deploy só funciona quando ela está acordada

Por que essas e não outras

Cada uma delas é invisível enquanto o sistema é pequeno. Um timeout ausente não importa quando a dependência é rápida. Uma query sem limite está ótima no lançamento. Uma escrita não idempotente só duplica quando algo faz retry, e nada faz retry até a primeira queda. Esse é o padrão: essas falhas são dormentes por construção, e o momento em que acordam é o momento em que o negócio finalmente tem tráfego suficiente para importar. O sucesso do produto é o gatilho da falha.

Bugs sofisticados, os de algoritmos espertos ou concorrência sutil, são raros em comparação e normalmente pegos por quem escreveu o código esperto, porque estava prestando atenção. As falhas chatas sobrevivem porque ninguém estava prestando atenção nas partes chatas.

No que parei de acreditar

Parei de acreditar que a escolha de framework importa muito. Já vi as mesmas sete falhas em Rails, Django, Spring, Express e Next.js. Parei de acreditar que mais testes resolvem, porque testes exercitam os caminhos em que as pessoas pensaram, e esses são os caminhos em que ninguém pensou. Parei de acreditar que um time sênior é imune. Times sêniores cometem esses erros sob pressão de prazo exatamente como os júniores, só se sentem pior depois.

O que comecei a fazer

Confiro a lista. Todo projeto, toda vez, antes de ler qualquer outra coisa. Parece mecânico e um pouco ofensivo para o time, e encontra alguma coisa na grande maioria dos sistemas que olho. A conferência leva meio dia. As falhas que ela evita levam semanas e acontecem na pior hora possível. Essa troca é tão desproporcional que já não entendo por que não é universal.

Também comecei a construir as contramedidas desde o primeiro dia nos meus próprios projetos: timeout padrão em todo cliente HTTP, tamanho máximo de página imposto na camada de query, chave de idempotência em todo endpoint que altera dados, um exercício de restauração no calendário, um deploy que um recém-contratado consegue rodar a partir de um documento. Nada disso impressiona. Tudo isso é a diferença entre um sistema que sobrevive ao próprio sucesso e um que não sobrevive.

A conclusão honesta

Seiscentos projetos me ensinaram que a fronteira da falha de software não está onde a indústria olha. Não está no framework novo, nem no modelo, nem no padrão de arquitetura. Está nos mesmos sete lugares em que estava há uma década, esperando o tráfego chegar. A coisa mais valiosa que posso fazer por um cliente costuma ser a menos glamourosa: percorrer a lista, achar a falha adormecida e acordá-la num relatório em vez de em produção.