Table of Contents
Établir l'étape d'un examen réussi de la refactoration
Les systèmes logiciels dans les grands projets d'ingénierie accumulent naturellement la dette technique au fil du temps : logique dupliquée, classes monolithiques, dépendances enchevêtrées, et modèles de conception dépassés. Un examen refactoring est le processus formel, structuré d'identification et d'élimination de cette dette tout en préservant le comportement externe. Contrairement à un examen de code qui vérifie la justesse ou le style, un examen refactoring se concentre sur les améliorations structurelles.
Cependant, il est notoirement difficile de refactorer les examens dans les grandes bases de code. Le volume de code, l'interconnexion des modules et le risque d'introduire des régressions exigent une approche délibérée. Cet article fournit un plan détaillé pour mener à bien un examen de refactoring – de la préparation et de l'évaluation à l'exécution et au suivi – tiré des pratiques utilisées dans les environnements de génie à grande échelle.
Phase 1: Préparation stratégique
La mise en place d'un examen de refactoring sans planification entraîne un gaspillage d'efforts et des ruptures de constructions. La préparation garantit que l'examen reste ciblé, mesurable et sécuritaire.
Définir la portée et les objectifs
Les grands projets ne peuvent être recomposés d'un seul coup d'oeil.
- Les points d'accès de l'analyse statique: Des outils comme les fichiers de drapeau SonarQube, CodeClimate ou NDEpend avec une grande complexité, de longues méthodes ou de grandes classes.
- Les modules qui changent le plus souvent (déterminés par l'historique de la validation de Git) sont des candidats principaux car leur amélioration réduit la friction pour les fonctions continues.
- Gloupes de rendement:[ Les données de profilage peuvent indiquer les zones où des changements architecturaux entraîneraient des améliorations de vitesse.
Documenter les résultats spécifiques : par exemple, réduire de 20 % la complexité cyclomatique du service X, éliminer 90 % du code dupliqué dans le module de facturation ou remplacer une configuration codée en dur par un modèle d'injection de dépendance.
Rassembler l'équipe de droite
Un examen de refactoring exige des perspectives interfonctionnelles.
- Experts en matière de sujets[ qui comprennent la logique opérationnelle et les exigences du domaine.
- Les développeurs principaux qui connaissent profondément l'architecture et son histoire, peuvent prévoir des effets en aval.
- Un ingénieur d'automatisation des essais pour s'assurer que les pistes d'essai existantes sont robustes et que de nouveaux essais peuvent être créés.
Les groupes plus grands conduisent à une paralysie d'analyse. Assurez-vous que tous les membres reçoivent un document d'information et le code à l'étude au moins 48 heures à l'avance.
Rassembler les artéfacts
Recueillir tous les documents avant la réunion d'examen:
- Code source actuel (avec historique de la version).
- Unité actuelle, intégration et suites de test de bout en bout.
- Diagrammes d'architecture (mise à jour ou héritage – identifier les lacunes).
- Lignes directrices et guide de style utilisés dans le cadre du projet.
- Toute tentative de refactoration antérieure ou les points de douleur connus des trackers de problèmes.
Avoir ces derniers empêche l'examen de bloquer sur "où est ce fichier?" ou "est-on autorisé à renommer des API publiques?"
Phase 2 : Le processus d'examen – Identification et analyse des odeurs de code
Le centre de l'examen est la détection systématique des odeurs codées et l'évaluation de leur gravité. La présente section s'étend sur la liste de contrôle originale avec des exemples et des techniques concrètes.
Les odeurs de code commun dans les grands projets
Chaque odeur a une stratégie d'assainissement distincte. Le travail de l'examinateur est de prioriser ceux qui causent le plus de dommages.
Code dupliqué
Souvent la victoire la plus facile. Recherchez des blocs identiques ou quasi identiques à travers les méthodes, les classes ou les fichiers. Dans les grands projets, la duplication se produit souvent par le copy-collage à travers les microservices. Extraire la logique commune dans une bibliothèque ou une classe de base partagée. Attention : s'assure que le code extrait est vraiment dupliqué dans le comportement, pas de similitude. Une fausse extraction peut créer un couplage là où il n'y en avait pas.
Longues méthodes et classes de Dieu
Une méthode plus longue que 20-30 lignes fait souvent trop. La diviser en méthodes plus petites et à seule responsabilité. Une "classe de dieu" qui en sait trop sur le système (p. ex., un service Orchestrator de 5000 lignes) devrait être divisée en objets collaborateurs. Utilisez les modèles de Martin Fowler "classe d'extrait" ou "module d'extrait".
Chirurgie par fusil de chasse et changement divergent
Chirurgie des fusils de chasse : un seul changement nécessite de modifier le code dans de nombreux fichiers différents. Changement divergent : une classe change pour plusieurs raisons. Les deux indiquent une modularité médiocre.
Classes alternatives avec différentes interfaces
Deux classes qui font essentiellement la même chose mais exposent différents apis. Unifiez-les derrière une interface commune ou classe abstraite. Cela réduit la logique conditionnelle dans les appelants.
Grandes hiérarchies
La composition de l'héritage est favorable. La revue de refactoring devrait identifier les classes de base qui sont devenues gonflées avec des comportements par défaut non liés.
Évaluation d'impact : jusqu'où va le ripelle?
Avant de décider de refactorer, estimer le rayon de blason. Les techniques comprennent:
- Analyse graphique de la dépendance :[ Utiliser des outils comme ndepend, graphiz ou IDE pour visualiser les appelants et les personnes qui ont appelé.
- Analyse statique des appels :[ analyseurs de grep ou d'un langage spécifique (p. ex. pylint pour Python, reSharper pour C#) pour lister toutes les références.
- Couverture du test d'intégration:[ Si aucun test ne couvre un parcours d'utilisation, le risque de briser ce parcours est élevé.
- Drapeaux de caractéristiques:[ Si le code est derrière un drapeau inactif, l'impact sur le comportement de production est nul pendant le déploiement – mais le drapeau pourrait être activé plus tard.
Pour chaque candidat, attribuer un niveau de risque (faible, moyen, élevé) en fonction du nombre de personnes à charge externes et de la présence de tests de régression automatisés. Les changements à faible risque peuvent être effectués immédiatement; les changements à risque élevé nécessitent un plan en plusieurs étapes avec des drapeaux de caractéristiques et un déploiement progressif.
Phase 3 : Planification et exécution des stratégies de refactoration
Une fois les odeurs et les impacts catalogués, l'équipe conçoit une séquence de petits changements réversibles. La clé est d'éviter une réécriture « big bang » qui introduit une nouvelle architecture à partir de zéro – c'est la cause la plus courante de l'échec de refactoring.
Techniques à utiliser
Choisissez la technique qui correspond à l'odeur et au niveau de confort de l'équipe :
- Méthode d'extraction:[ Convertissez un bloc de code d'inline en méthode nommée. Améliore la lisibilité et la réutilisabilité.
- Renommer Variable/Méthod:[ Simple mais puissant. Utilisez les IDE avec un support de refactoring pour assurer la mise à jour de tous les appelants.
- Rupturer / Retirer: Déplacer les champs ou les méthodes entre la superclasse et la sous-classe pour réduire la duplication ou redistribuer les responsabilités.
- Remplacer Conditionnel avec Polymorphisme:[ Éliminer les chaînes de commutation/if-esel en utilisant l'expédition de sous-type. Il s'agit d'une transformation lourde; exiger une bonne couverture de test d'abord.
- Décomposer Conditionnel:[ Extraire des expressions booléennes complexes dans des appels de méthode descriptive.
- Introduire l'objet Parameter:[ Lorsqu'une méthode a plusieurs paramètres associés, les regrouper dans un nouveau type nommé.
Couverture des tests : le filet de sécurité
La refactoration sans tests est comme la chirurgie sans équipement de surveillance. Avant de changer une seule ligne, l'examen doit confirmer que:
- Il existe une série de tests unitaires pour le module, avec au moins 80 % de couverture de branche pour les pièces en cours de refactorisation.
- Les tests d'intégration couvrent les principaux contrats externes et effets secondaires (p. ex., écriture de base de données, réponses aux API).
- La suite d'essai peut être exécutée localement par l'ingénieur en moins de deux minutes (si elle est plus longue, planifier la vérification basée sur l'IC).
Si la couverture des tests est insuffisante, la première étape du projet de refactoring est d'écrire des tests pour caractériser le comportement actuel. Ce « test de caractérisation » implique l'exécution du code avec des entrées typiques et la capture des sorties, puis l'affirmation de ces sorties dans les tests. Une fois les tests réussis, vous avez une base de référence sûre pour la refactoration.
Changements progressifs : la seule voie de sécurité
Les grands projets d'ingénierie reposent souvent sur un déploiement continu. La refactoration doit être divisée en demandes de tirage (PR) suffisamment petites pour être examinées rapidement et réacheminées facilement.
- Touchez une seule responsabilité.
- Inclure les mises à jour ou les ajouts correspondants.
- Exécuter en CI sans échouer les essais existants.
- Être accompagné d'un examen du code (différent de l'examen de refactoring) axé sur l'exactitude.
Utilisez le "schiffle de figue" pour de grands changements : remplacez progressivement les anciens composants par de nouveaux pendant le routage du trafic. Ceci est particulièrement pertinent pour les architectures de microservice. Par exemple, extrait une méthode de ServiceA, puis introduit un nouveau ServiceB, et plus tard retirez l'ancien code.
Meilleures pratiques pour la réunion d'examen de la refactoration
L'examen lui-même devrait être un atelier de collaboration, et non une conférence. Attribuer suffisamment de temps (2-3 heures pour un seul module) et s'assurer qu'un facilitateur continue de discuter.
Utiliser une liste de contrôle structurée
Distribuer une liste de contrôle qui comprend :
- La refactoration proposée élimine-t-elle ou réduit-elle une ou plusieurs odeurs identifiées?
- Avons-nous vérifié qu'aucun comportement externe ne change?
- Les nouvelles abstractions sont-elles cohérentes et clairement nommées?
- Y a-t-il une amélioration mesurable (p. ex., lignes de réduction de code, réduction de complexité)?
- La suite d'essais est-elle toujours suffisante? Devrions-nous ajouter des tests pour les cas de bord révélés lors de la refacturation?
Encourager la collaboration
Rotation qui présente chaque section de code. Paire l'examen (deux critiques côte à côte) souvent attraper des problèmes subtils plus rapidement. Si l'équipe est à distance, utilisez un écran partagé avec l'édition en direct et un notetaker pour documenter les décisions.
Priorité par impact sur les entreprises
Toutes les odeurs de code ne sont pas égales.
- Coût de retard: Combien de temps cette odeur ajoute-t-elle à chaque changement futur? Une routine de validation hautement dupliquée que chaque nouveau paramètre d'API doit reproduire est une cible hautement prioritaire.
- Intérêts de dette technique:> L'effort supplémentaire nécessaire pour modifier ce code lorsqu'il change. Mesurez en heures par semaine ou par sprint.
- Risque d'inaction :[ L'odeur pourrait-elle éventuellement causer un incident de production ? Exemple : logique conditionnelle enchevêtrée qui a causé deux pannes.
Cette priorité permet à l'équipe de travailler sur ce qui compte le plus.
Essais d'automatisation et vérification après la remise en état
Le travail de l'examen n'est pas fait avant que le code ne passe les portes automatisées dans des environnements de production.
Ajouts de pipelines d'intégration continue
Après refactoring, mettre à jour l'IC pour faire respecter les nouvelles barrières de qualité :
- Seuils de complexité : échec de la construction si la complexité cyclomatique dépasse une certaine valeur dans toute méthode.
- Seuils de reproduction: échec si plus de 3 % des lignes sont dupliquées dans l'ensemble du projet.
- Couverture de test : couverture de ligne d'au moins 70 % sur un nouveau code ou un code modifié.
Ces règles empêchent la réintroduction des odeurs dans les futures demandes de tirage.
Surveiller les mesures de performance
Suivre les mesures pertinentes avant et après:
- Build time: la refactoring devrait réduire le temps de compilation ou de test.
- Utilisation de la mémoire et latence : pour la refactoration liée à la performance, utiliser la surveillance de la production (p. ex. Prométhée, Datadog) avec des tableaux de bord comparant deux semaines avant deux semaines après.
- Changer le taux d'échec : si la refacturation était risquée, surveiller la fréquence des incidents pour le mois suivant.
Pièges courants et comment les éviter
Même avec un processus solide, les examens refactoriels peuvent se tromper. Soyez conscient de ces pièges :
Crèche de portée
L'examen commence à cibler les petites odeurs mais s'étend rapidement à une réécriture complète de l'architecture. Mitigation: impose que tout changement de plus de 300 lignes ou touchant plus de 10 fichiers doit être approuvé par le responsable de l'examen de refactoring avant la mise en oeuvre.
Sur-ingénierie
Éviter de rendre le code "futur-proof" pour des scénarios qui ne peuvent jamais arriver. Mitigation: appliquer le principe "vous n'en aurez pas besoin" (YAGNI) : refactoriser seulement ce qui cause actuellement de la douleur ou va causer de la douleur dans les trois prochaines sprints.
Non mise à jour de la documentation
Après la refactoration, la documentation peut devenir obsolète. Mitigation: inclut les mises à jour de documentation dans le même PR, même si ce n'est qu'un commentaire dans le code ou un diagramme d'architecture mis à jour.
Négliger les exigences non fonctionnelles
Parfois, la refacturation améliore la lisibilité, mais aggrave la performance (par exemple, introduire de nombreux appels de méthode de petite taille qui ajoutent des frais généraux). Mitigation: exécute toujours un profileur sur le code refacturé et se compare à la base de référence.
Ressources externes pour un apprentissage plus approfondi
Pour maîtriser les examens de refactoring, les références établies à l'étude sont les suivantes :
- Refactoring: Amélioration de la conception du code existant – Martin Fowler – le catalogue définitif des motifs de refactoring avec mécanique.
- SonarQube Documentation[ – comment configurer la détection automatique des odeurs dans les pipelines CI.
- Comprendre le code legs – L'approche efficace – livre pratique pour travailler avec le code qui manque de tests.
Conclusion
Un examen de refactoring réussi dans un grand projet d'ingénierie est moins au sujet du code lui-même et plus au sujet du processus : préparation disciplinée, détection systématique des odeurs, analyse d'impact prudente, exécution progressive et application automatisée.En suivant l'approche structurée décrite ici – définir la portée, assembler la bonne équipe, utiliser des stratégies appropriées, et maintenir la force d'essai – les équipes peuvent éliminer la dette technique sans mettre en péril la stabilité de la production.