Em abril de 2000, Joel Spolsky publicou um texto argumentando que reescrever código do zero era o pior erro estratégico que uma empresa de software podia cometer, usando a Netscape como exemplo central. A empresa abandonou o código do Netscape 4.0 pra construir a versão 6.0 do zero, e o intervalo de quase três anos entre versões principais entregou o mercado de navegadores à Microsoft sem resistência (Joel Spolsky, 2000). A prescrição absoluta envelheceu. O problema que ela tentava resolver permanece: calcular o custo real de cada alternativa antes de escolher exige reconhecer que refactoring e rewrite carregam perfis de risco distintos, com condições diferentes pra funcionar.
Cada alteração incremental num refactoring preserva o sistema em funcionamento enquanto modifica a organização interna, e o custo de cada passo fica contido pela superfície limitada da mudança. O risco por unidade de trabalho é baixo e o feedback é imediato, até porque o sistema continua rodando entre iterações. O investimento se distribui sem interrupção de entrega ao negócio. Testes continuam validando comportamento enquanto integrações seguem funcionando, e o conhecimento acumulado permanece acessível mesmo quando a arquitetura muda. Martin Fowler descreveu o Strangler Fig Application pra migrações maiores: novos componentes crescem ao redor do sistema legado e absorvem suas responsabilidades até que o original seja removido (Martin Fowler, Strangler Fig). O Strangler Fig distribui risco no tempo. Na prática, tenho visto que ele também mantém rollback disponível em cada etapa, reduzindo o custo político de reverter uma decisão que não funcionou.
Essa abordagem encontra seu limite quando a base de código resiste à mudança incremental. Sistemas com acoplamento profundo entre camadas, onde cada alteração local produz efeitos em cascata em módulos distantes, tornam o preço de cada passo desproporcionalmente alto. O refactoring pressupõe independência entre as partes; quando ela não existe, a coordenação exigida consome o benefício da abordagem. O outro limite é temporal: quando a distância entre a arquitetura atual e a necessária é grande, o caminho incremental leva anos, e manter dois modelos mentais em paralelo (o que o sistema é e o que ele está se tornando) cobra seu preço em velocidade e em carga cognitiva sobre o time.
Um rewrite concentra investimento e risco de uma vez: os resultados só se tornam visíveis quando o novo sistema atinge paridade funcional com o anterior, e o período intermediário produz gasto sem retorno direto. Não existe taxa de fracasso segmentada pra rewrites. Os números que aparecem nessa posição vêm de levantamentos de projetos de software em geral, e a fonte mais citada, o CHAOS Report, tem problemas metodológicos documentados (Eveleens & Verhoef, 2010). O mecanismo de falha que mais encontro nem é técnico. O código antigo contém decisões acumuladas ao longo de anos, muitas não documentadas, codificadas como tratamentos de caso especial e validações de borda cujas peculiaridades só se manifestam em produção. Redescobrir essas decisões é o custo oculto que as estimativas não alcançam. Ferramentas de modernização assistida por IA prometem atacar justamente esse custo, gerando testes de caracterização a partir do comportamento observado em produção e automatizando a análise de dependências. Se entregam o que anunciam, o trabalho de mapear o que o código faz diminui. Mas entender por que ele faz, inclusive quando o bug virou contrato com o usuário, continua sendo humano.
Existem condições sob as quais o rewrite é a decisão de menor custo total. A mais óbvia: a plataforma tecnológica atingiu o fim de vida útil e o ecossistema de suporte degradou a ponto de tornar a manutenção progressivamente mais cara, com o gasto de infraestrutura dupla durante a migração incremental excedendo o investimento do rewrite. Outra condição aparece quando o domínio do negócio mudou de forma que a modelagem original não consegue mais representar, não por limitação de implementação, mas por incompatibilidade entre o modelo de dados e a realidade do negócio. Me parece que o cenário mais subestimado é o de um sistema que precisa atender requisitos não funcionais radicalmente diferentes dos originais, como mudança de escala em ordens de magnitude, quando a arquitetura não foi projetada pra acomodar essa transição.
A reconstrução do cliente desktop do Slack (Electron) ilustra uma abordagem que dissolve a fronteira entre as duas estratégias. Em julho de 2019, Mark Christian e Johnny Rogers descreveram como a equipe reconstruiu o cliente sem descartar o produto em funcionamento, mantendo entrega contínua enquanto substituía componentes internos. Eles chamaram a abordagem de Ship of Theseus (Slack Engineering, 2019). O resultado se aproxima de um rewrite em escopo final, mas executado com o perfil de risco do refactoring: incrementos verificáveis com rollback disponível em cada etapa.
A decisão útil exige uma análise de custo total: risco de execução, custo de oportunidade do período sem entrega, carga cognitiva da transição e probabilidade realista de conclusão no prazo. O refactoring contínuo deve ser o ponto de partida, porque distribui risco e preserva entrega, mas precisa de condição de saída. Quando o gasto incremental de cada refatoração cresce consistentemente e a distância até a arquitetura alvo se mede em anos, ou quando a plataforma ou o modelo de domínio deixou de ser compatível com a realidade, o rewrite entra como opção legítima. A execução deve seguir o Strangler Fig pra migrações de sistema, ou o Branch by Abstraction pra refatorações dentro do mesmo código (Fowler), evitando o salto de fé de escopo fechado. A preferência do engenheiro é irrelevante pra essa decisão.