Publié le 06/07/2023 Par Didier VIDAL

Lorsque le temps est venu pour moi de changer de mission, des consultants à qui mon poste a été proposé me demandent en quoi consiste la mission. J’ai alors toujours été étonné que revienne souvent une question en particulier : quelle est la stack technique ? Or si je cite le nom de frameworks de plus de cinq ans d’âge, je sens au travers de mon téléphone pâlir mon interlocuteur, effrayé par l’horrible spectre du legacy qui ne peut que se profiler derrière un tel environnement. C’est pourquoi je vais vous expliquer dans cet article en quoi une mission autour d’une application legacy ancienne, mais largement déployée et utilisée peut se révéler pleine de défis passionnants et enrichissants. 

J’ai un profil plutôt technique. Si je fais un job dans lequel je ne mets pas la main sur un compilateur, l’ennui risque de me gagner rapidement. Je trouve qu’il existe du code beau, avec de belles API basées sur des concepts solides, et du code moche, fragile et bancal comme une construction de Numérobis dans Astérix et Cléopâtre.

J’adore les moments de créativité lorsqu’on conçoit une nouvelle fonctionnalité, et cette impression de jouer aux LEGO®. Et avec tout cela, je trouve que l’on peut avoir des missions très enrichissantes, favorisant des moments de créativité dans un environnement legacy. Et je dirai même plus, on peut trouver des choses bien difficiles à avoir dans un projet tout neuf, tout beau utilisant les dernières friandises de la communauté open source.

 Qu’est-ce que le code legacy ou legacy code ? 

Si l’on demande à ChatGPT de nous donner une synthèse des opinions du web sur le code legacy, il répondra quelque chose de ce style :

« Le code legacy, également connu sous le nom de « code hérité », se réfère à l’ensemble des systèmes logiciels et du code source qui ont été développés dans le passé et qui sont encore utilisés aujourd’hui, malgré le fait qu’ils ne répondent pas aux normes et aux pratiques de développement modernes. Ce code est souvent obsolète et peut poser de nombreux défis pour les développeurs. Il peut être difficile à maintenir, à améliorer et d’intégrer de nouvelles fonctionnalités. La gestion du code legacy peut entraîner des coûts de maintenance élevés et ralentir le développement de l’entreprise. Il est donc important de mettre en place des stratégies de modernisation et de migration pour assurer la pérennité du système et améliorer l’efficacité des opérations. »

À l’encontre de cette vision conformiste, notre consultant nous explique les défis passionnants que l’on peut trouver dans une mission pour faire évoluer une application legacy et accompagner les métiers qui l’utilisent dans leurs transformations.

Qu’est-ce qu’une application legacy ? (un projet IT qui a réussi)

Au départ, c’etait un projet lancé avec plein de bonnes idées et d’ambitions, et surtout avec l’envie de faire mieux qu’avant. C’était aussi un projet reçu dans le club très select des projets IT qui n’échouent pas. Il a donc été déployé et utilisé, et réunit autour de lui tout un écosystème :

  • Des métiers dépendants de cette application ;
  • Une équipe support, et des développeurs et des MOA pour le faire évoluer ;
  • Des personnes pour gérer un système de build ;
  • Et des tests plus ou moins automatisés.

L’application est monitorée, parfois redondée. Un système d’alerte et d’escalade est mis en place en cas de défaillance ayant un impact sévère sur l’activité de l’entreprise qui l’utilise. L’application s’est ainsi parfois enrichie de fonctionnalités au point de devenir impossible à décrire et à comprendre dans sa totalité avant de l’avoir côtoyée pendant plusieurs années. Et surtout, c’est un système qui a su se transformer pour rester pertinent et qui a besoin de relever certains défis pour le rester à l’avenir.

Une mission dans un tel environnement est pour moi avant tout une occasion d’accompagner ces équipes et ces métiers. Muni d’un bon compilateur, c’est aussi l’opportunité de participer à quelques-unes de leurs transformations.

Les opportunities d’améliorations d’une application legacy

Parmi les soucis qui peuvent exister dans une application déployée et largement utilisée figure le support. Les exemples ne manquent pas :

  • Des équipes de développement interrompues pour une configuration ou un bout de code urgent qu’il faut absolument pour demain à destination d’un besoin métier prioritaire ;
  • Des traitements importants qui ne tournent plus à la suite d’on ne sait quel changement au sein de l’infrastructure qu’il faut diagnostiquer ;
  • Des plantages rares qui apparaissent une fois par mois ou moins et qui conduisent à des reprises manuelles fastidieuses ;
  • Des utilisateurs bloqués dans l’incapacité d’accomplir une tâche importante à cause d’un bug ou d’une mauvaise manipulation ;
  • Et bien d’autres choses qui viennent interrompre les tâches de développement et qu’il faut adresser parfois en très haute priorité.

Ces interruptions sont rarement des fatalités inévitables. Tel plantage aléatoire peut provenir d’un bug se produisant dans des conditions rares mais parfaitement identifiables (avec pour cause un problème de gestion de transaction en base, une race condition sur des traitements parallèles, un GC un peu trop long faisant croire qu’un serveur est mort etc.). De la même manière, les demandes pressantes des métiers peuvent venir d’un manque d’outillage sur des configurations qui devraient être à leur main, les problèmes bloquant des utilisateurs peuvent être liés à un comportement « logique » mais absolument non intuitif d’une application…

Analyser les causes des problèmes de legacy

Par conséquent, il est souvent utile d’analyser les causes de ces problèmes, et de voir si une solution simple ne peut pas être apportée. Bien sûr, une fois un problème ciblé, il est nécessaire d’implémenter le correctif, de le déployer et de vérifier que les choses vont vraiment mieux.

L’identification et la résolution de ces problèmes relèvent souvent d’investigations intéressantes qui permettent de naviguer dans les divers logs et de suivre les traces pour comprendre les différents scenarii potentiellement sources de problème. Au passage, cela permet également d’apprécier ce qu’il est important de loguer, ce qui manque cruellement, ce qui pollue ou ce qui est utile.

Une fois les causes comprises, une analyse du code est de ses usages est aussi nécessaire pour déterminer la meilleure stratégie de correction et étudier l’impact et les risques de régressions de ce qu’on propose de livrer

Comment résoudre les problèmes de performance ?

Autre type de problème pouvant advenir pour une application déployée et évoluant depuis longtemps : le problème de performance. Soit l’application est victime de son succès et de la croissance des activités qu’elle supporte : amenée à traiter de plus en plus de volumes de données, elle tombe alors sur une limite d’un goulot d’étranglement dans sa chaîne de traitements. Soit l’application est étendue à un nouveau domaine d’activité proche mais générant des volumétries différentes.

Optimiser les performances nécessite d’identifier le goulot d’étranglement et sa fonction. Parfois, dans les cas simples, on peut trouver une correction très facile de quelques lignes de code, qui produit un résultat strictement équivalent mais de façon plus efficace – en supprimant des calculs inutiles ou en modifiant un algorithme quadratique par exemple.

Parfois, une petite réarchitecture est nécessaire. Par exemple pour ne pas travailler avec toutes les données en mémoire mais être capable de « streamer », pour utiliser les bases de données de façon plus ensembliste, ou encore rendre un goulot d’étranglement « parallélisable ».

Il s’agit alors de trouver les modifications les plus simples possibles, n’ajoutant pas d’effet de bord, laissant le code lisible et maintenable, et n’ajoutant pas trop de risques supplémentaires de problème à runtime. Et ce, sans connaître tous les scenarios d’utilisation de la fonction que l’on optimise si l’application est très riche fonctionnellement.

C’est pourquoi, il est important de savoir à quel point la nouvelle implémentation optimisée est équivalente à la précédente, quels sont les points de divergence afin de bien documenter les risques de passer en production sur la nouvelle implémentation, et de discuter avec les équipes des mesures à prendre. Quitte par exemple à ne l’activer dans un premier temps que sur les traitements qui posent problème, ou a minima, sur les applications vraiment critiques, avoir une possibilité via un feature toggle de revenir à l’ancien mode, lent mais connu.

Les autres transformations possibles du legacy

Il y a bien d’autres transformations qui se produisent au sein d’une équipe gérant une application legacy, et la faisant évoluer par petits sauts continus sans effet tunnel. Parmi lesquelles :

  • Bénéficier des bonnes pratiques permises pas les évolutions des frameworks, développées et éprouvées par la communauté open source.
  • Modifier les pratiques d’écritures de tests unitaires pour mieux tirer parti des annotations et les rendre bien plus lisibles, voire pouvant être écrits par des MOA pour vérifier la conformité d’un traitement à leurs specs.
  • Améliorer les chaînes de build et de tests d’intégration automatiques.
  • Déployer du code en container et sur une plateforme Kubernetes ou dans le cloud.
  • Packager de bons vieux servlets écrits pour un serveur d’application dans une application Springboot.

Bien souvent des consultants expérimentés expliquent et convainquent de l’intérêt de ces bonnes pratiques vues et éprouvées ailleurs, et les font diffuser dans les équipes…

Développer dans une application legacy

Toutefois, on peut craindre un certain inconfort de développement sur une application legacy. Des IDE obsolètes, insupportablement lents, des difficultés pour builder et tester son code, des pertes de temps dans le processus de développement… Une application legacy peut connaître de telles dérives dans son histoire, à la suite d’ajouts de fonctionnalités qui l’ont complexifiée et qui ont dégradé son environnement de développement.

Mais dans une application active et saine, il est rare que ces situations durent longtemps et que quelques développeurs n’aient pas pris ce sujet en main et aient des solutions. En java par exemple, Intelliji supporte un grand nombre de JRE, même anciens. Un peu de temps investi sur un build Maven permet d’accélérer et d’automatiser bien des choses. J’ai toujours réussi, heureusement, à me créer un environnement de développement confortable dans mes missions sur des applications legacy.

Oublier les frameworks et revenir aux fondamentaux

On peut aussi craindre que l’utilisation de frameworks anciens rendent les choses plus complexes, et qu’on ne bénéficie pas de concepts de haut niveau permettant de se concentrer uniquement sur la logique métier à coder, sans se soucier de toute la complexité qui se trouve derrière. Mais en réalité, pour résoudre la plupart des problèmes évoqués ci-dessus, il est nécessaire de retirer les ornières d’un framework et d’ouvrir le capot.

Pour analyser un problème de cohérence des données dans une base, il est important de connaître la logique de transactions, d’avoir conscience des pièges qui peuvent exister même dans un framework à base d’annotations comme Spring Data et de faire en sorte que, par exemple, des commits non désirés aient lieu. Pour analyser un problème de performance, il faut donc comprendre :

  • Quels threads sont en jeu ;
  • Comment ils interagissent ;
  • Comment les pools de diverses ressources sont gérés et configurés ;
  • Quels services externes ou internes sont appelés ; Comment le GC fonctionne au moins dans ses grandes lignes, etc.

Autant de choses qu’il est d’ailleurs dangereux d’ignorer lorsqu’on pose les bases d’une application toute neuve sur un nouveau projet.

Conclusion : une expérience très enrichissante dans la carrière d’un développeur

En fait, travailler sur l’évolution d’une application legacy donne l’occasion de résoudre des problèmes parfois complexes, de mesurer rapidement l’effet des modifications sur les utilisateurs, le niveau de support et la performance dans un environnement réel. C’est aussi l’opportunité de mesurer les défis auxquels sont confrontées les applications dans un environnement changeant, et de participer pour un temps à l’évolution de cette application et des métiers qui l’utilisent. Enfin, cela donne aussi des clefs importantes pour le développement d’applications nouvelles, anticiper les problèmes auxquels l’application risquera d’être confrontée et de faire de meilleurs choix. Avoir dans une équipe de développeur d’une nouvelle application un développeur qui a une expérience de maintenance d’une application legacy largement déployée et utilisée, c’est donner a son projet plus de chances de trouver ses utilisateurs, d’être déployée avec succès, de surpasser l’existant, et de devenir un jour une application legacy…

mieux comprendre avec meritis

Envie d’aller plus loin ?

Découvrir aussi note article « Legacy Systems : savez-vous à quoi vous attendre ?« 

Pas encore de commentaires

Publier un commentaire

Didier VIDAL

Auteur

Didier VIDAL

Didier Vidal a accumulé plus de 20 ans d'expérience dans l'édition de logiciels. Il a d'abord travaillé chez ILOG, puis chez IBM, où il a développé des logiciels de visualisation, de gestion de règles métiers, d'optimisation et de planification pour diverses industries. Aujourd'hui, il met à profit son expertise au sein de l'équipe de développement de Meritis pour accompagner les clients dans leur transformation numérique.

Découvrir ses autres articles

Pas d'autres articles publiés par cet auteur pour le moment