Um crash é o melhor bug que você pode ter. Ele acontece na sua frente, para o app, e você o resolve naquela tarde. Todo mundo que constrói com geradores de IA tem uma história sobre um deploy quebrado ou uma tela em branco, e quase sempre é uma história com final feliz: encontrou, corrigiu, entregou.
A corrupção de dados não funciona assim. Ela não causa crash. Não gera erro. Ela escreve um número errado em uma coluna do banco de dados e segue em frente, e o app continua rodando exatamente como antes. O bug que você realmente deve temer é aquele que nunca te avisa que aconteceu.
Por que crashes são o resultado de sorte
Quando algo quebra visivelmente, você recebe feedback imediato e uma lista curta de suspeitos: o último prompt, o último deploy, a última alteração de código. Lovable, Bolt e geradores similares falham dessa forma constantemente, e isso é irritante, mas gerenciável, porque a falha é barulhenta.
A corrupção silenciosa inverte todo o problema. O bug e a descoberta do bug podem estar separados por meses, e nesse intervalo os dados corrompidos continuam se acumulando: são copiados para relatórios, somados em totais, usados para calcular uma fatura. Quando alguém percebe que os números estão errados, você não está depurando um único erro. Você está tentando descobrir quais dos milhares de registros desde que o bug foi lançado são confiáveis e quais não são, sem nenhum log que aponte a diferença.
Os casos extremos que ninguém solicita via prompt
Modelos de IA constroem para o cenário que você descreveu. Um prompt como “permita que os usuários atualizem a quantidade do pedido” te entrega um botão de atualização funcional, testado contra exatamente uma coisa: um único usuário, em uma conexão estável, clicando uma vez. O uso real não fica dentro dessa caixa, e as lacunas aparecem em alguns padrões repetíveis:
- Edições simultâneas. Duas pessoas abrem o mesmo registro e salvam alterações com segundos de diferença. Sem uma estratégia de travamento ou resolução de conflitos, quem salvar por último sobrescreve silenciosamente as alterações da outra pessoa, sem aviso para nenhum dos usuários.
- Queda de rede no meio do formulário. Um envio é feito, a conexão oscila e o cliente não consegue confirmar se o servidor o recebeu. O usuário vê um ícone de carregamento, assume que falhou e envia novamente. Sem deduplicação, agora existem dois registros onde deveria haver apenas um.
- O botão de envio clicado duas vezes. A versão mais mundana do mesmo problema. Uma resposta lenta somada a um clique impaciente e você criou um pagamento duplicado, uma reserva duplicada ou uma linha duplicada que infla cada contagem subsequente.
- Entrada inesperada. Um campo de quantidade que aceita um número negativo, um campo de data que aceita um valor no passado, um campo de desconto que aceita mais de 100%. Nada disso derruba o app. Apenas produz um registro que é matematicamente absurdo no momento em que alguém o confronta com a realidade.
Nenhum desses é um modo de falha exótico. São os atritos comuns de pessoas reais usando um app em redes reais, e um único prompt quase nunca pede para a IA se defender deles, porque se defender disso não adiciona progresso visível a uma demo.
Quando a matemática está errada em cada transação
A segunda variação desse problema é ainda mais silenciosa: um erro de arredondamento ou cálculo que está errado por uma fração de centavo, todas as vezes, em cada transação. Ele roda sem problemas. Nunca gera uma exceção. O teste unitário, se é que existe um, verifica se o cálculo retorna um número, não se o número está correto até a última casa decimal em dez mil execuções.
É aqui que o teste do “está funcionando”, no qual o vibe coding te treina a confiar, torna-se ativamente perigoso. Um cálculo de preço que está errado em 0,3% não falha na demo. Ele falha na reunião de conciliação seis meses depois, quando o financeiro aponta que a soma de todas as transações individuais não bate com o valor total da receita, e ninguém consegue dizer o porquê sem analisar registro por registro.
Essa lacuna entre “a funcionalidade funciona” e “a funcionalidade está correta” é exatamente o que os testes automatizados devem capturar no desenvolvimento de software profissional, e exatamente o que falta quando um construtor não técnico é o único verificando a saída da IA. Você pode confirmar visualmente que uma página carrega. Você não pode confirmar visualmente que um cálculo composto é preciso ao centavo ao longo de um ano de transações.
Por que “parece certo” é o teste errado para a integridade dos dados
| O que você pode testar manualmente | O que realmente causa corrupção |
|---|---|
| O formulário é enviado com sucesso? | Ele é enviado exatamente uma vez, mesmo em uma conexão instável? |
| O dashboard mostra um total? | Esse total continua correto após 10.000 linhas, ou um erro de arredondamento se acumula? |
| Um usuário consegue editar um registro? | O que acontece quando dois usuários o editam ao mesmo tempo? |
| A calculadora retorna um número? | Esse número é o número correto, verificado contra uma fonte independente? |
A coluna da esquerda é o que uma demo, e a maioria dos QAs manuais, realmente verifica. A coluna da direita é o que determina se seu faturamento, suas reservas ou seus relatórios são confiáveis no sexto mês. O vibe coding otimiza fortemente para a coluna da esquerda e não possui um mecanismo natural para a direita, porque a coluna da direita exige tentar deliberadamente quebrar o caminho feliz, não apenas confirmar que ele funciona.
A parte que torna isso pior do que um bug: você não consegue saber quais registros estão errados
Um travamento tem um raio de impacto que você consegue ver. Dados corrompidos têm um raio de impacto que você só consegue estimar. Quando um bug de envio duplicado ou um erro de arredondamento está ativo por meses, não há sinalização nas linhas afetadas. Ou você confia em todo o conjunto de dados, que agora sabe ser não confiável, ou o audita registro por registro, o que, para qualquer coisa além de algumas centenas de linhas, não é realista para uma equipe pequena sem tempo de engenharia dedicado.
Este é o custo real do “Gap de Confiança” que vem com o código gerado: você nunca esteve em posição de verificar se a lógica era infalível, então, quando se descobre que não era, você não tem um ponto de partida para a limpeza. Descobrir o bug não é o fim do problema. É o início de um muito mais difícil: descobrir até onde o dano retrocede.
Construindo para que o dano não se acumule
Você não consegue eliminar todos os casos extremos sendo mais cuidadoso com os prompts. O que você pode fazer é escolher onde as partes do seu app que lidam com dinheiro, quantidades ou reservas realmente rodam.
Para projetos de hobby, protótipos internos ou qualquer coisa onde um número errado seja um inconveniente em vez de um risco, código gerado e testes manuais são uma troca razoável por velocidade. O cálculo muda no momento em que os números alimentam a fatura de um cliente, um calendário de reservas ou um relatório que alguém assina. Nesse ponto, a pergunta não é “isso parecia certo quando testei”, mas sim “quem está verificando se ainda está certo após dez mil transações”.
Para essa categoria de app de negócios, estruture o caminho de escrita para que ele não dependa da IA acertar a concorrência e o arredondamento na primeira (ou quinta) tentativa:
- Empurre as escritas centrais para infraestruturas testadas, não para código gerado na hora. O Softr gerencia a criação de registros, atualizações e cálculos de rollup (somas, médias, contagens em registros vinculados) através de seu próprio mecanismo de banco de dados, em vez de lógica gerada por IA por app. Um rollup que soma itens de linha de fatura executa o mesmo cálculo testado todas as vezes, em vez de uma função personalizada que uma IA escreveu uma vez e nunca testou sob estresse para deriva de arredondamento.
- Use permissões visuais em vez de lógica de concorrência escrita à mão. Os Grupos de Usuários e as Restrições de Dados em nível de registro do Softr governam quem pode editar o quê, o que reduz (embora não elimine) o problema de edição concorrente ao controlar o acesso no nível da plataforma, em vez de depender de bloqueios codificados manualmente que uma IA pode ou não ter pensado em adicionar.
- Reconcilie independentemente, com um cronograma. Nenhuma plataforma, no-code ou não, substitui o hábito de verificar periodicamente os totais contra uma fonte externa: um extrato bancário, o painel de um processador de pagamentos, uma contagem manual. Isso é verdade quer você tenha construído com código gerado por IA ou não, e é a única maneira de pegar um erro cumulativo antes que ele complete um ano.
- Se você for continuar no código, reserve tempo real para testes adversariais. Se você é um desenvolvedor usando Cursor ou Replit para construir ou expandir um app customizado, escreva explicitamente testes para escritas concorrentes, envios duplicados e valores limite (números negativos, zero, datas extremas), porque a IA não os gerará a menos que você peça, e “compilou” não diz nada sobre se está correto sob carga.
Nada disso faz o problema subjacente desaparecer. Softwares que lidam com dinheiro ou reservas sempre precisarão de alguém conferindo a matemática contra a realidade. Mas há uma diferença real entre um app onde a lógica de escrita foi gerada de forma personalizada por projeto e nunca testada sob estresse, e um onde as operações centrais do banco de dados são o mesmo caminho de código testado no qual cada empresa na plataforma confia. O primeiro te dá uma nova chance de errar a concorrência e o arredondamento em cada recurso. O segundo não remove sua responsabilidade de reconciliar, mas remove a loteria diária de saber se essa função de escrita específica gerada por IA lida corretamente com um clique duplo.
A conclusão honesta é que travamentos são irritantes, mas perdoáveis. A corrupção silenciosa é paciente. Ela espera até que o volume de dados seja alto o suficiente, e o tempo decorrido seja longo o suficiente, para que corrigi-la custe muito mais do que teria custado preveni-la.