Sortir d’un legacy en limitant les dégâts dans des temps corrects, c’est possible !

Nicolas Poste
Ceetiz
Published in
8 min readFeb 2, 2022

Vous êtes CTO, Lead Tech ou développeur, disposez d’un legacy et souhaitez en sortir ? Vous êtes au bon endroit !

Chez Ceetiz, tout comme vous et la plupart des développeurs, nous avons un legacy. Nous avons choisi d’en sortir pour diverses raisons après une étude approfondie des motivations et impacts.

(Markus Winkler, unsplash)

Bien qu’il existe des techniques pour continuer à travailler sur un legacy, nous avons pris la décision de nous en séparer pour tout un tas de raisons et nous devons par conséquent disposer de tactiques pour faire coopérer le legacy avec les nouvelles applications le temps de le faire sortir du paysage (peut-on parler de retraite bien méritée ?!).

Cet article aborde différentes tactiques, il en existe d’autres et toutes ne sont pas systématiquement applicables. Elles dépendent de votre situation.

Mais, qu’est-ce qu’un legacy ?

Comme le nom le laisse penser, un legacy est une application ou un ensemble d’applications dont la responsabilité nous est laissée en héritage, alors que nous n’avons que peu voire pas du tout travaillé dessus. Souvent, les développeurs qui ont travaillé dessus ne sont plus dans les parages.

Bien qu’il ait pu permettre de faire du business (dans certains cas, beaucoup de business !) et a priori continue à en faire, ce legacy peut disposer de nombreux défauts :

Bref, ce n’est définitivement pas une partie de plaisir que de travailler sur un legacy ! En revanche, cela nous en apprend beaucoup :

  • on apprend des erreurs commises pour ne pas les reproduire
  • c’est un travail très challengeant si on cherche à l’améliorer (plutôt que de continuer à creuser le trou), des fois bien plus que s’il s’agissait d’un tout nouveau produit à concevoir
  • découvertes de stratégies de refactor

📖 Il est possible de continuer à travailler de façon efficace sur un legacy et il y a d’ailleurs tout un livre sur le sujet que je vous recommande ! Il s’agit de “Working Effectively with Legacy Code” de Michael C. Feathers.

Au passage, j’en profite pour donner quelques conseils pour travailler sur un legacy :

  • il est impératif de connaître la règle du “Boy Scout” : Toujours laisser un endroit dans un état meilleur que celui où vous l’avez trouvé.
  • une technique donnée par Michael C. Feathers (parmi tant d’autres !) est d’utiliser des tests de caractérisation (Golden Master Testing) : on crée un test qui part du principe que le code existant est vrai et qui nous permettra de vérifier que nos modifications à venir n’ont pas modifié ce comportement. Le Kata Gilded Rose représente un bon exercice mais il en existe bien d’autres.

Pourquoi sortir d’un legacy ?

S’il “fonctionne” et fait du business, pourquoi en sortir ? Est-ce qu’il serait envisageable de le refactorer pour améliorer les conditions de développement ? (cf Michael C. Feathers)

Et bien, pas toujours ! S’il n’a pas été conçu en respectant des bonnes pratiques de développement et d’architecture, le refactor peut s’avérer dangereux et long. L’ajout de fonctionnalités peut introduire de nombreux bugs, non détectés car les tests automatisés sont trop faibles.

📖 Je vous invite à lire des articles sur la Clean Architecture, ainsi que notre article qui détaille notre implémentation : “Notre implémentation de la Clean Architecture — Zoom sur les Use Cases”.

Il faut en effet savoir que sortir d’un legacy est très coûteux, souvent bien plus que de continuer à maintenir et faire évoluer ce legacy, en tout cas à court terme. En revanche, le côté humain n’est pas à négliger non plus car recruter des développeurs pour intervenir sur une stack technologique dépassée est loin d’être évident (déjà que de base ce n’est pas chose aisée de recruter des développeurs !). Retenir l’équipe en place ne l’est pas non plus.

Construire une nouvelle application est une excellente opportunité pour intégrer les bonnes pratiques de développement et d’architecture, et ce afin d’éviter que cette application soit rapidement un legacy ;) (parce que oui, la nouvelle application sera un legacy tôt ou tard !).

👉 Chez Ceetiz, nous avons par exemple introduit la documentation au sein de notre code source pour nos nouvelles applications. Cf cet article où nous détaillons la mise en place de la documentation : “Une documentation vivante et utile”, déjà mentionné en introduction de cet article.

Comment sort-on d’un legacy ?

La sortie d’un legacy s’étudie, se prépare. On n’en sort pas aussi facilement. Il y a souvent une période assez longue pendant laquelle la (ou les) nouvelle application tournera en parallèle du legacy. Qui est maître des données ? Où sont-elles stockées ? Comment se font les échanges entre les applications ?

Ce double run est complexe. Il faut souvent faire des choix, et les bons ! Hors de question de recréer une application qui dépend trop fortement du legacy, au risque d’introduire un ver dans la pomme, à savoir créer une application rapidement moisie et malheureusement dépendante de ce legacy.

Quid de la base de données ?

La base de données requiert une attention particulière. Que faire d’elle ? Faut-il la garder ? La nouvelle application y sera-t-elle connectée ? Si oui, en écriture et en lecture ? Etant donné qu’a priori le legacy garde la responsabilité de cette base de données historique, quels seraient les impacts sur un éventuel cache du côté du legacy ?

Bon nombre de questions de ce genre doivent avoir une réponse, ou une idée de réponse, puisqu’à tout moment la situation peut changer.

Une technique pour sortir progressivement de cette base de données, plutôt que de l’enrichir avec de nouvelles tables, collections ou autre, est d’en créer une nouvelle, utilisée uniquement par la nouvelle application qui en sera l’unique responsable.

💡 Cette technique est assez proche du principe “Open/Closed”, qui, dans le cas des classes, affirme qu’une classe doit être ouverte à l’extension et fermée à la modification.

Modifier une base de données dont l’application n’est pas “maître” peut s’avérer dangereux puisqu’on ne maîtrise pas tous les impacts.

En revanche, créer une nouvelle base de données tout en gardant la connexion à l’ancienne est également assez complexe.

👉 Chez Ceetiz, nous avons choisi de partir sur une nouvelle base de données et de garder la connexion à l’ancienne le temps de migrer : la récupération d’une donnée se fait dans un premier temps dans la nouvelle base, et si elle n’est pas trouvée, se fait dans la seconde (au détriment d’éventuelles pertes de performance).

Il est important de profiter de la mise en place d’une nouvelle base de données pour améliorer le modèle. Reprendre l’existant à l’identique n’a aucun intérêt.

ADR

Nous conseillons de rédiger un ADR (Architecture Decision Record) pour tracer tout choix non trivial : il faut impérativement faire figurer tous les éléments connus lors de la décision pour comprendre pourquoi elle a été prise. Cela n’empêche en aucun cas de revenir sur la décision plus tard, mais permet de comprendre quelles étaient les problématiques à l’époque. Cet ADR a l’avantage de ne pas nécessiter une quelconque maintenance puisqu’il est rédigé à un moment donné et ne doit pas être modifié (sauf éventuelles typos ou mises en forme).

Ce qu’on cherche à savoir, c’est quel est le contexte et les différentes pistes abordées.

💡 Dans le même genre, la rédaction de Post Mortem permet de tracer un épisode particulièrement douloureux pour que si à l’avenir le problème le problème devait se reproduire, la résolution serait plus rapide. Dans le cas d’un legacy, toute documentation pertinente est la bienvenue !

Plus d’informations sur les ADR ici.

Feature Toggles

Cette technique est connue et plutôt facile à mettre en place. Il s’agit d’un toggle modifiable à chaud qui permet d’activer/désactiver une fonctionnalité. Certaines implémentations, telle que celle fournie par GitLab via Unleash, permettent de spécifier un pourcentage d’utilisateurs ou de désigner des utilisateurs pour leur autoriser le passage à la nouvelle fonctionnalité.

Ces toggles sont une première technique pour activer/désactiver une fonctionnalité rapidement et si besoin revenir en arrière si une anomalie est détectée.

Éligibilité

Une tactique pour passer progressivement d’un legacy à une nouvelle application sans faire le “Big Bang”, est d’ouvrir au fur et à mesure des cas de plus en plus complexes. On parle alors d’éligibilité. Quelques exemples :

  • Peut-on afficher ou retourner une commande qui a été réalisée sur tel produit ?
  • Est-ce que nous gérons les commandes multi-produits ?
  • Est-il possible d’annuler telle commande dans le nouveau système ?

Si la nouvelle application n’est pas éligible pour gérer le use-case (il faut être en mesure de le détecter !), alors il y a un fallback vers le legacy qui, lui, sait gérer ce cas.

Progressivement, on décommissionne alors des fonctionnalités et de la charge au legacy, jusqu’à pouvoir s’en passer totalement. Cela donne également plus de confiance quant à la sortie de fonctionnalités : dès une régression trouvée, on peut fermer l’éligibilité pour revenir sur le comportement précédent avec le legacy.

Du côté du front-end, cela peut se faire avec une redirection et l’utilisation de nginx (parmi d’autres !). Par exemple :

  • un utilisateur souhaite afficher la page d’un produit, via l’url habituelle
  • nginx transmet la requête à la nouvelle application (front-end)
  • le front-end regarde s’il est éligible pour afficher ce produit (éventuellement via un appel au back-end)
  • s’il l’est, il affiche la page. Sinon, il redirige l’utilisateur vers la même URL mais avec un paramètre supplémentaire qui permet cette fois à nginx de transmettre au legacy plutôt que vers la nouvelle application

Cette tactique permet de sortir de nouvelles fonctionnalités dans des temps corrects : pas besoin d’attendre que l’intégralité du legacy soit réécrit avant de voir apparaître les premières fonctionnalités.

Anti Corruption Layer

Dans certains cas, des appels ou connexions vers le legacy sont indispensables. Il convient alors de mettre en place une couche d’anti-corruption (ACL). Cette couche, clairement identifiée, peut se permettre quelques écarts vis-à-vis des bonnes pratiques de développement afin d’obtenir plus rapidement la fonctionnalité souhaitée. Il conviendra alors de planifier sa suppression à une date ultérieure.

L’adoption de la Clean Architecture contribue largement à mettre en place cet ACL car il se situerait au niveau des Adapters, facilement identifiable et remplaçable (et compatibles avec les Feature Toggles et système d’éligibilité !).

Et vous, quelles sont vos tactiques ou même difficultés ?

Nous sommes en perpétuelle quête d’amélioration, adorons re-challenger nos décisions, et serions donc par conséquent curieux de connaître vos approches en ce qui concerne la sortie d’un legacy et même savoir ce que vous pensez de nos tactiques !

Nous partageons également sur d’autres articles !

Si la Clean Architecture vous intéresse, lisez sans plus attendre notre approche à ce propos et comment nous l’avons mise en place.

D’autres articles sont à venir, n’hésitez pas à nous suivre 😉

--

--

Nicolas Poste
Ceetiz
Editor for

CTO @ Ceetiz, passionné par le Software Craftsmanship, les aspects techniques, d'automatisation pour gagner en efficacité, Docker, ...