Le code hérité désigne un code logiciel qui remplit toujours sa fonction, mais qui a été développé à l’aide de technologies désormais obsolètes. Il englobe le code hérité d’une autre équipe ou d’une ancienne version du logiciel, et le code source qui n’est plus activement pris en charge ou maintenu. Il englobe également le code écrit à l’aide de matériel ou de systèmes d’exploitation obsolètes, de compilateurs ou d’interfaces de programmation des applications (API) abandonnés, ou de langages de programmation ou d’environnements de développement logiciel dépassés. Par conséquent, le code hérité n’est plus conforme aux nouvelles normes de codage, aux principes de conception logicielle actuels ou aux dernières architectures informatiques.
Dans son ouvrage paru en 2004, Working Effectively with Legacy Code, Michael Feathers a proposé une autre description, « le code sans test ».1 Cette définition du code hérité signifie que les programmeurs n’ont aucun moyen de vérifier que le code fonctionne, et qu’il fonctionne comme prévu. De nombreux systèmes hérités ne disposent pas non plus de documentation adéquate, essentielle pour comprendre leur comportement. Leur extension ou amélioration s’avère donc très fastidieuse pour les développeurs.
Le code hérité contribue à la dette technique, qui doit être « remboursée » au fil du temps grâce à une maintenance continue du code. Voici quelques défis courants que les entreprises peuvent rencontrer lors de la maintenance de code hérité :
• Adaptabilité
• Coût
• Performances
• Évolutivité
• Sécurité et conformité
En raison de sa nature obsolète, le code hérité peut être incompatible ou difficile à intégrer à des systèmes plus modernes. Ce manque d’adaptabilité peut entraver l’innovation, ralentir la croissance des entreprises et leur faire perdre leur avantage concurrentiel.
Les systèmes hérités peuvent être coûteux à entretenir. Ces coûts d’exploitation et de maintenance peuvent s’accumuler, les frais de support tiers augmentant pour les anciennes versions de logiciels et de matériel. En outre, il peut être difficile et onéreux de trouver des développeurs compétents en pratiques informatiques ou langages de programmation obsolètes.
Les architectures monolithiques et maladroites entraînent une latence élevée, des temps de réponse lents et des temps d’arrêt fréquents. Ces performances lentes peuvent avoir un impact négatif sur l’expérience utilisateur, ce qui réduit la satisfaction client. Cela peut également nuire à la productivité et à l’efficacité des membres de l’équipe qui travaillent avec ces systèmes et les entretiennent.
Les systèmes obsolètes supportent difficilement l’augmentation du nombre d’utilisateurs. Ils ont du mal à répondre aux pics de demande et à augmenter ou réduire la capacité en fonction des besoins. Leurs composants étroitement couplés compliquent la mise à niveau des fonctionnalités existantes ou l’ajout de nouvelles fonctionnalités.
Un code hérité peut ne pas être activement mis à jour avec des correctifs de sécurité et ne pas suivre les dernières normes de sécurité, ce qui le rend vulnérable aux cyberattaques et aux violations. Les systèmes hérités peuvent également ne pas être conformes aux réglementations en vigueur.
La modernisation des applications héritées nécessite une planification minutieuse. Voici une méthodologie en 5 étapes pour vous aider à rationaliser le processus :
• Comprendre la base de code
• Diviser pour mieux régner
• Élaborer des tests de caractérisation
• Refactoriser, migrer ou réécrire
• Tester et documenter
La première étape consiste à comprendre la base de code, et c’est généralement la partie la plus difficile. Commencez par passer en revue l’ensemble de la documentation disponible, qu’il s’agisse de documents d’exigences, de commentaires de code intégrés ou de l’historique de contrôle de versions, comme les journaux de validation ou les journaux de modifications.
Lorsque la documentation est insuffisante, essayez d’utiliser des outils d’analyse de code statique qui examinent automatiquement le code sans l’exécuter. De plus, les outils de visualisation de code peuvent créer une représentation graphique de la structure du code source, aidant à cartographier les dépendances et les interactions entre les éléments.
Une fois qu’elles ont acquis une compréhension suffisante du code hérité, les équipes de développement logiciel peuvent commencer la procédure. Ces bases de code tentaculaires peuvent être difficiles à gérer. Divisez-les en modules plus petits et plus faciles à gérer et travaillez sur un module à la fois.
Les tests sont généralement écrits pour valider l’exactitude du code et son comportement attendu. Cependant, des tests de caractérisation sont créés pour comprendre ce que fait le code et comment il fonctionne. Ils sont utiles pour mieux comprendre le code hérité.2
Les entreprises disposent généralement de trois options lorsqu’il s’agit de moderniser le code hérité : refactoriser, migrer ou réécrire. Elles peuvent également combiner n’importe laquelle de ces approches. Le choix de la voie à suivre nécessite d’impliquer à la fois l’équipe d’ingénierie logicielle et l’équipe de direction.
Le refactoring de code modifie la structure interne du code source sans modifier son comportement externe ni affecter ses fonctionnalités. Ces petits ajustements sont moins susceptibles d’introduire des bugs et peuvent produire un code clair et propre plus facile à gérer.
Pour le code hérité, les équipes peuvent commencer par des modifications mineures pour chaque module, notamment en renommant les variables, en supprimant les méthodes en double ou inutilisées et en standardisant le formatage. Elles peuvent ensuite procéder à une restructuration plus logique, par exemple en décomposant les grandes méthodes en méthodes plus petites, en simplifiant les conditionnalités complexes et en déplaçant les fonctionnalités entre les fonctions afin de réduire les dépendances et améliorer la cohésion.
La migration est un autre moyen de moderniser le code hérité. Cela consiste à migrer tout ou partie du code vers des plateformes ou des piles technologiques plus récentes, comme le passage d’une architecture monolithique à des microservices ou la transition d’un système sur site au cloud. Il est important de vérifier la compatibilité avec la plateforme ou la pile technologique, ainsi que le support proposé par les fournisseurs pendant la migration.
La réécriture du code hérité est souvent le dernier recours, car elle implique la création d’un code entièrement nouveau pour remplacer l’ancien. Il s’agit d’un nouveau projet en soi, une entreprise de grande ampleur susceptible de mobiliser une équipe de développement distincte.
La migration et la réécriture peuvent être une tâche ardue pour les grands codes bases hérités, et les équipes peuvent dans ce cas envisager la stratégie du « figuier étrangleur ».3 Un figuier étrangleur pousse à la surface d’un arbre, ses racines descendent vers le sol et enveloppent lentement son arbre hôte dans un treillis resserrant qui finit par le faire dépérir.
En ce qui concerne les systèmes hérités, les équipes peuvent migrer ou réécrire de manière incrémentielle de petits fragments de code jusqu’à ce que l’ensemble du code soit passé à un framework moderne ou développé dans un langage de programmation actuel. Cependant, les équipes doivent créer une architecture transitionnelle pour que le code existant et le nouveau code coexistent. Cette architecture transitionnelle sera ensuite mise hors service une fois la migration ou la réécriture terminée.3
Il est essentiel de tester minutieusement le code remanié, migré ou réécrit afin de s’assurer qu’aucun bug n’apparaît. Les développeurs peuvent écrire leurs propres tests d’intégration et unitaires, mais il est également essentiel d’impliquer des équipes d’assurance qualité qui peuvent exécuter des tests fonctionnels, de régression et de bout en bout pour vérifier que les fonctionnalités et les comportements sont intacts.
La documentation est un autre élément critique du workflow de modernisation. Documentez les modifications du code source, que ce soit en annotant le code par le biais de commentaires en ligne, en créant des journaux détaillés des modifications ou en rédigeant des documents complets sur l’architecture et la conception et d’autres documentations.
Plusieurs outils permettent d’accélérer et d’automatiser le processus de modernisation du code hérité. Voici les plus courants :
• Analyseurs statiques de code
• Applications de visualisation de code
• Cadres d’automatisation des tests
• Plateformes et outils de migration
• Générateurs de documents
Les analyseurs statiques peuvent aider à déboguer le code hérité pour détecter les défauts de programmation, les problèmes de qualité et même les vulnérabilités de sécurité. De nombreux outils d’analyse de code statique prennent en charge les langages de programmation hérités tels que C, COBOL, PL/I et RPG. Parmi ces outils, citons CodeSonar, Klocwork, le PMD open source et SonarQube.
Les visualiseurs de code fournissent une représentation graphique du code source afin d’obtenir une meilleure image de son fonctionnement, en particulier pour les bases de code complexes ou de grande taille. Ces représentations graphiques prennent différents formats tels que les cartes de code, les organigrammes et les diagrammes de langage de modélisation unifié (UML). CodeScene, CodeSee et Understand, entre autres, sont des exemples d’applications de visualisation de code.
Ces cadres d’exigences créent et exécutent des tests automatisés et produisent des rapports sur ces tests. Parmi les cadres d’automatisation des tests les plus utilisés, citons Cypress et Selenium pour les applications Web, et Appium pour les applications mobiles.
Ces plateformes et outils permettent de simplifier et d’automatiser les workflows de migration des systèmes hérités. AWS Application Migration Service, Azure Migrate, les outils de migration Google cloud, IBM Cloud Transformation Advisor et Red Hat Migration Toolkit for Applications sont parmi les principales plateformes de migration utilisées.
Ces outils génèrent automatiquement de la documentation à partir du code source et d’autres fichiers d’entrée. Doxygen, Sphinx et Swimm sont des exemples d’outils de génération de documents.
L’intelligence artificielle (IA) peut contribuer à la modernisation du code hérité. Les applications d’IA générative s’appuient sur de grands modèles de langage (LLM) capables d’analyser des bases de code héritées complexes ou volumineuses.
L’IA générative peut être employée pour faciliter ces tâches de modernisation du code hérité :
• Explication du code
• Refactoring de code
• Transformation du code
• Génération et documentation des tests
L’IA générative peut comprendre le contexte et la sémantique qui sous-tendent les codes bases hérités. Elle est ainsi capable de mettre en évidence la logique et la fonction sous-jacentes, ce qui permet d’expliquer le code d’une manière que les programmeurs peuvent comprendre.
Les outils alimentés par l’IA peuvent fournir des recommandations de refactoring en temps réel. Par exemple, IBM watsonx Code Assistant exploite les modèles IBM Granite pour identifier les bugs et les optimisations. Il suggère ensuite des corrections ciblées qui s’alignent sur les conventions de codage établies par l’équipe, ce qui permet de simplifier et d’accélérer le refactoring du code.
Les systèmes d’IA peuvent suggérer des moyens d’implémenter le code source d’un langage de programmation hérité vers un langage plus moderne. Par exemple, IBM watsonx Code Assistant pour Z combine l’automatisation et l’IA générative pour aider les développeurs à moderniser les applications mainframe. Ces capacités d’IA générative incluent l’explication du code pour COBOL, JCL et PL/I et la conversion du code COBOL en code Java.
Comme les cadres d’automatisation des tests, les assistants de codage IA peuvent aussi générer des tests automatiquement. Ils peuvent également créer des commentaires en ligne pour documenter ce que font certains fragments ou extraits de code.
Comme pour toute application alimentée par l’IA, les programmeurs doivent toujours faire preuve de prudence lorsqu’ils utilisent l’IA pour moderniser le code hérité. Ils doivent passer en revue les sorties pour en vérifier l’exactitude et tester les modifications ou correctifs suggérés.
Instana simplifie votre parcours de migration vers le cloud en offrant une surveillance complète et des informations exploitables.
Tirez parti de l’IA générative pour une modernisation accélérée et simplifiée des applications mainframe.
Optimisez les applications existantes grâce à des services et des stratégies de modernisation basées sur le cloud hybride et l’IA.
1 #195 - Working Effectively with Legacy Code and AI Coding Assistant - Michael Feathers, Tech Lead Journal, 14 octobre 2024
2 Characterization Testing, Michael Feathers, 8 August 2016
3 Strangler Fig, Martin Fowler, 22 August 2024