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 : Commencez par examiner la forme globale du graphe de dépendances. Une codebase saine présente des clusters distincts avec des connexions limitées entre eux, tandis qu'une codebase malade ressemble à une pelote de laine emmêlée. Faites attention au sens des dépendances également, elles devraient généralement aller dans un seul sens (par exemple, contrôleurs vers services vers repositories), et des flèches qui vont en sens inverse indiquent des violations architecturales. Enfin, vérifiez la distribution des connexions. Quelques nœuds hub sont normaux (utilitaires partagés, clients de base de données), mais trop de hubs suggèrent que les frontières entre modules sont faibles.
Signaux d'alerte : Méfiez-vous d'une absence totale de structure discernable où tout dépend de tout. Un seul fichier avec plus de 20 dépendances entrantes ou sortantes est un autre signal préoccupant, tout comme 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 : Vous recherchez les cycles directs (A vers B vers A), les cycles indirects (A vers B vers C vers A), et 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 devrait susciter une préoccupation immédiate. Les cycles impliquant plus de 3 modules sont quasiment impossibles à démêler de manière incrémentale. Plus de 5 chaînes de dépendances circulaires au total constitue un problème sérieux.
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 l'extraction de la logique partagée dans un nouveau module dont les deux côtés peuvent dépendre, l'utilisation de l'injection de dépendances pour inverser le sens de la dépendance, ou l'introduction d'un système d'événements ou d'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 : Concentrez-vous sur les fichiers avec plus de 10 imports depuis votre propre codebase (pas les packages externes), les fichiers de plus de 500 lignes, et 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 est clairement un module dieu. Un fichier « utils » de plus de 1 000 lignes a largement dépassé son objectif d'origine. 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 fait bien trop pour un seul module.
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 : Recherchez 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, et les blocs de code commentés.
Signaux d'alerte : Plus de 15% de code mort est un signal sérieux. Des répertoires entiers qui ne sont pas référencés et des fichiers de test pour des modules qui n'existent plus sont des indicateurs forts de dette technique accumulée.
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 : Commencez par le pourcentage de couverture global, puis approfondissez la couverture des chemins de logique métier critiques (paiements, authentification, transformations de données). Examinez la fraîcheur des fichiers de test, quand les tests ont-ils été mis à jour par rapport au code qu'ils testent ? Évaluez aussi 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 est préoccupant. Zéro couverture sur la logique de paiement ou d'authentification est dangereux. Des tests désactivés ou ignorés depuis plus de 3 mois suggèrent une négligence systémique. Des fichiers de test qui importent depuis des modules renommés ou déplacés indiquent que les tests sont cassés et que 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 : Recherchez les écarts de version majeure (par exemple, utiliser React 17 quand React 19 est sorti), les dépendances avec des vulnérabilités de sécurité connues (exécutez npm audit ou pnpm audit), les dépendances qui ne sont plus maintenues (dernière publication il y a plus de 2 ans), et 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 représente un risque sérieux. Une version du framework avec plus de 2 versions majeures de retard signifie que vous manquez des corrections et fonctionnalités critiques. Des dépendances dépréciées sans plan de migration et un package.json avec 50+ dépendances directes signalent tous deux que la gestion des dépendances a été négligée.
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 : Mesurez 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), et notez toute étape de build qui semble disproportionnellement lente.
Signaux d'alerte : Un temps de build propre supérieur à 5 minutes pour un projet de moins de 100K lignes de code est trop lent. Un temps de build incrémental supérieur à 10 secondes perturbe le flux du développeur. Un pipeline CI de plus de 15 minutes décourage les commits fréquents. Une seule étape de build qui prend plus de 50% du temps total est un goulot d'étranglement évident.
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.ts qui ré-exportent tout) car ils annulent le tree-shaking et ralentissent les builds. Vérifiez que les options incremental et tsBuildInfoFile de TypeScript sont activées. Envisagez de découper le projet en workspaces s'il a dépassé l'échelle monolithique, et remplacez les outils lents par des alternatives plus rapides (par exemple, 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 : Commencez par le README : explique-t-il comment installer, lancer et déployer le projet ? Vérifiez la documentation d'API pour voir si les endpoints sont documentés et si la documentation est auto-générée ou maintenue manuellement. Recherchez une documentation d'architecture qui décrit l'architecture de haut niveau. Passez en revue les commentaires en ligne pour voir si les algorithmes complexes ou les règles métier sont expliqués. Enfin, vérifiez que toutes les variables d'environnement requises sont documentées avec des descriptions.
Signaux d'alerte : Un README non mis à jour depuis plus d'un an est un problème pour tout nouveau contributeur. Une documentation d'API qui référence des endpoints qui n'existent plus est activement trompeuse. L'absence d'un fichier .env.example, des diagrammes d'architecture qui ne correspondent pas à la structure réelle du code, et des commentaires comme // TODO: corriger ça ou // hack temporaire datant de plus d'un an indiquent tous une dette de documentation.
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 : Vérifiez si la codebase utilise des patterns de gestion d'erreurs cohérents ou un mélange d'approches. Recherchez 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 ou UI de fallback pour les applications frontend, et si les erreurs sont journalisées avec suffisamment de contexte pour le debugging.
Signaux d'alerte : Les blocs catch vides comme catch (e) { } qui avalent les erreurs silencieusement comptent parmi les patterns les plus dangereux. Tout aussi problématiques sont les blocs catch (e) { console.log(e) } où les erreurs sont journalisées en console sans alerting. Des formats de réponse d'erreur incohérents entre les endpoints d'API, l'absence d'error boundary global dans le frontend, et 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 indiquent tous une discipline de gestion d'erreurs défaillante.
// 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 : Recherchez 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é), et 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 sont un problème critique, même dans des fichiers de config gitignorés, car ils ont pu être commités précédemment. Des requêtes SQL brutes avec interpolation de chaînes, dangerouslySetInnerHTML sans sanitization, des routes dans le dashboard qui ne vérifient pas l'authentification, et une configuration CORS manquante ou trop permissive (Access-Control-Allow-Origin: *) sont toutes des préoccupations de sécurité sérieuses.
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 : Surveillez 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), et 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 indiquent des problèmes de performance. Des requêtes de base de données sans clauses WHERE sur de grandes tables, un bundle frontend de plus de 1 Mo (gzippé) pour une application web standard, l'absence de pagination sur les endpoints de liste, et le chargement de jeux de données entiers en mémoire quand seuls des agrégats sont nécessaires sont autant de signes de négligence de la performance.
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 : Recherchez 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 exemple, le module « commandes » qui importe des fonctions internes du module « utilisateurs » au lieu de passer par une API publique), et 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 est une violation de frontière claire. Des handlers de routes API de plus de 50 lignes suggèrent que la logique métier devrait être dans les services. Plus de 10 chemins d'import qui traversent les frontières de domaines et aucune séparation claire entre ce qui est « l'API publique » d'un module et ce qui est interne indiquent tous deux une discipline architecturale faible.
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) : Les vulnérabilités de sécurité (#10) et la documentation manquante ou cassée pour l'installation (#8) doivent être traitées avant toute autre chose, car elles vous mettent en danger ou empêchent quiconque de contribuer.
Corriger avant tout refactoring : Vous avez besoin d'une vue d'ensemble du graphe de dépendances (#1) parce que vous devez voir le terrain avant de vous déplacer. Les dépendances circulaires (#2) saperont tout effort de refactoring si elles ne sont pas traitées. La couverture de tests sur le code que vous prévoyez de modifier (#5) est essentielle pour refactorer en confiance.
Corriger au fil du travail : Les modules dieu (#3) devraient être découpés au fur et à mesure que vous les rencontrez. Le code mort (#4) devrait être supprimé quand vous le trouvez. La gestion d'erreurs (#9) peut être standardisée au fur et à mesure que vous touchez chaque module, et les violations de frontières (#12) devraient être appliquées sur le nouveau code tout en corrigeant l'existant progressivement.
Corriger comme initiatives séparées : Les dépendances obsolètes (#6), le temps de build (#7), et les goulots d'étranglement de performance (#11) sont importants mais peuvent être abordés comme des efforts dédiés en dehors de votre travail de refactoring principal.
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.
Articles similaires
Microservices vs Monolithe : Comment réellement visualiser votre architecture
Monolithe ou microservices ? La vraie question est : pouvez-vous voir ce que vous avez réellement ? Apprenez à visualiser, comparer et décider en confiance.
Continuer la lectureComment détecter les dépendances circulaires dans votre projet TypeScript (et les corriger)
Découvrez 3 méthodes pratiques pour détecter les dépendances circulaires en TypeScript : madge CLI, ESLint import/no-cycle, et les checks PR automatiques avec ReposLens.
Continuer la lectureGestion des dépendances dans un monorepo : visualisez avant qu'il ne soit trop tard
Apprenez à gérer les dépendances internes d'un monorepo. Découvrez les pièges courants comme les dépendances circulaires et les god packages, et les outils pour les détecter.
Continuer la lecture