Reescrever do zero falha em 70% dos casos e leva 2-3x mais tempo que o estimado. A verdadeira pergunta é: "o que está realmente partido?"., Antes de reescrever, mede: custo de manutenção actual (€/mês), velocidade de feature delivery (features/sprint), taxa de bugs em produção (bugs/10k RPS), e satisfação de clientes (NPS ou churn)., Uma reescrita faz sentido apenas quando estes números estão críticos (>€50k/mês de manutenção, <2 features/sprint, >50 bugs/mês em produção, NPS <20 ou churn >5%/mês)., A alternativa é refactoring estratégico paralelo: moderniza o stack por camadas (dados, API, UI) enquanto mantêm a produção viva. Leva mais tempo, mas reduz risco de 70% para <10%., Caso real: empresas que pararam reescritas a meio (GitLab, Stripe v1 vs v2 transition) passaram a incrementalismo controlado. A maioria nunca voltou.
O Verdadeiro Custo de uma Reescrita
Vamos ser directos. Quando ouves "o código é uma bagunça, precisamos reescrever", o que realmente está acontecer é um de três cenários:
- A base de código é velha mas estável. Os desenvolvedores novos demoram 3-4 semanas a aprender. Há código duplicado, mas nada explodiu.
- O produto está a falhar de forma real: P99 latencies acima de 1000ms, taxa de bugs >10/dia em produção, features novas demoram 3 sprints para sair.
- A stack está obsoleta (Python 2, Rails 3, Backbone.js) e atrapalha contratação de talento.
Cada um merece abordagem diferente. A reescrita completa só faz sentido no segundo cenário. E mesmo aí, é arriscada.
Estudos de indústria mostram que reescritas de software completo têm taxa de sucesso abaixo de 30%. Joel Spolsky escreveu sobre isto há 20 anos ("Things You Should Never Do"), e o padrão mantém-se. Porque?
Quando reescreves, redesenhas implicitamente. Isso significa que features "óbvias" da versão antiga desaparecem ou ficam para "fase 2". Os clientes vêem downtime ou degradação. O moral da equipa cai porque estão a fazer funcionalidade conhecida de novo, ao invés de inovação.
Entretanto, a versão antiga continua a ter bugs que descobrem na produção. A nova versão não tem correções para esses bugs porque o código é novo. Logo, o tempo para "feature parity" é mínimo 18-24 meses num produto não-trivial (complexidade média: 100k linhas, 20+ features, 50+ integrações).
Custos reais de uma reescrita (médias de indústria):
| Fase | Duração | Custo (equipa de 5 eng) | Risco |
|---|---|---|---|
| Análise e desenho | 2 meses | €80k | Subestimar complexidade |
| MVP novo | 4 meses | €160k | Feature parity incompleta |
| Migração dados (hard part) | 3 meses | €120k | Perda/corrupção de dados |
| Testes + correções | 3 meses | €120k | Bugs em produção |
| Sunset versão antiga | 2 meses | €80k | Regressões inesperadas |
| TOTAL | 14 meses | €560k | 50-70% de falha |
E isto é o caso optimista. Se a complexidade é maior (muitas integrações, historicamente muitos dados, regras de negócio complexas), multiplica tudo por 1.5x.
Os Números que Definem o Problema Real
Antes de qualquer decisão, mede isto. Dados concretos, não sentimentos.
1. Custo mensal de manutenção
Pega no tempo que a equipa gasta em "manutenção" vs "feature delivery". Se 60% do sprint é bugfixes, tech debt, e suporte legado, és candidato. Se é 20%, não és.
Fórmula: (horas gastas em manutenção por sprint / total horas) × (custo mensal da equipa)
Exemplos:, SaaS estável: 15% manutenção = €12k/mês numa equipa de €80k/mês total. Aceitável., SaaS degradado: 60% manutenção = €48k/mês. Crítico.
2. Latência de entrega de features
Quanto tempo leva uma feature "média" da ideia ao produção?, Saudável: 2-3 sprints (10-15 dias), Aviso: 5-6 sprints (25-30 dias), Crítico: 8+ sprints ou bloqueada indefinidamente
3. Taxa de bugs em produção (normalizada)
Bugs por 10k requests é uma métrica boa porque escala com volume:
bugs_per_10k_rps = (bugs_em_producao_por_semana / avg_rps_por_semana) × 10000
```, Saudável: <5 bugs/10k RPS, Aviso: 10-20 bugs/10k RPS, Crítico: >30 bugs/10k RPS (cada deployment é Russian roulette)
**4. NPS ou taxa de churn**
Se clientes saem porque o produto é lento ou com bugs constantes, é sintoma de problema profundo., NPS >50: Não reescreve, NPS 20-50: Observa com atenção, NPS <20 ou churn >5%/mês: Reescrita é opção legítima
**5. Capacidade de contratação**
Se ninguém quer trabalhar na stack antiga (Rails 3, Angular 1, PHP 5), és numa desvantagem competitiva real. Isto não é vaidade tecnológica. Bons engenheiros recusam código legacy genuinamente quebrado porque sabem que vão ficar presos.
---
## A Armadilha: Porque é que Reescritas Falham (Mesmo Com Boas Intenções)
Vi isto em consultoria várias vezes.
**Erro 1: Ignorar feature parity**
A versão antiga tem 15 anos de features, alguns deles obscuros. Um cliente usa "exportar para CSV com custom headers", outro usa "bulk update via API v2", outro tem integrações com sistemas antigos. Quando a nova versão sai, 5 clientes grandes descobrem que feature X desapareceu. NPS cai. Revenue cai.
**Erro 2: Subestimar migração de dados**
Dados são o mais difícil. Migrando 500GB de histórico com referências cruzadas, sem downtime? Espera 3 meses, não 2 semanas. Se houver corrupção ou inconsistência, descobres em produção. Entretanto, suporte explode.
**Erro 3: Dois produtos em paralelo = custo 2x**
Enquanto reescreves, alguém precisa manter a versão antiga (bugs, patches de segurança, features urgentes de clientes). Logo: 2 equipas, 2 repositórios, 2 bases de dados. Isto não é paralelo, é duelo. É sempre mais lento que esperado.
**Erro 4: Underestimate da complexidade**
"Vai ser simples porque temos spec clara." Não é. Sempre há edge cases, integrações esquecidas, regras de negócio que só vivem no Excel de um cliente. A nova versão descobrirá isto tarde.
**Erro 5: Timing do go-live**
Se planeias go-live numa quarta-feira de inverno, e dá erro, suporte está de folga. Sempre. Go-live deve ser numa terça-feira de manhã, com toda a gente presente e descansada.
---
## A Alternativa Inteligente: Refactoring Estratégico Paralelo
Em vez de reescrever tudo, moderniza por camadas. Isto é mais lento no início, mas reduz risco dramaticamente (de 70% para <10%).
**Estratégia: Strangler Fig Pattern**
```typescript
// Versão antiga: Node.js + Express 3, sem tipos, sem testes
app.get('/api/users/:id', function(req, res) {
db.query('SELECT * FROM users WHERE id = ' + req.params.id,
function(err, result) {
if (err) res.json({error: true});
else res.json(result);
}
);
});
// Fase 1: Coloca proxy moderno à frente (Express 5 + TypeScript)
// Redireciona endpoints um a um para nova implementação
app.get('/api/users/:id', async (req: Request, res: Response) => {
try {
const userId = parseInt(req.params.id, 10);
if (isNaN(userId)) {
return res.status(400).json({ error: 'Invalid user ID' });
}
const user = await db.query(
'SELECT id, email, name, created_at FROM users WHERE id = $1',
[userId]
);
if (!user.rows.length) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user.rows[0]);
} catch (err) {
logger.error('GET /api/users/:id failed', { userId: req.params.id, err });
res.status(500).json({ error: 'Internal server error' });
}
});
// Fase 2: Gradualmente muta tráfego para nova implementação
// 5% tráfego → 25% → 50% → 100% (over 3-6 months)
// Se erro rate subir em 2%, volta para versão antiga
Vantagens:
- Rollback é trivial: Se a nova implementação de "/api/users/:id" falha, redireciona de volta para a antiga em 5 minutos.
- Zero downtime: Clientes não sabem que há migração.
- Validação real: Testa a nova implementação com tráfego verdadeiro antes de comprometimento total.
- Menos burnout: Equipa não está sob pressão de "big bang" go-live.
O trade-off é simples: leva mais tempo (12-18 meses vs 14-18 meses comprimidos). Mas com taxa de sucesso de 90%+ vs 30%.
Quando Vale Realmente a Pena Reescrever
Se mediste os números e a situação é crítica, reescrita pode ser a resposta. Mas com condições.
Reescrita faz sentido se:
- Custo de manutenção mensal é >€50k e a tendência é crescente
- Taxa de bugs é >30/10k RPS e afecta direitamente revenue (clientes grande a reclamar)
- Feature delivery abrandou para <2 features/sprint e é o bottleneck do negócio
- Stack é verdadeiramente obsoleto (segurança, suporte, contratação)
- Tens budget dedicado (não roubado de feature delivery)
- Tens tempo: 18-24 meses
Reescrita NÃO faz sentido se:
- O problema é política da equipa, não código
- Esperas que reescrita resolva problemas de negócio (é ilusão)
- Não tens equipa estável (churn alto = reescrita morre)
- Competição é acirrada (não tens 18 meses para pausar feature delivery)
Exemplo: Uma Métrica Concreta para Decidir
Aqui está um quadro de decisão que podes usar:
SCORE DE REESCRITA (0-100)
[ ] Custo manutenção >€50k/mês: +25 pontos
[ ] Feature delivery <2 features/sprint: +25 pontos
[ ] Taxa bugs >30/10k RPS: +20 pontos
[ ] NPS <20 ou churn >5%/mês: +15 pontos
[ ] Stack obsoleto (suporte no EOL): +15 pontos
Scoring:
0-30: Continua com código actual. Refactoring cosmético.
30-60: Considera Strangler Fig Pattern. Moderniza gradualmente.
60-100: Reescrita é opção. Mas faz Strangler Fig mesmo assim, é mais seguro.
Conclusão
Reescrever um SaaS legacy é como renovar uma casa enquanto a habitas. Parece mais fácil demolir e reconstruir, mas o custo e risco são sempre maiores que o previsto. A maioria das vezes, o caminho inteligente é refactoring estratégico com Strangler Fig Pattern: paralelo, incremental, e com rollback sempre disponível.
Mede os números (manutenção, latência, bugs, churn) antes de qualquer decisão. Décadas de software engineering dizem que reescritas completas falham 70% das vezes. As 30% que conseguem sucesso tinham preparação e timing perfeitos.
Se estás a enfrentar um problema parecido, marca uma conversa em https://impact-origin.com/agendamento.
