Projete a falha antes da funcionalidade
O caminho feliz qualquer um escreve. O sistema de verdade é o que acontece quando ele quebra, e é isso que se projeta primeiro.
Quando eu reviso um documento de design, pulo o caminho feliz. Vou procurar a seção que descreve o que acontece quando o provedor de pagamento dá timeout, quando a fila enche, quando dois usuários clicam no mesmo botão no mesmo instante. A maioria dos documentos não tem essa seção. E o problema é exatamente esse.
A funcionalidade é a parte fácil
Uma funcionalidade é uma sequência de passos que funciona quando tudo funciona. Qualquer engenheiro competente escreve isso. O sistema é o que acontece em volta dessa sequência: os retries, as escritas parciais, os eventos duplicados, o usuário que dá refresh no meio da requisição. É ali que mora o design de verdade, e é ali que eu encontro as falhas que ninguém mais encontra, porque ninguém olhou.
O hábito que eu recomendo é simples: antes de escrever a primeira linha da funcionalidade, escreva a lista de falhas. Não é uma matriz de risco com probabilidades. É uma lista crua de frases concretas que começam com "o que acontece quando".
As perguntas que eu faço antes de existir código
- O que acontece quando essa chamada dá timeout depois que a escrita já foi commitada?
- O que acontece quando a mesma requisição chega duas vezes?
- O que acontece quando o serviço downstream está de pé, mas dez vezes mais lento que o normal?
- O que acontece quando esse job roda ao mesmo tempo que ele mesmo?
- O que acontece quando o usuário fecha a aba entre o passo dois e o passo três?
- Quem percebe, e quanto tempo leva para perceber?
Seis perguntas. Num serviço de checkout, elas levam vinte minutos num quadro branco. Respondê-las depois que a funcionalidade está em produção leva semanas, porque agora cada resposta mexe em dados que já existem.
Um exemplo concreto
Pegue um app de agendamento de clínica. A funcionalidade: o paciente reserva um horário. O caminho feliz é um formulário, uma validação, um insert. Agora as falhas. Dois pacientes reservam o mesmo horário com 200 milissegundos de diferença. O provedor de e-mail de confirmação está fora. O paciente dá clique duplo. O insert funciona, mas a resposta se perde, e o cliente tenta de novo.
Cada uma dessas situações força uma decisão de design. A reserva dupla precisa de uma unique constraint em (médico, horário), não de um if no código da aplicação. O e-mail precisa ir para uma fila, não ser enviado inline, para que um provedor quebrado não trave as reservas. O clique duplo e a resposta perdida precisam de uma chave de idempotência, para que a segunda tentativa devolva a primeira reserva em vez de criar outra.
Nada disso é exótico. Mas repare que as quatro decisões mudam o schema, o contrato da API ou a infraestrutura. Se você descobre isso depois do lançamento, vai migrar uma tabela viva com dados de pacientes dentro.
Projetar a falha é mais barato do que tratar a falha
Existe uma assimetria que eu repito para as equipes o tempo todo. Projetar um modo de falha custa minutos. Tratar a falha depois que ela acontece em produção custa o incidente, o conserto dos dados, a conversa com o cliente e a correção, que agora está presa a tudo o que você já colocou no ar.
Não estou pedindo que ninguém construa para toda falha possível. Estou pedindo que decidam, explicitamente, quais falhas aceitam. "Se o provedor de e-mail cair, as reservas continuam funcionando e o e-mail sai depois" é um design. "Se duas pessoas reservarem o mesmo horário, a segunda recebe um erro" é um design. "A gente não pensou nisso" não é.
Como isso aparece numa revisão de design
Quando eu reviso, quero ver três coisas ao lado de cada funcionalidade. Primeiro, a lista de frases de falha. Segundo, para cada uma, ou o mecanismo que trata a falha ou uma linha explícita dizendo que ela é aceita e por quê. Terceiro, a forma como alguém vai descobrir quando ela acontecer: um log, uma métrica, um alerta.
Se o documento tem essas três coisas, a parte da funcionalidade quase sempre está boa. Se não tem, a funcionalidade geralmente também está boa, e o sistema não está. A funcionalidade é o que o cliente pediu. As falhas são o que o cliente vai lembrar.