Aller au contenu
14 août 2026·7 min de lecture

Comment mesurer le code mort sans supprimer une règle métier ?

Apprenez à mesurer le code mort par l'accessibilité statique, la couverture à l'exécution, le rejeu du trafic et des tests de fin d'année.

Comment mesurer le code mort sans supprimer une règle métier ?

Le code mort n'est pas tout ce qui paraît vieux, maladroit ou silencieux en production. C'est du code dont on peut décrire précisément l'accessibilité, l'observation et la responsabilité métier, preuves à l'appui. Ces affirmations sont différentes. Les réunir sous une seule étiquette conduit une opération de nettoyage ou de réécriture à supprimer l'unique implémentation d'un ajustement annuel, d'un contrat dormant ou d'une procédure de reprise.

J'ai vu des équipes supprimer des routines dont personne ne reconnaissait le nom, puis découvrir qu'un ordonnanceur les appelait avec un compte de service le dernier jour ouvré de l'année. Aucun appel entrant ne venait de l'application, aucun échantillon de trafic ordinaire ne montrait d'exécution, mais il existait bien un appelant. Une méthode sérieuse doit résister à ce cas.

Il faut donc traiter le code présumé mort comme un problème de preuve. L'analyse statique cartographie ce qui peut être appelé. La couverture à l'exécution enregistre ce qui a été appelé dans des conditions définies. Catalogues de tâches, calendriers, configuration, valeurs de données, procédures d'exploitation et archives de trafic révèlent ce qu'aucune méthode ne voit seule. La suppression vient lorsque ces éléments concordent, qu'un responsable accepte la conclusion et qu'un test de parité ne montre aucune perte de comportement.

Le code mort a trois sens différents

Un rapport doit séparer les chemins impossibles, les chemins non observés et le comportement devenu obsolète. Chaque catégorie appelle une action différente. Un pourcentage unique masque l'incertitude dont les réviseurs ont besoin.

Le code statiquement inaccessible ne possède aucun chemin possible depuis les points d'entrée déclarés dans le modèle de l'analyseur. Une fonction privée non référencée dans un module fermé peut en faire partie, comme une branche derrière une condition que le système de types prouve fausse. C'est le signal technique le plus fort, mais il ne vaut que par la liste des entrées et le modèle de résolution.

Le code non observé n'a reçu aucun passage pendant une fenêtre et une charge nommées. Cela ne dit rien des autres dates, locataires, rôles, plages de données, pannes ou actions d'un opérateur. Le trafic web ordinaire manque souvent les lots, les reprises, les écrans d'administration, les outils de migration et la branche qui traite un solde négatif après annulation. Il est non observé, pas inaccessible.

Le code fonctionnellement obsolète s'exécute encore ou reste accessible, mais l'entreprise n'a plus besoin de son résultat. Une règle fiscale visant un pays abandonné peut l'être. Un calcul pour un produit arrêté peut rester nécessaire aux corrections des anciens comptes. Seul un responsable métier, avec les faits contractuels et de conservation, peut trancher. Un compilateur ne le peut pas.

Utilisez un état plutôt qu'un booléen :

  • inaccessible selon le modèle M
  • non observé dans la charge W pendant la fenêtre T
  • conservé pour l'événement rare E
  • obsolète selon la décision D
  • inconnu, enquête requise

Ce vocabulaire empêche une substitution courante. Des ingénieurs partent d'une absence de passages, parlent de code mort en réunion, puis approuvent une suppression comme si l'impossibilité avait été prouvée. Les mots ont changé, pas les preuves.

L'accessibilité statique prouve l'impossibilité, pas l'inutilité

L'analyse statique sait montrer que le contrôle ordinaire ne peut atteindre un symbole depuis des racines connues. Elle faiblit lorsqu'un ancien système transforme noms et données en contrôle. Le résultat doit toujours consigner ses racines, ses règles de résolution et ses angles morts.

Recensez tous les points d'entrée légitimes, pas seulement l'exécutable principal. Sur un mainframe, cela comprend programmes transactionnels, étapes JCL, modules appelés, sorties, déclencheurs de base et utilitaires lancés par l'exploitation. Sur AS/400, les programmes CL et descriptions de tâches peuvent appeler du RPG sans chemin interactif. Les postes de travail ajoutent entrées COM, macros de rapport et associations de fichiers. Les monolithes web ajoutent scripts planifiés, consommateurs de files, hooks de framework et routes issues de la configuration.

Construisez ensuite un graphe d'appels avec un degré de confiance sur chaque arête. Un appel direct résolu par le compilateur est plus fort qu'une chaîne qui ressemble à un nom de procédure. Gardez visibles les appels indirects non résolus. Pointeurs de fonction, réflexion, injection de dépendances, liaison tardive, SQL généré, procédures stockées et registres de plugins créent des arêtes qu'une recherche textuelle rate.

L'élimination par l'éditeur de liens ou le compilateur répond à une question plus étroite. Leurs manuels décrivent le retrait de sections ou d'instructions sans effet dans une construction donnée. C'est utile pour la taille du binaire, mais ne prouve rien pour d'autres options, modules chargés séparément, scripts ou entrées d'exploitation. Prendre un binaire optimisé pour le modèle complet de l'application confond deux problèmes.

Un petit relevé révisable vaut mieux qu'un graphe coloré de dix mille nœuds. Exportez une ligne par candidat avec symbole, emplacement, racines examinées, appels directs entrants, références indirectes possibles, variantes de construction et version de l'analyseur. Si une arête dépend d'une chaîne, d'une clé de configuration, d'une ligne de base ou d'un nom de tâche, conservez cette preuve.

Un résultat statique n'est fort qu'après quatre réponses : quelles racines ont été incluses ? Quels langages et artefacts générés ont été analysés ? Comment les appels indirects ont-ils été résolus ? Quels composants vivent hors du dépôt ? Toute réponse inconnue rend le résultat provisoire. C'est une description exacte du modèle.

La couverture prouve une exécution, pas la sécurité

La couverture à l'exécution peut prouver que du code a tourné dans une charge enregistrée. Zéro passage ne prouve pas son inutilité. La couverture atteste une présence, jamais une absence.

GNU gcov indique combien de fois les lignes et branches d'un programme instrumenté ont tourné. Coverage.py fait une distinction analogue pour Python et peut enregistrer les destinations des branches. Les deux manuels rattachent les résultats aux exécutions fournies. Cette réserve compte plus que le taux : une exécution ne couvre que ses entrées, son environnement, ses dates, ses identités et ses pannes.

La couverture de lignes perd aussi le détail du contrôle. Une ligne avec une condition composée peut passer sans qu'un opérande change. Un switch peut tourner tandis qu'un cas reste intact. La couverture de branches améliore la preuve, mais ne dit pas si le résultat ou l'effet secondaire était correct. Pour une suppression, collectez branches ou arêtes lorsque le langage le permet et comparez aussi les sorties.

Instrumentez toutes les surfaces trouvées statiquement. Le trafic interactif suffit rarement. Incluez exécutables de lot, workers, tâches planifiées, générateurs de rapports, routines de base, commandes de reprise et outils administratifs. Avant de fusionner les données, gardez version, entrée, nom de tâche, locataire ou entité, classe de rôle, date et source de charge. Une image fusionnée cache qu'une ligne n'a tourné que lors de la clôture annuelle.

La fenêtre d'observation doit suivre le calendrier métier, pas un nombre commode de jours. Couvrez opérations quotidiennes, hebdomadaires, mensuelles, fins de trimestre et d'année, renouvellements, expirations, changement d'heure, jour intercalaire et déclarations réellement traitées. Si l'attente est impossible, rejouez une charge ou recréez l'événement dans un environnement isolé. Trois jours ouvrés chargés ne représentent pas un exercice.

L'instrumentation peut modifier temps d'exécution, mémoire et pannes. Mesurez son coût près des courses, délais et limites de lots. Si elle est risquée, utilisez traces échantillonnées, compteurs aux frontières stables, audits de base ou journaux de tâches. Une preuve plus faible convient si elle est nommée et combinée à d'autres.

Le temps fait partie des entrées

Le code calendaire rare est actif, avec pour entrée une date, une échéance ou un état accumulé. Les équipes le ratent quand elles prennent le temps pour un décor.

Prenons une allocation de fin d'année. L'application enregistre des écritures ordinaires toute l'année. Le dernier jour ouvré, un ordonnanceur lance un lot après la clôture du grand livre. JCL passe un mode, une table désigne les comptes différés et le programme émet des écritures dans la période suivante. Aucune requête web ne l'appelle. Aucun développeur ne reconnaît son nom abrégé. Onze mois de couverture montrent zéro passage.

La réécriture supprime la routine et remplace le service comptable. Les tests ordinaires passent car leurs jeux de données portent sur mars et juin. À la clôture, les totaux restent équilibrés, donc les contrôles simples passent aussi. Le défaut apparaît quand les relevés divergent de la règle contractuelle. La règle perdue était une combinaison planifiée de date, contrôle de tâche, état de table et période de sortie.

Pour l'exposer, bâtissez un inventaire d'événements à côté du graphe. Interrogez finance, exploitation, support et conformité, puis vérifiez ordonnanceurs, JCL, cron, historique, procédures, tables de contrôle, calendriers, arrivées de fichiers et archives. Cherchez comparaisons de dates, numéros de période, jours fériés, modes spéciaux et constantes ressemblant à d'anciennes échéances.

Consignez la dernière exécution et la prochaine occasion prévue. Une routine vue à la dernière clôture s'explique. Une routine muette quatre ans peut couvrir un délai de correction de cinq ans. À l'inverse, une tâche nocturne peut entrer dans une branche seulement si une ligne de contrôle existe. La fréquence de l'appelant n'est pas celle de chaque règle.

Le remplacement de l'horloge mérite une interface de test. Faites passer le temps applicatif par une source contrôlable et figez de façon cohérente l'heure de la base ou de l'ordonnanceur. Si un composant lit la date simulée et l'autre l'hôte, le test fabrique des états rassurants mais impossibles.

Constituez un registre de preuves avant toute suppression

Gardez le code réglementé interne
Des modèles isolés fonctionnent dans votre périmètre sur du matériel dédié.

Un registre transforme un débat vague en conclusions reproductibles. Il doit accompagner la migration, être révisé comme le code et conserver les références brutes de chaque décision.

Une ligne par symbole ou fonction cohérente suffit. Notez identifiant, symbole, état statique, racines, arêtes non résolues, passages, fenêtre, charges, événement rare, appelants externes, responsable, décision et emplacements des preuves. Ne changez pas inconnu en zéro. Zéro signifie mesuré et absent, inconnu signifie non mesuré.

Une base de couverture peut produire une liste utile par une requête ordinaire. Adaptez les noms, mais gardez les dimensions :

SELECT s.symbol_id, s.qualified_name,
       COALESCE(SUM(c.hit_count), 0) AS hits,
       MIN(c.observed_at) AS first_seen,
       MAX(c.observed_at) AS last_seen,
       COUNT(DISTINCT c.workload_id) AS workloads
FROM symbols s
LEFT JOIN coverage_events c ON c.symbol_id = s.symbol_id
WHERE s.release_id = :release_id
GROUP BY s.symbol_id, s.qualified_name
ORDER BY hits, s.qualified_name;

La sortie doit rester simple : symbole, passages, première et dernière observation, nombre de charges. Reliez-la à une table indiquant trafic en ligne, fin de mois, fin d'année, reprise, administration ou rejeu. Un zéro issu du seul trafic en ligne ne condamne pas un symbole de lot.

Ajoutez cette table de décision :

Résultat statiqueRésultat d'exécutionPreuve métierAction
InaccessibleAucun passageAucune entrée externeIsoler puis tester la suppression
AccessibleAucun passageÉvénement rare connuConserver et tester
AccessiblePassagesResponsable : obsolèteConfirmer les appelants puis retirer
InconnuAucun passageInconnueEnquêter, ne pas supprimer

La première ligne demande toujours construction et test comportemental. Code généré, variantes et empaquetage peuvent rouvrir le graphe. La troisième demande aussi de la prudence : des appelants observés peuvent dépendre d'effets secondaires. Retirez ensemble chemin d'appel et obligations de données.

Exercez volontairement les chemins rares

Un chemin rare mérite une charge ciblée, pas l'espoir que la production finira par passer dessus. Dérivez les tests de l'inventaire et rendez les sorties attendues assez précises pour détecter la règle manquante.

Le trafic enregistré garde des combinaisons oubliées par les données synthétiques. Nettoyez ou tokenisez les champs sensibles, préservez l'ordre quand l'état en dépend, et capturez tables de contrôle, horloges et fichiers. Une requête sans état de base n'est souvent pas reproductible. Pour les lots, archivez entrées, paramètres, codes retour, fichiers, changements de base et messages opérateur.

Ajoutez des frontières synthétiques. Testez la veille, le jour et le lendemain de l'échéance, une entrée vide, le plus petit compte valide, une annulation, un compte créé tard et une relance après traitement partiel. Ces cas séparent sélection, calcul, persistance et reprise.

Comparez aux frontières observables : réponses HTTP, écritures, fichiers, messages, codes de sortie, arrondis, ordre et fenêtres de nouvelle tentative. Normalisez les identifiants volontairement variables, pas les valeurs métier. Pour un enregistrement de largeur fixe, comparez positions et remplissage, car un consommateur peut dépendre des octets.

Ne poursuivez pas un taux global. Une suite élevée peut manquer la branche de la période fiscale 13. Reliez chaque candidat à la charge qui doit l'atteindre ou prouvez pourquoi aucune ne le peut. L'unité utile est un symbole expliqué, pas une ligne colorée.

Si un chemin ne peut être exercé sans risque, placez un test de caractérisation dessous. Appelez le calcul avec des entrées capturées, lancez la procédure sur une base restaurée ou invoquez le module avec son vrai bloc de paramètres. Décrivez précisément ce qui reste non testé à la frontière.

Faites de la suppression une expérience contrôlée

Apportez la charge rare
Vos enregistrements testent les comportements absents des scénarios ordinaires.

Supprimez par petites unités réversibles et laissez le système réfuter votre conclusion. Le meilleur test retire le candidat, reconstruit chaque variante, rejoue les charges et compare tous les effets avec la référence.

Si les dépendances sont emmêlées, isolez d'abord. Placez un adaptateur unique, retirez les entrées en double et ajoutez compteurs ou journalisation à cette frontière. La structure change sans comportement et le point de mesure devient propre. Une absence d'appels sur tous les événements renforce la suppression suivante.

Conservez quatre éléments : ligne du registre, diff exact, sorties de référence et sorties après retrait. Lancez tests unitaires et intégrés, cibles alternatives, lots, outils administratifs et rejeu du trafic. Vérifiez mutations et fichiers, pas seulement le succès du processus. Un code retour réussi peut accompagner une écriture manquante.

La comparaison fantôme convient à un calcul sans effet. Exécutez ancien et nouveau sur la même entrée, bloquez les écritures d'un côté et comparez. Ne dupliquez pas paiement, notification, réservation ou mutation partagée sans réceptacle sûr. Les doubles effets créeraient l'incident recherché.

Le conseil populaire de supprimer tout ce qui reste à zéro pendant une durée fixe séduit par sa simplicité. Il est faux avec événements calendaires, contrats dormants, reprise manuelle ou dispatch par données. Fixez les exigences par classe : un contrôle en ligne demande des rôles et locataires représentatifs, une clôture demande une charge fidèle.

Gardez un retour arrière réel. Un revert ne suffit pas si la suppression change les données, retire une colonne, arrête un fichier ou modifie un contrat de message. Repoussez les changements destructifs de schéma et gardez la compatibilité jusqu'aux preuves des consommateurs.

Une réécriture préserve le comportement avant l'architecture

Retrouvez le lot silencieux
L'analyse globale suit les tâches planifiées et les appels entre langages.

Une réécriture doit classer et tester l'ancien comportement avant de choisir ce qui sera réimplémenté. Traduire toute routine accessible conserve la structure accidentelle. Supprimer toute routine suspecte perd des règles. Il faut d'abord la parité des obligations, puis une architecture décidée.

Construisez le harnais autour des observations de production et événements rares. Donnez aux deux systèmes les mêmes entrées ordonnées et le même état initial. Comparez réponses, état durable, fichiers, messages et pannes. Si l'interface change, comparez une représentation métier canonique plutôt que de reproduire les modules internes.

La différence entre parité du code et du comportement devient décisive. Un service Go n'a pas besoin des paragraphes COBOL ni des variables globales VB6. Il doit garder allocations, décisions d'éligibilité, arrondis et reprise jusqu'à l'approbation d'un changement. CodeHero utilise le trafic de production enregistré dans un harnais de parité tout en modernisant l'architecture, le bon niveau de comparaison ici.

Donnez au comportement retiré une assertion négative. Pour un rapport abandonné, testez qu'aucune tâche ne le planifie et qu'aucun fichier ne sort. Pour une ancienne règle, fournissez un ancien dossier éligible et vérifiez le nouveau traitement approuvé. L'absence devient testable à une frontière définie.

Ne perdez pas la provenance. Reliez chaque règle implémentée, modifiée ou omise au registre. Un réviseur doit retrouver charge, responsable et effet expliquant une branche cible, ou les preuves expliquant la disparition d'une routine source.

Fixez une règle de suppression applicable

Une politique ne fonctionne que si elle précise preuve, autorité et condition d'arrêt. Écrivez-la pour qu'un réviseur puisse refuser un changement sans débattre de l'âge apparent du code.

Une barrière défendable peut exiger :

  1. Aucun chemin entrant inexpliqué depuis l'inventaire complet, ou tous les appelants restants font partie du retrait.
  2. Les preuves d'exécution couvrent charges et événements calendaires pertinents, avec conservation des données brutes.
  3. Appelants externes, configuration, ordonnanceur, dispatch par données et procédures opérateur ont été vérifiés.
  4. Un responsable a approuvé l'obsolescence, ou la preuve technique établit l'impossibilité sans jugement métier.
  5. Le retrait passe constructions, tests ciblés, rejeu et comparaison des effets durables, avec retour arrière pour données et contrats.

La barrière doit accepter inconnu. Certaines routines attendent la restauration d'une archive ou la reconstruction d'une clôture. Les marquer inconnues désigne la preuve manquante. Les supprimer pour améliorer un taux ne fait rien avancer.

Mesurez les candidats étudiés, chemins prouvés inaccessibles, chemins rares testés, comportements retirés avec accord, inconnues restantes et suppressions ayant passé la parité. Ne récompensez pas les lignes retirées. Dix lignes de fin d'année peuvent porter plus d'obligations que dix mille lignes d'écran abandonné.

Prenez une routine dite morte et écrivez l'affirmation exacte. Si elle dit seulement que personne ne l'a vue tourner, vous avez mesuré la familiarité. Ajoutez racines, charges, événements, responsables et effets jusqu'à ce qu'un autre ingénieur reproduise la conclusion. Alors seulement la touche Suppr entre dans le processus.

FAQ

Quelle différence entre code mort et code inutilisé ?

Le code mort est assorti d'une preuve qu'aucune exécution requise ne l'atteint. Inutilisé signifie souvent qu'un outil ou une période n'a rien vu, malgré de possibles appelants externes ou événements rares.

L'analyse statique peut-elle prouver qu'un code est mort ?

Elle peut prouver l'inaccessibilité dans un modèle défini. Réflexion, appels générés, configuration, ordonnanceurs, déclencheurs et composants externes réduisent la portée de la preuve.

Zéro couverture autorise-t-il la suppression d'une fonction ?

Non. Cela signifie seulement qu'elle n'a pas tourné dans les charges et dates mesurées. Il faut aussi étudier accessibilité, événements rares, appelants externes et décision métier.

Combien de temps faut-il mesurer la couverture ?

Suivez le calendrier métier, pas une durée fixe. La période ou le rejeu doit inclure tâches, clôtures, renouvellements, expirations, reprises et traitement annuel pertinents.

Comment trouver le code exécuté seulement en fin d'année ?

Examinez historique de l'ordonnanceur, JCL, définitions de tâches, procédures, tables, archives et conditions de date. Recréez la clôture avec ses paramètres et son état, puis mesurez branches et sorties.

Le code éliminé par le compilateur est-il du code source mort ?

Pas automatiquement. Le compilateur ne prouve que ce qu'une construction peut omettre. D'autres options, modules, scripts et points d'entrée peuvent encore exiger la source.

Que contient un registre de preuves ?

Notez symbole, entrées, arêtes non résolues, charges, dates, événements rares, références externes, responsable, décision et preuves brutes. Séparez inconnu de zéro.

Comment tester la suppression de code ancien ?

Capturez la référence, retirez un petit candidat, reconstruisez les variantes et rejouez les charges ciblées. Comparez état durable, fichiers, messages, codes retour et pannes.

Un taux de couverture élevé suffit-il à une réécriture ?

Non. Un taux global peut manquer une branche fiscale ou de reprise. Reliez chaque comportement à une charge et comparez les effets ancien et nouveau.

Qui approuve le retrait d'une ancienne règle métier ?

Un responsable métier nommé doit confirmer l'obsolescence avec les preuves techniques. Les ingénieurs peuvent prouver l'impossibilité d'un chemin, pas déduire un changement de contrat du silence.