Un plan de migration du système existant avant tout code
Construisez un plan de migration du système existant autour des preuves, de l’ordre d’extraction, des tests de parité et des décisions techniques.

Une migration d’un système existant échoue bien avant que le code généré paraisse manifestement faux. Elle échoue quand l’équipe demande à un modèle, dans une seule invite, de comprendre le système, de choisir une nouvelle architecture, de préserver les comportements cachés, de planifier le travail et de juger son propre résultat. Cette invite peut produire un dépôt impressionnant. Elle ne peut pas produire une chaîne de décisions défendable.
Le plan doit exister avant le premier fichier écrit dans le langage cible. Je parle de bien plus qu’un backlog rempli de cases nommées "convertir la facturation" et "migrer les rapports". Un plan utile désigne les preuves de chaque comportement, l’ordre dans lequel l’équipe les extraira, la frontière cible qui le remplacera et le test qui autorisera le changement suivant. Si l’un de ces champs est vide, la génération doit attendre.
Cette distinction compte parce qu’un modèle de langage génère à partir du contexte qu’il reçoit, tandis qu’un ingénieur doit trouver le contexte que personne n’a pensé à inclure. Les anciens systèmes cachent leurs règles dans le contrôle des travaux, les déclencheurs de base de données, les habitudes des opérateurs, les formats de fichiers, les réglages d’imprimante, les scripts de reprise et les exceptions de clôture mensuelle. Le travail difficile consiste à décider ce qui constitue un comportement et à prouver que le remplacement le conserve.
Inventorier les comportements avant les fichiers
L’inventaire d’une migration doit décrire les comportements observables, pas seulement les fichiers sources et le nombre de langages. Les listes de fichiers aident à estimer le travail d’analyse, mais disent très peu du contrat dont dépendent les utilisateurs et les systèmes connectés. Une étape JCL de douze lignes peut décider si le fichier de règlement de la veille sera rejoué. Un grand module de rapport peut produire une sortie que personne ne lit.
Commencez à la frontière du système. Notez chaque entrée, sortie, événement planifié, action d’opérateur, appel externe, stockage persistant et signal d’échec. Pour chacun, capturez un exemple réel et identifiez la personne capable de dire s’il est correct. Vous obtenez ainsi une surface comportementale testable. Vous pouvez alors seulement y rattacher les unités sources.
J’utilise quatre catégories de preuves parce que les équipes les mélangent régulièrement:
- Preuves exécutées: requêtes de production, entrées de lots, modifications de bases de données, fichiers, messages et sorties réellement traités par le système actuel.
- Comportement déclaré: manuels, accords d’interface, copybooks, schémas, textes d’aide et procédures qui décrivent ce qui devrait se passer.
- Chemins implémentés: branches, requêtes, travaux, déclencheurs et gestionnaires d’erreurs présents dans le code.
- Pratique opérationnelle: horaires, corrections manuelles, points de reprise et exceptions appliqués par les opérateurs en dehors du programme.
Ces catégories peuvent se contredire. Ce désaccord est un constat, pas une gêne à effacer. Si le manuel impose un champ alors que le trafic enregistré contient des valeurs vides, le plan de migration doit décider si la compatibilité ou la règle écrite l’emporte. Une génération unique choisit généralement l’artefact qui semble faire le plus autorité dans son contexte. Un ingénieur consigne le conflit, trouve le responsable et transforme la décision en test.
Construisez une table des frontières avant d’écrire le code cible. Une petite version pourrait ressembler à ceci:
| Frontière | Preuves | Responsable | Règle de compatibilité | Vérification |
|---|---|---|---|---|
| Fichier de comptes nocturne | Trois fichiers acceptés et un rejeté | Responsable d’exploitation | Conserver les largeurs fixes et le code de rejet 17 | Rejouer les quatre fichiers |
| Calcul des taxes | Requêtes enregistrées et table des taux courants | Responsable des systèmes financiers | Faire correspondre le total arrondi et les champs d’audit | Comparer réponse et lignes du registre |
| Impression des relevés | Échantillons de spool et configuration d’imprimante | Responsable du service client | Conserver les sauts de page et l’ordre de tri | Générer et examiner les cas nommés |
Cette table révèle tôt les preuves absentes. Elle empêche aussi l’erreur habituelle qui consiste à prendre le schéma de base de données pour tout le modèle métier. Une colonne peut autoriser une valeur nulle parce qu’un import en échec y dépose des données partielles, alors que toute transaction normale exige une valeur. La forme du schéma et le sens métier sont deux faits différents.
Le registre de migration est le vrai plan
Un plan de migration du système existant utile est un registre exécutable de déclarations, de dépendances et de portes. Il doit permettre à un autre ingénieur de répondre à cinq questions pour chaque unité de travail: que modifions-nous, quelles preuves définissent son comportement actuel, que faut-il avoir terminé auparavant, comment allons-nous comparer l’ancien et le nouveau, et qui accepte une différence volontaire?
Un tableau de tickets ne suffit pas. Les tickets dérivent, les notes d’acceptation deviennent de la prose et les dépendances restent en mémoire. Gardez un registre lisible par machine dans le dépôt et faites référence à ses identifiants pendant les revues. Il peut prendre la forme de YAML, JSON ou d’une table de base de données. L’essentiel est que l’absence de preuve reste visible.
- id: CALC-014
boundary: POST /interest/accrue
evidence:
traffic_set: traffic/interest/month_end_2025_01.ndjson
state_snapshot: snapshots/ledger_before.sql.zst
depends_on: [DATA-006, CLOCK-002]
target: services/interest/accrual.go
invariants:
- response.status == legacy.response.status
- ledger.delta_cents == legacy.ledger.delta_cents
- audit.event_type == legacy.audit.event_type
allowed_differences:
- field: response.request_id
rule: compare_presence_only
approved_by: architecture-review-27
gate: parity/CALC-014
Ce fragment évite trois échecs. Il empêche un développeur de tester le calcul sans l’état qui le détermine. Il transforme les identifiants de requête non déterministes en règle de comparaison explicite plutôt qu’en liste d’exclusion croissante. Il lie aussi l’approbation à une différence précise, afin que personne ne puisse élargir discrètement l’exception plus tard.
Le registre doit séparer les découvertes des décisions. "Le service existant renvoie 200 pour une requête en double" est une observation. "Le remplacement conservera cette réponse" est une décision de compatibilité. "Nous devrions renvoyer 409" est une préférence de conception. Mélanger ces phrases permet à un nettoyage souhaitable de passer pour une migration fidèle.
N’inscrivez pas de pourcentage comme "module migré à 80 %" dans le registre. Les pourcentages cachent le comportement restant. Comptez plutôt les portes fermées par rapport aux frontières nommées. Dix variantes mineures de rapport ne compensent pas un seul chemin de comptabilisation non vérifié, et le plan doit le rendre évident.
Le plan a aussi besoin de conditions d’arrêt. La génération s’arrête lorsqu’une preuve manque, qu’une dépendance ne possède pas de cible vérifiée, que la comparaison produit une différence inexpliquée ou qu’aucun responsable n’a approuvé un changement volontaire. Sans ces conditions, la pression du calendrier transforme chaque résultat rouge en ticket de nettoyage futur.
Extraire des frontières vers le centre
L’ordre d’extraction le plus sûr commence par les frontières observables, passe par la sémantique des données et l’orchestration, puis atteint seulement les algorithmes internes. Cet ordre donne à chaque génération ultérieure un contrat et un moyen de mesurer son résultat. Commencer par le module qui paraît le plus autonome semble efficace, mais crée souvent une île aux interfaces devinées.
Capturez d’abord les entrées et sorties aux jointures stables. Pour un service en ligne, cela peut inclure le corps des requêtes et des réponses, les en-têtes, les effets en base de données et les messages émis. Pour un système de lots, il s’agit des générations d’entrée, cartes de contrôle, codes retour, sorties de spool, fichiers produits et comportement de reprise. Pour une application de bureau, ajoutez les actions utilisateur, fichiers locaux, rapports, état du registre ou de la configuration et appels aux bases de données partagées.
Extrayez ensuite le sens des données. Cartographiez les identifiants, unités, encodages, règles de valeur nulle, échelles décimales, règles de date et cycles de vie des enregistrements. Ne normalisez pas encore. Un champ décimal compacté, un code complété par des espaces et un horodatage en heure locale peuvent sembler laids, mais chacun peut porter un comportement. Consignez comment chaque valeur entre dans le système et où elle devient observable avant de choisir une représentation plus propre.
Reconstituez ensuite l’orchestration. Les anciens systèmes placent souvent l’ordre métier hors des modules métier. Le JCL définit quel programme suit un code retour. Des scripts CL changent de bibliothèque. Un script d’enveloppe relance une commande mais pas la suivante. Un ordonnanceur fournit une date métier différente de l’horloge de la machine. Si la génération voit les programmes appelés sans cette orchestration, elle construit des fonctions individuellement plausibles dans le mauvais ordre.
Identifiez ensuite les transitions d’état et les invariants. Décrivez une transaction par son état initial, son stimulus, son état final et les effets émis. C’est plus précis que de traduire les procédures une par une. Cela révèle aussi le traitement des doublons, les validations partielles, les actions compensatoires et les points de reprise.
L’équipe ne devrait générer les implémentations internes et l’architecture cible qu’après avoir établi ces couches. Les frontières des services cibles doivent suivre les responsabilités, les besoins de cohérence et les modes de changement. Elles ne doivent pas recopier l’arborescence des sources. Une traduction individuelle des modules conserve les couplages accidentels et appelle cela une modernisation.
Il existe une exception pratique. Il faut parfois construire tôt un analyseur léger ou un émulateur pour lire des preuves enfermées dans un format propriétaire. Faites-en un outil d’extraction, qualifiez-le de jetable et testez-le sur des échantillons connus. Ne laissez pas ce composant pratique devenir discrètement l’architecture de production.
Séparer preuves, interprétations et décisions
Les ingénieurs ont besoin d’enregistrements distincts pour ce que le système a fait, le sens qu’ils lui donnent et ce que le projet décide de conserver. Une longue invite fond ces trois éléments dans un texte fluide. Une fois fusionnés, personne ne peut dire si une exigence générée provient du trafic, du code source ou d’une déduction.
Utilisez une fiche d’affirmation pour chaque comportement qui contrôlera l’implémentation. Elle n’a pas besoin de cérémonie. Elle a besoin d’une provenance et d’un statut.
{
"claim_id": "BATCH-031",
"statement": "A rerun skips records already posted for the same business date",
"kind": "observed",
"evidence": ["run-884/input.dat", "run-884/ledger-after.csv", "ops-runbook-4.2"],
"confidence": "confirmed",
"decision": "preserve",
"tests": ["parity/batch_031_first_run", "parity/batch_031_rerun"]
}
La distinction entre comportement observé et comportement déduit paraît facile à écarter jusqu’à ce qu’elle provoque une erreur de données. Supposons que le code consulte une table "déjà comptabilisé" avant d’écrire. Un générateur peut en déduire l’idempotence. Les preuves de production peuvent montrer que cette table est vidée pendant une procédure de récupération particulière, de sorte que certaines reprises comptabilisent volontairement une seconde fois. Le chemin du code, la pratique opérationnelle et le contrat attendu divergent. La fiche oblige l’équipe à résoudre ce conflit.
Traitez les commentaires comme des affirmations, pas comme la vérité. Il en va de même des noms de variables, branches mortes, anciens documents de conception et tests qui n’ont jamais tourné sur un état proche de la production. Chacun peut orienter l’enquête. Aucun ne doit supplanter une preuve exécutée sans décision désignée.
Les niveaux de confiance doivent avoir un sens opérationnel. "Confirmé" peut exiger deux types de preuves indépendants et la revue d’un responsable. "Provisoire" peut autoriser le travail sur un analyseur tout en bloquant l’implémentation cible. "Inconnu" doit créer une tâche d’extraction. Si ces étiquettes ne communiquent qu’un sentiment, elles plieront sous la pression des délais.
Conservez les améliorations volontaires dans un registre des changements lié à l’affirmation de compatibilité. Il peut s’agir de rejeter une date invalide acceptée par l’ancien système, de remplacer une méthode d’authentification faible ou de modifier la disposition d’un rapport. Testez séparément le chemin conservé et le nouveau comportement. Sinon, un échec de parité et une amélioration voulue deviennent impossibles à distinguer, ce qui complique revue et retour arrière.
Chaque génération se termine par une porte de parité
Chaque étape de génération doit finir par une porte de parité qui compare les effets observables avec le système actuel. La revue de code et les tests unitaires dans le langage cible sont nécessaires, mais ils ne prouvent pas la compatibilité. Ils indiquent si le nouveau code est raisonnable en lui-même, pas s’il se comporte comme le système en service.
Une boucle utile comporte cinq mouvements:
- Sélectionnez une entrée du registre dont les dépendances ont passé leurs portes.
- Réunissez uniquement son contexte approuvé: affirmations, schémas, échantillons de preuve, contraintes cibles et différences autorisées.
- Générez ou révisez la plus petite portion cible capable de satisfaire la frontière.
- Rejouez le même stimulus sur l’ancien et le nouveau système à partir d’états équivalents.
- Classez chaque différence, puis acceptez, révisez, escaladez ou modifiez la fiche de décision.
L’équivalence de l’état mérite de l’attention. Si l’exécution existante démarre avec trente ans d’historique client et le remplacement avec des fixtures construites à la main, des réponses identiques prouvent peu de chose. Prenez un instantané de l’état pertinent, masquez-le lorsque nécessaire, préservez les relations référentielles et documentez tout état impossible à reproduire. Pour les systèmes qui ne peuvent pas fonctionner deux fois sur le même état, clonez cet état ou enregistrez les effets à une jointure.
La comparaison doit être sémantique, pas un diff de texte brut. Ne normalisez les champs que pour des raisons inscrites dans le registre. Vous pouvez comparer des horodatages dans une tolérance approuvée, ignorer la valeur des identifiants générés tout en exigeant leur présence, mettre les objets JSON dans un ordre canonique ou comparer un PDF par le texte extrait et la géométrie de page. N’ajoutez jamais une règle d’exclusion globale simplement pour faire passer une compilation rouge au vert.
Un rapport de parité doit montrer l’entrée, le jeu de preuves, l’ancien résultat, le nouveau résultat, les règles de normalisation, les différences et leur traitement. Cette forme compacte suffit à l’automatisation et à la revue:
gate=CALC-014 evidence=month_end_2025_01
cases=184 matched=183 different=1 errored=0
difference[1].path=ledger.entries[2].amount_cents
difference[1].legacy=1250
difference[1].target=1249
difference[1].rule=exact
status=FAIL
La différence d’un centime n’est pas "assez proche". Elle signale un ordre d’arrondi, une représentation décimale ou un état divergent. Un ingénieur la suit dans les valeurs intermédiaires, vérifie la sémantique arithmétique de la source et ajoute le plus petit test qui isole la cause. Régénérer tout le module avec une instruction plus insistante modifie souvent des comportements sans rapport et détruit la piste de preuves.
Exécutez les portes en continu, pas dans une phase d’acceptation finale. Une frontière validée devient une contrainte pour les travaux ultérieurs. Lorsqu’une correspondance de données partagée change, le graphe des dépendances indique quelles portes doivent repasser. Voilà pourquoi le registre et le banc de test vont ensemble: l’un dit ce qui peut changer, l’autre montre ce qui a changé.
Une invite géante échoue de façon prévisible
Une seule invite de migration échoue parce que ses missions se contredisent et que son contexte ne possède aucun mécanisme d’application. Davantage de contexte peut améliorer le rappel, mais ne crée ni provenance des preuves, ni ordre des dépendances, ni jugement indépendant, ni porte de test durable. Le dépôt généré peut être cohérent tout en étant faux à chaque frontière absente de l’invite.
Prenons une chaîne de facturation nocturne. L’ordonnanceur fournit une date métier. Une étape JCL trie les transactions selon un classement propre aux paramètres régionaux. Un programme comptabilise les lignes valides et écrit les rejets. Un code retour décide si les relevés sont produits. L’exploitation peut reprendre après la comptabilisation sans la répéter. Les modules sources contiennent des fragments de ce comportement, mais aucun module ne possède le contrat complet.
Une grande invite demande une réécriture en Go et inclut les programmes, copybooks, fichiers d’exemple ainsi qu’une phrase disant "conserver le comportement". Le résultat utilise la date de la machine, trie les chaînes avec la valeur par défaut du runtime cible, enveloppe le lot dans une transaction unique et traite tout rejet comme une erreur fatale. Chaque choix pourrait se défendre dans un nouveau système. Ensemble, ils cassent la clôture mensuelle.
Le premier fichier de test contient des enregistrements ordinaires, si bien que les deux systèmes calculent les mêmes totaux. L’équipe se réjouit. La première reprise répète les écritures, car la cible ne possède pas de point de contrôle correspondant à l’étape existante. Un fichier dont le suffixe de compte est vide se trie différemment et change le regroupement. Une seule mauvaise ligne annule maintenant des travaux valides que l’ancienne chaîne aurait comptabilisés. Aucune de ces erreurs ne ressemble à un défaut de syntaxe ni à une conception manifestement absurde.
Une extraction planifiée les aurait détectées dans l’ordre. La capture des frontières consigne la date métier et les codes retour. L’analyse des données consigne le classement et le remplissage par espaces. L’analyse de l’orchestration consigne les points de validation et de reprise. Le rejeu comprend les exécutions ordinaires, rejetées et reprises. L’architecture cible peut toujours améliorer l’implémentation, mais elle ne peut pas effacer ces contrats par accident.
La réponse populaire consiste à allonger l’invite. Cela n’aide que si l’omission est le seul problème. Elle rend la résolution des conflits plus difficile, enfouit la preuve qui soutient chaque instruction et laisse toujours le générateur juger son propre travail. Diviser l’invite entre plusieurs agents ne corrige pas non plus le problème tout seul. Plusieurs générateurs ont besoin du même registre, des mêmes règles de responsabilité et des mêmes portes de parité, sinon ils distribuent simplement plus vite des hypothèses non suivies.
Employez la génération comme une opération d’implémentation délimitée. Donnez-lui une portion cible, des contraintes explicites, les preuves nécessaires à cette portion et la sortie de parité en échec de la tentative précédente. Examinez ensuite la modification et exécutez la porte en dehors du processus de génération. Cette séparation garde le modèle productif sans lui donner une autorité qu’il ne peut assumer de façon responsable.
L’ingénieur assume les éléments non résolus
Un ingénieur accomplit le travail qui ne se réduit pas à produire du code plausible: trouver les preuves manquantes, décider quelle contradiction compte, choisir une frontière, négocier les changements volontaires et accepter le risque. Ce ne sont pas des lacunes temporaires que des modèles plus grands feront disparaître. Ce sont des actes de responsabilité au sein d’une organisation donnée.
L’ingénieur demande qui subit les conséquences lorsque deux artefacts se contredisent. Si le code source autorise un découvert mais que la politique financière l’interdit, la réponse exige une décision produit et conformité, pas une synthèse pondérée par des probabilités. Si les opérateurs dépendent d’une astuce de reprise que la nouvelle conception doit supprimer, l’ingénieur doit comprendre pourquoi elle existe, concevoir un chemin de récupération plus sûr et obtenir un accord sur la rupture volontaire de compatibilité.
L’ingénieur contrôle aussi la décomposition. Un générateur tend à suivre la structure qu’il voit. L’ingénieur peut reconnaître que six programmes forment une seule frontière de cohérence, ou qu’un monolithe contient quatre capacités relevant de responsables indépendants. Ce jugement vient de la sémantique des transactions, des besoins de déploiement, de l’historique des incidents et des personnes qui entretiendront la cible.
La revue doit se concentrer sur les affirmations et les effets avant le style. Demandez quelle entrée du registre la modification clôt, quelles preuves elle utilise, quelle décision cible elle incarne et ce que dit le rapport de parité. Un service parfaitement idiomatique avec une différence de sortie inexpliquée reste inachevé. Un adaptateur disgracieux qui préserve une frontière difficile peut être exactement le bon composant temporaire.
Les ingénieurs doivent aussi empêcher le banc de test de devenir une simple machine d’approbation. Chaque règle de normalisation exige une raison. Chaque fichier de référence exige une provenance. Chaque modification d’un résultat attendu mérite la même revue qu’un changement de comportement en production. Si l’équipe met à jour les instantanés chaque fois qu’un test échoue, elle a construit une machine à valider, pas un banc de parité.
La vitesse reste possible. Générez en parallèle analyseurs, adaptateurs, tests, code de correspondance et candidats d’implémentation lorsque les dépendances du registre le permettent. Centralisez l’acquisition des preuves et les résultats des portes. La production parallèle de code est utile; des vérités parallèles se contredisent.
L’architecture ne change que derrière des contrats prouvés
La modernisation doit changer l’architecture derrière des contrats préservés, pas traduire l’ancienne structure ligne par ligne. Dès qu’une frontière possède ses preuves et sa porte de parité, l’équipe peut remplacer l’état partagé par des services explicites, isoler les noyaux numériques, déplacer les données dans Postgres ou construire un client TypeScript sans deviner si la nouvelle forme a modifié le comportement visible.
Décidez de l’architecture au plus petit niveau pour lequel vous disposez de preuves suffisantes. Certaines décisions appartiennent au départ: contraintes du runtime cible, limites de sécurité, environnement de déploiement, résidence des données et systèmes qui devront coexister pendant la bascule. D’autres devraient attendre: découpage des services, placement des caches, frontières asynchrones et nettoyage du schéma dépendent souvent du comportement découvert pendant l’extraction.
Évitez deux extrêmes. Figer tous les détails de la cible avant la découverte produit un plan élégant pour un système imaginaire. Laisser chaque génération inventer son architecture produit des frontières incohérentes et une infrastructure dupliquée. Consignez les décisions contraignantes, gardez visibles les décisions reportées et indiquez quelles preuves permettront de les fermer.
La planification de la bascule appartient au même registre. Nommez la source de vérité pendant la transition, le sens de synchronisation, la requête de rapprochement, le point de retour arrière et l’interruption maximale acceptée. Un remplacement qui réussit les tests de parité isolés peut encore échouer en exploitation si les deux systèmes écrivent les mêmes enregistrements ou si le retour arrière ne peut pas récupérer les modifications créées uniquement dans la cible.
CodeHero applique cette forme de travail lorsqu’il lit tout un arbre existant, le réécrit en Go, Rust, TypeScript et Postgres, puis vérifie le comportement par un banc de parité face au trafic de production enregistré. Sa promesse de livraison en moins de 30 jours dépend d’un ordre serré entre extraction et vérification; elle ne rend pas le plan facultatif.
Avant d’approuver le premier fichier cible généré, exigez une entrée complète du registre avec de vraies preuves, des dépendances explicites, une règle de comparaison et un responsable nommé pour les différences. Si l’équipe ne peut pas produire cette entrée, elle n’est pas prête à migrer. Elle est seulement prête à générer du code qui semble avoir été migré.
FAQ
Pourquoi une seule longue invite ne peut-elle pas migrer un système existant ?
Une longue invite peut produire une base de code cohérente en apparence, mais elle ne peut pas établir quelles preuves font autorité ni trancher les conflits entre le code, l’exploitation et les règles internes. Elle ne peut pas non plus rendre un jugement indépendant sur la compatibilité lorsqu’elle évalue son propre résultat.
Que doit contenir un plan de migration d’un système existant ?
Pour chaque frontière comportementale, consignez ses preuves, dépendances, destination, invariants, différences autorisées, porte de vérification et responsable de la décision. Le plan doit aussi définir des conditions d’arrêt afin qu’une preuve manquante ou une différence inexpliquée bloque la génération.
Que faut-il extraire en premier d’un code existant ?
Commencez par les entrées, sorties, événements planifiés, actions des opérateurs, effets persistants et signaux d’échec observables. Extrayez ensuite la sémantique des données et l’orchestration avant d’implémenter les algorithmes internes, car ces frontières donnent un contrat aux travaux suivants.
Comment vérifier la réécriture d’un système existant ?
Rejouez le même stimulus sur l’ancien et le nouveau système à partir d’états équivalents, puis comparez chaque effet observable selon des règles de normalisation écrites. Classez chaque écart comme défaut, changement approuvé, problème de preuve ou problème d’environnement.
Les tests unitaires suffisent-ils pour une migration ?
Non. Les tests unitaires montrent que le code cible se comporte comme ses auteurs l’attendent, tandis que les tests de parité montrent s’il correspond au système remplacé. Les deux sont nécessaires, car une implémentation propre peut appliquer fidèlement une hypothèse erronée.
Des agents d’IA peuvent-ils planifier toute une migration de code ?
Les agents peuvent inventorier le code, proposer des correspondances, générer des portions délimitées et enquêter sur les tests en échec. Les ingénieurs restent responsables de la qualité des preuves, de l’ordre des dépendances, des décisions d’architecture, de la résolution des conflits et de l’acceptation des changements de comportement volontaires.
Une modernisation doit-elle conserver tous les comportements existants ?
Non, mais chaque différence doit être volontaire. Conservez l’ancien chemin dans un test de parité, consignez séparément le changement approuvé et testez la nouvelle règle afin qu’un nettoyage souhaité ne masque pas un défaut de compatibilité distinct.
Comment traiter les champs non déterministes dans les tests de parité ?
Écrivez une règle de comparaison étroite, par exemple exiger la présence d’un identifiant sans imposer sa valeur exacte ou autoriser une tolérance temporelle documentée. N’utilisez jamais une liste d’exclusion générale, car elle masquerait des différences importantes ailleurs.
Quand faut-il décider de l’architecture cible ?
Fixez tôt les contraintes fermes et les limites de sécurité, puis reportez les choix qui dépendent du comportement découvert. Ne décidez du découpage des services, du nettoyage des données et des flux asynchrones que lorsque les preuves révèlent les limites de cohérence et de responsabilité à respecter.
Quelle est la première porte avant de générer le code de migration ?
Complétez une entrée du registre avec de vraies preuves d’entrée et de sortie, les dépendances connues, des invariants explicites, les règles de comparaison et un responsable des résultats contestés. Si cette fiche reste incomplète, l’équipe doit poursuivre l’extraction au lieu de générer du code de production.