Skip to content

Receita: Migração de Stack Tecnológica

Esta receita percorre o planejamento e a execução de uma migração de tecnologia usando o SpecForge. Usaremos a migração de uma API Node.js de Express 4 para Fastify como exemplo — uma migração comum que toca rotas, middlewares, plugins e tratamento de erros.

O mesmo fluxo de trabalho se aplica a qualquer migração de tecnologia: upgrades de framework, mudanças de banco de dados, substituições de ORM ou upgrades de linguagem.


Antes de Começar

Migrações são de alto risco porque tocam muitos arquivos e podem quebrar comportamentos de formas sutis. O SpecForge reduz esse risco ao:

  1. Criar uma spec de paridade funcional antes de qualquer mudança de código
  2. Gerar testes que verificam se o comportamento corresponde antes e depois
  3. Fornecer um plano de migração faseado com rollback em cada etapa
  4. Detectar drift conforme a migração progride

Etapa 1 — Analisar a Base de Código Fonte

Prompt:

Faça engenharia reversa da minha base de código em /Users/me/meu-app/src para o projeto proj_abc123

Isso cria specs da implementação atual — documentando o que o app realmente faz. Essas specs se tornam a linha de base de paridade funcional.


Etapa 2 — Analisar o Escopo da Migração

Prompt:

Planeje uma migração do Express para o Fastify para o projeto proj_abc123

O que esperar:

## Análise de Migração: Express 4 → Fastify 5

### Escopo
- 23 arquivos de rotas
- 8 middlewares (auth, logging, rate-limit, cors, compression, error, validation, cache)
- 4 handlers de erro
- 2 integrações WebSocket (socket.io → @fastify/websocket)
- 12 arquivos de teste que mockam internos do express

### Mapa de Equivalências
Express                    → Fastify
─────────────────────────────────────────
app.use(middleware)        → fastify.addHook / fastify.register(plugin)
app.get('/path', handler)  → fastify.get('/path', { schema }, handler)
req.body                   → request.body (mesmo)
res.json(data)             → reply.send(data)
res.status(201).json(data) → reply.code(201).send(data)
next(err)                  → throw err (ou return reply.send(err))
express-validator          → @fastify/ajv-compiler + JSON Schema
multer                     → @fastify/multipart
cors (pacote)              → @fastify/cors
helmet                     → @fastify/helmet
express-rate-limit         → @fastify/rate-limit
socket.io                  → @fastify/websocket + ws diretamente

### Áreas de Risco
- Alto: migração de socket.io (sem equivalente direto — mudança de comportamento)
- Alto: Ordem de middleware (ciclo de vida do Fastify difere do Express)
- Médio: Tratamento de erros (Fastify usa setErrorHandler, não middleware de erro)
- Baixo: Parâmetros de rota (sintaxe compatível)

### Esforço estimado: 8–14 dias
### Abordagem recomendada: Strangler fig (rota por rota)

Etapa 3 — Criar a Spec de Migração

Prompt:

Crie uma spec para migração do Express para Fastify no projeto proj_abc123.
Abordagem: strangler fig — migrar grupos de rotas um de cada vez por trás de um proxy reverso.

Critérios de aceitação que a spec incluirá:

  1. Todos os 23 grupos de rotas se comportam identicamente antes e após a migração (suite de testes de paridade)
  2. Schemas de resposta são validados com a integração AJV nativa do Fastify
  3. Middleware de autenticação migrado para hooks do ciclo de vida do Fastify (onRequest)
  4. Respostas de erro mantêm a mesma estrutura JSON da implementação Express
  5. Funcionalidade WebSocket preservada (migração de socket.io para @fastify/websocket)
  6. Sem regressão no tempo de resposta — latência P99 do Fastify ≤ P99 do Express × 1,05
  7. Todos os testes de integração existentes passam no servidor Fastify
  8. Migração sem downtime — Express e Fastify rodam simultaneamente durante a transição

Etapa 4 — Testar o Plano de Migração

Prompt:

Desafie a spec de migração do projeto proj_abc123

O SpecForge investigará casos extremos:

  • O que acontece com requisições em andamento durante a transição Express → Fastify?
  • Como os cookies de sessão são tratados durante o período de transição?
  • E se um feature flag falhar e alguns usuários acessem o Express, outros o Fastify?
  • Há algum middleware específico do Express sem equivalente no Fastify?

Etapa 5 — Gerar Testes de Paridade Funcional

Prompt:

Gere testes para a spec de migração no projeto proj_abc123

Esses testes rodam contra ambos os servidores Express e Fastify — garantindo comportamento idêntico:

typescript
// parity.test.ts
describe.each([
  ['Express', expressApp],
  ['Fastify', fastifyApp],
])('%s — POST /api/orders', (_, app) => {
  it('returns 201 with order ID on valid payload', async () => {
    const res = await request(app)
      .post('/api/orders')
      .send({ productId: 'prod_1', quantity: 2 })
    expect(res.status).toBe(201)
    expect(res.body).toMatchObject({ orderId: expect.any(String) })
  })

  it('returns 422 on missing productId', async () => {
    const res = await request(app)
      .post('/api/orders')
      .send({ quantity: 2 })
    expect(res.status).toBe(422)
  })
})

Etapa 6 — Gerar o Plano de Execução

Prompt:

Gere um plano de execução para a spec de migração no projeto proj_abc123

Como fica um plano strangler fig:

markdown
## Fase 1: Fundação
- [ ] Instalar Fastify + plugins (fastify-cors, fastify-helmet, etc.)
- [ ] Configurar servidor Fastify junto ao Express (porta diferente)
- [ ] Configurar proxy reverso (nginx/Caddy) com roteamento por feature flag
- [ ] Escrever harness de testes de paridade que roda contra ambos os servidores

## Fase 2: Migrar rotas (por grupo — pode paralelizar grupos)
- [ ] Grupo A: rotas /api/auth (baixo risco, sem WebSocket)
- [ ] Grupo B: rotas /api/users (risco médio, mudanças de validação)
- [ ] Grupo C: rotas /api/orders (alto risco, integração de pagamento)
- [ ] Grupo D: rotas /api/admin (baixo risco, apenas interno)

## Fase 3: Migrar middlewares
- [ ] Hook de auth (middleware Express → Fastify onRequest)
- [ ] Handler de erro (next(err) → setErrorHandler)
- [ ] Rate limiting (@fastify/rate-limit)
- [ ] CORS + Helmet (@fastify/cors, @fastify/helmet)

## Fase 4: Migração WebSocket
- [ ] Substituir socket.io por @fastify/websocket + ws
- [ ] Migrar socket.io do lado do cliente → WebSocket nativo
- [ ] Teste de paridade: fluxo de mensagens WebSocket

## Fase 5: Cutover
- [ ] Trocar proxy reverso para 100% Fastify
- [ ] Manter Express rodando por 48h (janela de rollback)
- [ ] Remover Express após 48h sem incidentes
- [ ] Atualizar PLAN.md e marcar spec de migração como done

Etapa 7 — Executar a Migração

Com cada fase:

  1. Implemente as mudanças
  2. Execute testes de paridade contra ambos os servidores
  3. Valide paridade funcional com validate
  4. Detecte drift entre a spec de migração e a implementação

Prompt após cada fase:

Valide a spec de migração contra o código em /Users/me/meu-app/src para o projeto proj_abc123

Etapa 8 — Validação de Performance

Prompt:

Audite o código em /Users/me/meu-app/src para o projeto proj_abc123

Verifique se a implementação Fastify pontua pelo menos tão bem quanto a baseline Express em conformidade com a arquitetura e qualidade de código.

Para validação de latência, execute sua ferramenta de teste de carga (k6, Artillery, wrk) contra ambos os servidores e compare a latência P99 — o critério da spec diz que P99 Fastify ≤ P99 Express × 1,05.


Etapa 9 — Documentar Decisões Arquiteturais

Prompt:

Gere ADRs para a spec de migração no projeto proj_abc123

Isso produz:

  • ADR-001: Por que strangler fig em vez de migração big-bang
  • ADR-002: @fastify/websocket em vez de socket.io no contexto Fastify
  • ADR-003: JSON Schema AJV em vez de express-validator para validação de requisições

Etapa 10 — Capturar Aprendizados

Prompt:

Capture aprendizado: ao migrar do Express para o Fastify, a ordem dos middlewares importa mais —
os hooks do ciclo de vida do Fastify (onRequest, preHandler, onSend) devem ser planejados antes do início da migração,
não descobertos durante a implementação

Plano de Rollback

A abordagem strangler fig do SpecForge significa que o rollback é sempre possível:

FaseAção de rollback
Durante a migraçãoTrocar proxy reverso de volta para 100% Express
Após cutover (< 48h)Express ainda está rodando — trocar proxy
Após remoção do ExpressRestaurar a partir da tag git pre-migration

Sempre faça tag do último commit Express estável antes de começar: git tag pre-fastify-migration.


Aplicando Esta Receita a Outras Migrações

MigraçãoPreocupação principalAbordagem recomendada
Django → FastAPIPadrões assíncronos, diferenças de ORMStrangler fig
Mongoose → PrismaMigração de schema, API de consultasMódulo por módulo
React class → hooksParidade comportamental, ciclo de vidaComponente por componente
PostgreSQL → CockroachDBDiferenças de dialeto SQLRéplica de leitura primeiro
REST → GraphQLBreaking change no clienteAditivo (manter REST)
Node 18 → Node 22Depreciações de APIdetect_deprecations primeiro