Skip to content

Recette : Migration de stack technologique

Cette recette décrit la planification et l'exécution d'une migration technologique avec SpecForge. Nous utiliserons la migration d'une API Node.js d'Express 4 vers Fastify comme exemple — une migration courante qui touche le routage, les middlewares, les plugins et la gestion des erreurs.

Le même flux de travail s'applique à toute migration technologique : mises à niveau de framework, changements de moteur de base de données, remplacement d'ORM ou mises à niveau de langage.


Avant de commencer

Les migrations sont à haut risque car elles touchent de nombreux fichiers et peuvent casser le comportement de façon subtile. SpecForge réduit ce risque en :

  1. Créant une spec de parité fonctionnelle avant tout changement de code
  2. Générant des tests qui vérifient que le comportement correspond avant et après
  3. Fournissant un plan de migration par phases avec rollback à chaque étape
  4. Détectant le drift au fur et à mesure de l'avancement de la migration

Étape 1 — Analyser la base de code source

Prompt :

Rétro-ingénieure ma base de code dans /Users/moi/mon-app/src pour le projet proj_abc123

Cela crée des specs depuis l'implémentation actuelle — documentant ce que l'application fait réellement. Ces specs deviennent la baseline de parité fonctionnelle.


Étape 2 — Analyser le périmètre de la migration

Prompt :

Planifie une migration d'Express vers Fastify pour le projet proj_abc123

Ce à quoi s'attendre :

## Analyse de migration : Express 4 → Fastify 5

### Périmètre
- 23 fichiers de routes
- 8 middlewares (auth, logging, rate-limit, cors, compression, error, validation, cache)
- 4 gestionnaires d'erreurs
- 2 intégrations WebSocket (socket.io → @fastify/websocket)
- 12 fichiers de tests mockant les internals express

### Carte d'équivalences
Express                    → Fastify
─────────────────────────────────────────
app.use(middleware)        → fastify.addHook / fastify.register(plugin)
app.get('/path', handler)  → fastify.get('/path', { schema }, handler)
req.body                   → request.body (identique)
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 (package)             → @fastify/cors
helmet                     → @fastify/helmet
express-rate-limit         → @fastify/rate-limit
socket.io                  → @fastify/websocket + ws directement

### Zones à risque
- Élevé : migration socket.io (pas d'équivalent direct — changement de comportement)
- Élevé : ordre des middlewares (le cycle de vie Fastify diffère d'Express)
- Moyen : gestion des erreurs (Fastify utilise setErrorHandler, pas le middleware d'erreur)
- Faible : paramètres de routes (syntaxe compatible)

### Effort estimé : 8–14 jours
### Approche recommandée : strangler fig (route par route)

Étape 3 — Créer la spec de migration

Prompt :

Crée une spec pour migrer d'Express vers Fastify dans le projet proj_abc123.
Approche : strangler fig — migrer des groupes de routes un à la fois derrière un reverse proxy.

Critères d'acceptation que la spec inclura :

  1. Les 23 groupes de routes se comportent de façon identique avant et après la migration (suite de tests de parité)
  2. Les schémas de réponse sont validés avec l'intégration AJV native de Fastify
  3. Le middleware d'authentification migré vers les lifecycle hooks Fastify (onRequest)
  4. Les réponses d'erreur maintiennent la même structure JSON que l'implémentation Express
  5. La fonctionnalité WebSocket est préservée (migration de socket.io vers @fastify/websocket)
  6. Pas de régression en temps de réponse — latence P99 Fastify ≤ latence P99 Express × 1,05
  7. Tous les tests d'intégration existants passent contre le serveur Fastify
  8. Migration sans interruption — Express et Fastify fonctionnent simultanément pendant la transition

Étape 4 — Tester le plan de migration sous pression

Prompt :

Challenge la spec de migration pour le projet proj_abc123

SpecForge sondera les cas limites :

  • Que se passe-t-il pour les requêtes en vol lors du basculement Express → Fastify ?
  • Comment les cookies de session sont-ils gérés pendant la période de transition ?
  • Que se passe-t-il si un feature flag échoue et que certains utilisateurs touchent Express, d'autres Fastify ?
  • Y a-t-il des middlewares spécifiques Express n'ayant pas d'équivalent Fastify ?

Étape 5 — Générer les tests de parité fonctionnelle

Prompt :

Génère des tests pour la spec de migration dans le projet proj_abc123

Ces tests s'exécutent contre les deux serveurs Express et Fastify — assurant un comportement identique :

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)
  })
})

Étape 6 — Générer le plan d'exécution

Prompt :

Génère un plan d'exécution pour la spec de migration dans le projet proj_abc123

À quoi ressemble un plan strangler fig :

markdown
## Phase 1 : Fondation
- [ ] Installer Fastify + plugins (fastify-cors, fastify-helmet, etc.)
- [ ] Configurer le serveur Fastify en parallèle d'Express (port différent)
- [ ] Configurer le reverse proxy (nginx/Caddy) avec routage par feature flag
- [ ] Écrire le harnais de tests de parité qui s'exécute contre les deux serveurs

## Phase 2 : Migrer les routes (par groupe — peut paralléliser les groupes)
- [ ] Groupe A : routes /api/auth (risque faible, pas de WebSocket)
- [ ] Groupe B : routes /api/users (risque moyen, changements de validation)
- [ ] Groupe C : routes /api/orders (risque élevé, intégration paiement)
- [ ] Groupe D : routes /api/admin (risque faible, interne uniquement)

## Phase 3 : Migrer les middlewares
- [ ] Hook auth (middleware Express → Fastify onRequest)
- [ ] Gestionnaire d'erreurs (next(err) → setErrorHandler)
- [ ] Rate limiting (@fastify/rate-limit)
- [ ] CORS + Helmet (@fastify/cors, @fastify/helmet)

## Phase 4 : Migration WebSocket
- [ ] Remplacer socket.io par @fastify/websocket + ws
- [ ] Migrer côté client socket.io → WebSocket natif
- [ ] Test de parité : flux de messages WebSocket

## Phase 5 : Basculement
- [ ] Basculer le reverse proxy à 100% Fastify
- [ ] Garder Express en fonctionnement pendant 48h (fenêtre de rollback)
- [ ] Supprimer Express après 48h sans incident
- [ ] Mettre à jour PLAN.md et marquer la spec de migration comme done

Étape 7 — Exécuter la migration

À chaque phase :

  1. Implémenter les changements
  2. Exécuter les tests de parité contre les deux serveurs
  3. Valider la parité fonctionnelle avec validate
  4. Détecter le drift entre la spec de migration et l'implémentation

Prompt après chaque phase :

Valide la spec de migration contre le code dans /Users/moi/mon-app/src pour le projet proj_abc123

Étape 8 — Validation des performances

Prompt :

Audite le code dans /Users/moi/mon-app/src pour le projet proj_abc123

Vérifiez que l'implémentation Fastify obtient au moins aussi bien que la baseline Express sur la conformité architecturale et la qualité du code.

Pour la validation de latence, exécutez votre outil de test de charge (k6, Artillery, wrk) contre les deux serveurs et comparez la latence P99 — le critère de la spec dit que Fastify P99 ≤ Express P99 × 1,05.


Étape 9 — Documenter les décisions architecturales

Prompt :

Génère des ADR pour la spec de migration dans le projet proj_abc123

Cela produit :

  • ADR-001 : Pourquoi strangler fig plutôt qu'une migration big-bang
  • ADR-002 : @fastify/websocket plutôt que socket.io dans le contexte Fastify
  • ADR-003 : AJV JSON Schema plutôt qu'express-validator pour la validation des requêtes

Étape 10 — Capturer les apprentissages

Prompt :

Capture learning : lors de la migration d'Express vers Fastify, l'ordre des middlewares importe davantage —
les lifecycle hooks Fastify (onRequest, preHandler, onSend) doivent être planifiés avant le début de la migration,
pas découverts pendant l'implémentation

Plan de rollback

L'approche strangler fig de SpecForge signifie que le rollback est toujours possible :

PhaseAction de rollback
Pendant la migrationBasculer le reverse proxy à 100% Express
Après le basculement (< 48h)Express est toujours en fonctionnement — changer le proxy
Après la suppression d'ExpressRestaurer depuis le tag git pre-migration

Taguez toujours le dernier commit Express stable avant de commencer : git tag pre-fastify-migration.


Appliquer cette recette à d'autres migrations

MigrationPréoccupation principaleApproche recommandée
Django → FastAPIPatterns async, différences ORMStrangler fig
Mongoose → PrismaMigration de schéma, API de requêteModule par module
React classes → hooksParité comportementale, cycle de vieComposant par composant
PostgreSQL → CockroachDBDifférences de dialecte SQLRéplica de lecture en premier
REST → GraphQLChangement cassant côté clientAdditif (garder REST)
Node 18 → Node 22Dépréciations d'APIdetect_deprecations en premier