Checklist d'audit de code legacy : 12 points à vérifier avant de refactorer
On vient de vous confier une codebase legacy. Peut-être l'avez-vous héritée d'une équipe qui est partie. Peut-être que votre entreprise l'a acquise. Peut-être que c'est votre propre projet d'il y a trois ans, et que le vous du passé a pris quelques décisions discutables. Quelle que soit la raison, vous devez comprendre avec quoi vous travaillez avant de commencer à modifier quoi que ce soit.
La pire chose à faire avec du code legacy, c'est de commencer à refactorer immédiatement. Sans un audit approfondi, vous naviguez dans le noir. Vous corrigerez les symptômes au lieu des causes, casserez des choses dont vous ignoriez l'existence, et passerez des mois sur des changements qui auraient dû prendre des semaines.
Cette checklist vous offre une approche structurée pour auditer n'importe quelle codebase legacy. Pour chacun des 12 points, vous trouverez quoi chercher, ce qui constitue un signal d'alerte, et comment traiter le problème. Utilisez-la comme évaluation systématique avant d'écrire la moindre ligne de nouveau code.
1. Vue d'ensemble du graphe de dépendances
Quoi vérifier : Générez une carte visuelle de la façon dont les modules et fichiers dépendent les uns des autres. C'est votre radiographie architecturale — elle montre la structure réelle du code, indépendamment de ce que la documentation prétend.
Quoi chercher :
- La forme globale du graphe de dépendances. Une codebase saine présente des clusters distincts avec des connexions limitées entre eux. Une codebase malade ressemble à une pelote de laine emmêlée.
- Le sens des dépendances. Les dépendances devraient généralement aller dans un seul sens (par ex. contrôleurs → services → repositories). Des flèches qui vont en sens inverse indiquent des violations architecturales.
- La distribution des connexions. Quelques nœuds hub sont normaux (utilitaires partagés, clients de base de données). Trop de hubs suggèrent que les frontières entre modules sont faibles.
Signaux d'alerte :
- Aucune structure discernable — tout dépend de tout
- Un seul fichier avec plus de 20 dépendances entrantes ou sortantes
- Plusieurs fichiers important directement depuis la couche base de données à travers tous les modules
Comment corriger : On ne corrige pas un graphe de dépendances désordonné d'un seul coup. Commencez par identifier les frontières naturelles des clusters et documentez-les. Ensuite, dans les travaux futurs, faites respecter ces frontières en empêchant les nouveaux imports inter-frontières. Des outils comme ReposLens peuvent générer automatiquement le graphe de dépendances depuis votre dépôt et suivre son évolution dans le temps.
2. Nombre de dépendances circulaires
Quoi vérifier : Comptez le nombre de chaînes de dépendances circulaires dans la codebase. Une dépendance circulaire existe quand le module A dépend du module B, et le module B dépend du module A — directement ou via une chaîne de modules intermédiaires.
Quoi chercher :
- Les cycles directs (A → B → A)
- Les cycles indirects (A → B → C → A)
- La longueur de la plus longue chaîne de cycle
Signaux d'alerte :
- Toute dépendance circulaire dans les modules de logique métier critique
- Des cycles impliquant plus de 3 modules (ceux-ci sont quasiment impossibles à démêler de manière incrémentale)
- Plus de 5 chaînes de dépendances circulaires au total
Comment corriger : Pour chaque cycle, identifiez le maillon le plus faible — la dépendance la plus facile à casser sans restructuration majeure. Les techniques courantes incluent :
- Extraire la logique partagée dans un nouveau module dont les deux côtés peuvent dépendre
- Utiliser l'injection de dépendances pour inverser le sens de la dépendance
- Introduire un système d'événements ou un bus de messages pour la communication inter-modules
// Avant : Dépendance circulaire
// user-service.ts importe depuis email-service.ts
// email-service.ts importe depuis user-service.ts
// Après : Casser le cycle avec un événement
// user-service.ts émet l'événement 'user:created'
// email-service.ts écoute l'événement 'user:created'
// Aucune dépendance directe entre les deux
3. Modules dieu (fichiers avec trop d'imports)
Quoi vérifier : Identifiez les fichiers qui importent depuis un nombre anormalement élevé d'autres modules. Ce sont les « modules dieu » — ils en savent trop, en font trop, et sont impossibles à modifier sans effets de bord.
Quoi chercher :
- Les fichiers avec plus de 10 imports depuis votre propre codebase (pas les packages externes)
- Les fichiers de plus de 500 lignes
- Les fichiers dont le nom inclut « utils », « helpers », « common » ou « shared » qui ont grossi au-delà de leur objectif initial
Signaux d'alerte :
- Un seul fichier importé depuis 15+ modules
- Un fichier « utils » de plus de 1 000 lignes
- Un fichier de service qui gère les requêtes base de données, l'envoi d'emails, le traitement des paiements et le logging
Comment corriger : Les modules dieu doivent être découpés. L'approche dépend du type :
Pour les modules utilitaires dieu (utils.ts, helpers.ts) : Regroupez les fonctions par domaine et découpez en string-utils.ts, date-utils.ts, format-utils.ts, etc. Mettez à jour les imports dans toute la codebase. C'est mécanique et à faible risque.
Pour les modules service dieu (un service qui fait tout) : Identifiez les responsabilités distinctes et extrayez chacune dans son propre service. Utilisez le graphe de dépendances pour comprendre quelles parties de la codebase dépendent de quelles fonctions, et découpez en conséquence.
4. Pourcentage de code mort
Quoi vérifier : Estimez le pourcentage de code qui n'est plus utilisé — fonctions exportées que rien n'importe, composants qui ne sont jamais rendus, routes qui ne sont jamais appelées.
Quoi chercher :
- Les fichiers sans dépendances entrantes (rien ne les importe) qui ne sont pas des points d'entrée
- Les fonctions ou classes exportées qui ont zéro consommateur
- Les feature flags qui sont en permanence désactivés
- Les blocs de code commentés
Signaux d'alerte :
- Plus de 15% de code mort
- Des répertoires entiers qui ne sont pas référencés
- Des fichiers de test pour des modules qui n'existent plus
Comment corriger : La suppression de code mort est l'une des activités de refactoring les plus sûres. Commencez par les gains évidents :
- Supprimez les fichiers avec zéro dépendances entrantes (après avoir vérifié qu'ils ne sont pas des points d'entrée, des scripts ou des imports dynamiques)
- Supprimez les blocs de code commentés (ils vivent dans l'historique git si vous en avez besoin un jour)
- Supprimez les exports inutilisés identifiés par votre IDE ou vos outils de linting
- Supprimez le code sous feature flag lorsque le flag est désactivé en permanence depuis plus de 6 mois
5. Couverture de tests
Quoi vérifier : Mesurez la couverture de tests actuelle et, plus important encore, évaluez la qualité des tests existants.
Quoi chercher :
- Le pourcentage de couverture global
- La couverture des chemins de logique métier critiques (paiements, authentification, transformations de données)
- La fraîcheur des fichiers de test — quand les tests ont-ils été mis à jour par rapport au code qu'ils testent ?
- La qualité des tests — les tests assertent-ils réellement un comportement significatif, ou sont-ce des tests de snapshot que personne ne review ?
Signaux d'alerte :
- Moins de 30% de couverture globale
- Zéro couverture sur la logique de paiement ou d'authentification
- Des tests désactivés ou ignorés depuis plus de 3 mois
- Des fichiers de test qui importent depuis des modules renommés ou déplacés (indiquant que les tests sont cassés et personne ne l'a remarqué)
Comment corriger : Ne visez pas 100% de couverture sur une codebase legacy — c'est irréaliste et contre-productif. À la place :
- Écrivez des tests pour le code que vous allez modifier (la règle du « tester avant de toucher »)
- Priorisez la couverture sur les chemins critiques pour le business : tout ce qui touche à l'argent, l'authentification ou l'intégrité des données
- Fixez un plancher de couverture pour le nouveau code (par ex. 80%) et faites-le respecter dans la CI
- Supprimez les tests cassés ou sans signification — ils donnent une fausse confiance
6. Dépendances obsolètes
Quoi vérifier : Listez toutes les dépendances tierces et leur version actuelle par rapport à la dernière version disponible.
Quoi chercher :
- Les écarts de version majeure (par ex. utiliser React 17 quand React 19 est sorti)
- Les dépendances avec des vulnérabilités de sécurité connues (exécutez
npm auditoupnpm audit) - Les dépendances qui ne sont plus maintenues (dernière publication il y a plus de 2 ans)
- Les dépendances dupliquées (deux bibliothèques qui font la même chose)
Signaux d'alerte :
- Plus de 5 dépendances avec des vulnérabilités de sécurité connues
- Version du framework avec plus de 2 versions majeures de retard
- Des dépendances dépréciées sans plan de migration
- Un
package.jsonavec 50+ dépendances directes
Comment corriger : Créez un plan de mise à jour priorisé :
- Immédiat : Dépendances avec des vulnérabilités de sécurité critiques
- Court terme : Dépendances avec plus de 2 versions majeures de retard
- Moyen terme : Dépendances dépréciées nécessitant un remplacement
- En continu : Maintenez une cadence régulière de mises à jour de dépendances (mensuelle est un bon rythme)
7. Temps de build
Quoi vérifier : Mesurez le temps de build complet depuis un état propre, ainsi que les temps de build incrémentaux pendant le développement.
Quoi chercher :
- Le temps de build propre (à partir de zéro)
- Le temps de build incrémental (après le changement d'un seul fichier)
- Le temps de build CI (pipeline complet incluant les tests)
- Toute étape de build qui semble disproportionnellement lente
Signaux d'alerte :
- Temps de build propre supérieur à 5 minutes pour un projet de moins de 100K lignes de code
- Temps de build incrémental supérieur à 10 secondes
- Pipeline CI de plus de 15 minutes
- Une seule étape de build qui prend plus de 50% du temps total
Comment corriger :
- Profilez le build pour identifier les étapes les plus lentes (la plupart des bundlers ont des options de profiling)
- Vérifiez les barrel files inutiles (
index.tsqui ré-exportent tout) — ils annulent le tree-shaking et ralentissent les builds - Vérifiez que les options
incrementalettsBuildInfoFilede TypeScript sont activées - Envisagez de découper le projet en workspaces s'il a dépassé l'échelle monolithique
- Remplacez les outils lents par des alternatives plus rapides (par ex. Biome au lieu d'ESLint + Prettier)
8. État de la documentation
Quoi vérifier : Évaluez la complétude et l'exactitude de la documentation existante.
Quoi chercher :
- README : explique-t-il comment installer, lancer et déployer le projet ?
- Documentation d'API : les endpoints sont-ils documentés ? La documentation est-elle auto-générée ou maintenue manuellement ?
- Documentation d'architecture : y a-t-il une description de l'architecture de haut niveau ?
- Commentaires en ligne : les algorithmes complexes ou les règles métier sont-ils expliqués ?
- Variables d'environnement : toutes les env vars requises sont-elles documentées avec des descriptions ?
Signaux d'alerte :
- README non mis à jour depuis plus d'un an
- Documentation d'API qui référence des endpoints qui n'existent plus
- Pas de fichier
.env.example - Diagrammes d'architecture qui ne correspondent pas à la structure réelle du code
- Commentaires comme
// TODO: corriger çaou// hack temporairedatant de plus d'un an
Comment corriger : Triage de la documentation — corrigez ce qui compte le plus :
- Mettez à jour le README avec des instructions d'installation correctes (cela bloque chaque nouveau contributeur)
- Créez ou mettez à jour le
.env.exampleavec toutes les variables requises - Générez la documentation d'API depuis le code source (OpenAPI/Swagger) plutôt que de la maintenir manuellement
- Supprimez les diagrammes d'architecture obsolètes (une doc erronée est pire que pas de doc)
- Traitez les commentaires TODO : soit faites la tâche, soit supprimez le commentaire
9. Patterns de gestion d'erreurs
Quoi vérifier : Examinez comment la codebase gère les erreurs, aussi bien les erreurs attendues (échecs de validation, not-found) que les erreurs inattendues (pannes réseau, crashes runtime).
Quoi chercher :
- Des patterns de gestion d'erreurs cohérents vs. un mélange d'approches
- Des blocs catch génériques qui avalent les erreurs
- Des messages d'erreur qui exposent des détails internes aux utilisateurs
- Des error boundaries/UI de fallback pour les applications frontend
- La journalisation des erreurs avec suffisamment de contexte pour le debugging
Signaux d'alerte :
catch (e) { }— des blocs catch vides qui avalent les erreurs silencieusementcatch (e) { console.log(e) }— erreurs journalisées en console sans alerting- Des formats de réponse d'erreur incohérents entre les endpoints d'API
- Pas d'error boundary global dans le frontend
- Des messages d'erreur contenant des stack traces, des chemins de fichiers ou des requêtes de base de données visibles par les utilisateurs
// Signal d'alerte : Erreur avalée silencieusement
try {
await processPayment(order);
} catch (e) {
// TODO: gérer ça
}
// Signal d'alerte : Réponses d'erreur incohérentes
// Endpoint A retourne : { error: "Not found" }
// Endpoint B retourne : { message: "Resource not found", code: 404 }
// Endpoint C retourne : { errors: [{ msg: "not found" }] }
Comment corriger :
- Définissez un format d'erreur standard pour toute l'application
- Remplacez les blocs catch vides par une gestion d'erreur appropriée (journaliser, réessayer ou propager)
- Ajoutez un error boundary global (React ErrorBoundary, middleware d'erreur Express)
- Assurez-vous que les erreurs sont signalées à un service de monitoring (Sentry ou équivalent)
- Nettoyez les messages d'erreur envoyés aux clients — n'exposez jamais de détails internes
10. Vulnérabilités de sécurité
Quoi vérifier : Auditez la codebase pour les problèmes de sécurité courants.
Quoi chercher :
- Des secrets en dur (clés API, identifiants de base de données, tokens)
- Des vulnérabilités d'injection SQL (concaténation de chaînes dans les requêtes)
- Des vecteurs de cross-site scripting (XSS) (entrée utilisateur non nettoyée rendue en HTML)
- L'absence d'authentification sur les routes protégées
- L'absence de vérifications d'autorisation (authentifié mais pas autorisé)
- Des données sensibles dans les logs ou les messages d'erreur
Signaux d'alerte :
- Des clés API ou mots de passe dans le code source (même dans des fichiers de config gitignorés, ils ont pu être commités précédemment)
- Des requêtes SQL brutes avec interpolation de chaînes
dangerouslySetInnerHTMLsans sanitization- Des routes dans le dashboard qui ne vérifient pas l'authentification
- Configuration CORS manquante ou trop permissive (
Access-Control-Allow-Origin: *)
Comment corriger :
- Lancez un scanner de secrets (
gitleaks,trufflehog) sur l'historique git complet - Effectuez la rotation de tout identifiant exposé immédiatement
- Remplacez les SQL concaténés par des requêtes paramétrées ou un ORM
- Ajoutez un middleware d'authentification sur toutes les routes protégées
- Implémentez des politiques CORS appropriées
- Mettez en place les headers de sécurité (CSP, X-Frame-Options, X-Content-Type-Options)
11. Goulots d'étranglement de performance
Quoi vérifier : Identifiez les zones où l'application performe mal sous charge ou avec de grands volumes de données.
Quoi chercher :
- Les problèmes de requêtes N+1 (récupérer une liste, puis faire une requête pour chaque élément individuellement)
- Les index de base de données manquants sur les colonnes fréquemment interrogées
- Les images ou assets non optimisés (grandes images servies sans compression ni redimensionnement)
- Les fuites mémoire (event listeners non supprimés, subscriptions non annulées)
- Les opérations bloquantes sur le thread principal (calculs lourds dans le code UI)
Signaux d'alerte :
- Des endpoints API qui prennent plus d'une seconde pour des opérations courantes
- Des requêtes de base de données sans clauses
WHEREsur de grandes tables - Un bundle frontend de plus de 1 Mo (gzippé) pour une application web standard
- Pas de pagination sur les endpoints de liste
- Le chargement de jeux de données entiers en mémoire quand seuls des agrégats sont nécessaires
Comment corriger :
- Ajoutez des index de base de données sur les colonnes utilisées dans les clauses
WHERE,JOINetORDER BY - Corrigez les requêtes N+1 en utilisant le chargement eager ou les requêtes par lot
- Implémentez la pagination sur tous les endpoints de liste et les UI de liste
- Ajoutez l'optimisation d'images (compression, tailles responsives, chargement lazy)
- Profilez le bundle frontend et appliquez le code-splitting sur les grosses dépendances
12. Violations des frontières architecturales
Quoi vérifier : Vérifiez que la codebase respecte ses propres frontières architecturales — la séparation prévue entre couches, modules et domaines.
Quoi chercher :
- Des composants UI qui importent directement depuis la couche base de données
- De la logique métier embarquée dans les composants UI ou les handlers de routes API
- Des imports inter-domaines (par ex. le module « commandes » qui importe des fonctions internes du module « utilisateurs » au lieu de passer par une API publique)
- Des variables de configuration et d'environnement accédées depuis des emplacements arbitraires au lieu d'un module de config centralisé
Signaux d'alerte :
- Un composant React qui contient une requête de base de données
- Des handlers de routes API de plus de 50 lignes (la logique métier devrait être dans les services)
- Plus de 10 chemins d'import qui traversent les frontières de domaines
- Aucune séparation claire entre ce qui est « l'API publique » d'un module et ce qui est interne
Comment corriger :
- Documentez les frontières architecturales prévues (quelles couches existent, ce que chaque couche est autorisée à importer)
- Déplacez la logique métier depuis les composants UI et les handlers de routes vers des modules de service
- Créez des API publiques claires pour chaque module de domaine (un
index.tsqui n'exporte que ce que les autres modules devraient utiliser) - Faites respecter les frontières avec des règles de linting (eslint
import/no-restricted-pathsou équivalent) - Utilisez des outils d'analyse d'architecture pour suivre les violations de frontières dans le temps — ReposLens peut visualiser exactement où les imports inter-frontières se produisent et vous alerter quand de nouveaux sont introduits
Tableau récapitulatif
| # | Vérification | Vert | Orange | Rouge | |---|-------------|------|--------|-------| | 1 | Graphe de dépendances | Clusters distincts | Un peu d'enchevêtrement | Tout dépend de tout | | 2 | Dépendances circulaires | 0 | 1-3 | 4+ | | 3 | Modules dieu | Aucun avec plus de 10 imports | 1-2 fichiers | 3+ fichiers avec 15+ imports | | 4 | Code mort | < 5% | 5-15% | > 15% | | 5 | Couverture de tests | > 60% sur les chemins critiques | 30-60% | < 30% | | 6 | Dépendances obsolètes | Toutes à 1 version majeure près | 2-3 majeures de retard | Vulnérabilités de sécurité | | 7 | Temps de build | < 2 min propre | 2-5 min | > 5 min | | 8 | Documentation | README + env à jour | Docs partielles | Pas de docs ou docs fausses | | 9 | Gestion d'erreurs | Patterns cohérents | Approches mixtes | Erreurs silencieuses | | 10 | Sécurité | Aucun problème connu | Problèmes mineurs | Secrets en dur ou injection SQL | | 11 | Performance | Réponses sub-seconde | Quelques endpoints lents | Requêtes N+1, pas de pagination | | 12 | Violations de frontières | Séparation propre | Quelques fuites | Aucune frontière appliquée |
Comment prioriser
Les 12 points n'ont pas tous le même poids. Voici une priorisation suggérée :
Corriger immédiatement (bloque tout autre travail) :
- Vulnérabilités de sécurité (#10)
- Documentation manquante ou cassée pour l'installation (#8)
Corriger avant tout refactoring :
- Vue d'ensemble du graphe de dépendances (#1) — vous devez voir le terrain avant de vous déplacer
- Dépendances circulaires (#2) — elles saperont tout effort de refactoring
- Couverture de tests sur le code que vous prévoyez de modifier (#5)
Corriger au fil du travail :
- Modules dieu (#3) — découpez-les au fur et à mesure que vous les rencontrez
- Code mort (#4) — supprimez-le quand vous le trouvez
- Gestion d'erreurs (#9) — standardisez au fur et à mesure que vous touchez chaque module
- Violations de frontières (#12) — faites-les respecter sur le nouveau code, corrigez l'existant progressivement
Corriger comme initiatives séparées :
- Dépendances obsolètes (#6)
- Temps de build (#7)
- Goulots d'étranglement de performance (#11)
Conclusion
Auditer une codebase legacy n'est pas un travail glamour, mais c'est la chose la plus précieuse que vous puissiez faire avant de refactorer. Chaque heure passée sur cette checklist économise des jours d'efforts gaspillés plus tard.
L'objectif n'est pas de tout corriger d'un coup. L'objectif est de comprendre avec quoi vous travaillez, d'identifier les zones à plus haut risque, et de créer un plan qui traite les problèmes les plus impactants en premier. Imprimez cette checklist, notez votre codebase sur chaque point, et utilisez les résultats pour construire une feuille de route de refactoring que votre équipe peut exécuter avec confiance.