Vous êtes un développeur, un Lead Dev ou CTO et travaillez sur tout type de projet logiciel ? Comment vérifier la santé du code et s’assurer que le produit développé ne soit pas malade ? Quels sont les enjeux et que faire s’il l’est ?

Connaître et gérer la santé du code

Vous êtes agile mais vous n’en voyez toujours pas les bénéfices ? C’est peut-être normal, vous oubliez une partie complémentaire : l’artisanat du code, ou software craftsmanship.

📖 Tandis que l’agilité nous aide à nous assurer que nous construisons la bonne chose, les pratiques techniques nous aident à nous assurer que nous construisons la chose bien.

Comment mener le diagnostic pour connaître la santé du code ?

Des outils d’analyse statique de code tels que SonarQube peuvent vous amener des premiers indices. Ceci dit, il n’est pas toujours évident d’interpréter ses rapports.

Sur le code le plus malade que j’ai pu voir jusqu’à présent (en phase terminale, incurable), SonarQube attribue une note de A, soit la meilleure note. Il s’avère que la note est donnée est calculée à partir d’une estimation : la dette technique du projet comparée à l’estimation du coût pour tout réécrire à partir d’une feuille blanche. Dans mon cas, la complexité de l’application était telle qu’il est, selon SonarQube, plus simple de résorber la dette technique que de tout recommencer. Dans les faits, la complexité introduite n’avait pas lieu d’être, et dès lors, on se rend compte que le calcul de la note peut artificiellement être influencée par la façon d’écrire le code.

Avec un bon budget, il est également possible de commander un audit de code réalisé par un cabinet externe.

👉 La qualité logicielle passe par différentes notions que j’aborde dans un précédent article : Les notions derrière la qualité logicielle, ce qu’il faut savoir

Quels sont les symptômes ?

En général, il n’y a pas besoin d’être le nez dans le code pour savoir s’il est en bonne santé. Ça se sent ! Quelques symptômes :

  • Vous n’avez pas assez de tests unitaires ou pas du tout (on parle alors de code legacy) !
  • Vous avez des tests automatisés de haut niveau instables et lourds à maintenir
  • Vos évolutions sont très coûteuses
  • Des technologies utilisées sont méconnues d’une majeure partie de l’équipe de développement
  • Des régressions font fréquemment leur apparition
  • L’architecture et la logique sont complexes
  • Il existe une dette technique à faire pâlir la Grèce
  • Des outils ont été mis en place pour contourner les problèmes
  • Des frameworks ont élu domicile au cœur du système alors que vous aimeriez en changer

👉 Si vous êtes le responsable produit et travaillez avec une équipe de développement, quelques uns de ces points peuvent vous aider à connaître l’état du produit. Restez proche des équipes de réalisation !

Alors docteur, c’est grave ?

Plusieurs ordonnances vous sont proposées :

  • ne rien faire
  • résorber la dette progressivement
  • repartir d’une page blanche

Ne rien faire

Il s’agit en fait d’une fausse solution, car les évolutions seront de plus en plus coûteuses, et les bugs de plus en plus difficiles à corriger, les budgets illimités n’existant pas. Le risque de départ des développeurs n’est pas à prendre à la légère. Avec tout départ, c’est un peu de connaissance du projet et de l’ambiance dans l’équipe qui partent aussi.
La règle à appliquer dans ce cas est malgré tout la règle du “Boy scout” : Laisse ton code en meilleur état que tu ne l’as trouvé.

Résorber la dette progressivement

La tâche sera longue et difficile, mais peut s’avérer beaucoup moins coûteuse que de tout recommencer. Il n’en reste pas moins qu’il s’agit d’un sacré challenge qui peuvent en motiver certains, et en décourager d’autres. Selon moi, cela va principalement dépendre de l’environnement de travail et de l’angle d’attaque.
Le plus souvent, un pourcentage de production sera consacré à la résolution de la dette. Cela peut également passer par la création de fiches techniques pour refactorer telle ou telle partie du code, même si je préfère en général effectuer le refactoring selon les besoins de l’équipe et les évolutions confiées.

Exemple : Si je dois corriger un bug ou faire une évolution dans une méthode de 100 lignes, je pourrais en profiter pour ajouter des harnais de tests dans un premier temps, puis simplifier et mieux découper cette méthode pour respecter le principe de responsabilité unique (SRP).

Repartir d’une feuille blanche

La solution préférée des développeurs, mais pas des acheteurs !
Si annoncer à son client que le code est dans un tel état qu’il faut le recommencer est très délicat quand il s’agit de son propre développement, cela peut être plus facile lorsque le développement et la maintenance de l’application sont confiés à une toute autre entreprise.

💡 Et, de toute évidence, si on recommence à zéro, on en profite pour repartir sur une stack technique à jour et dans l’état de l’art !

Cette solution n’est pas sans risque, elle est très engageante. Entreprendre de repartir d’une feuille blanche et s’arrêter au milieu faute de budget est à l’opposé de ce qu’il faut faire. On se retrouverait alors à gérer deux applications en parallèle avec pour chacune sa complexité.

Si vous êtes tenté de repartir d’une feuille blanche, vous serez probablement amené à imaginer au moins deux façons de faire.

Première idée : reconstruire à côté

On serait tenté de construire la nouvelle application à côté et de ne la livrer qu’une fois prête, mais il est bien entendu déconseillé de procéder ainsi, surtout si l’application actuelle est déjà en production. Cela serait contraire à l’esprit agile, qui consiste à créer de la valeur et avoir des retours rapides : l’effet tunnel n’est pas à négliger et on n’est pas sûr d’obtenir quelque chose d’acceptable à l’arrivée.
Dans le lexique médical, on pourrait comparer cette reconstruction à la grossesse. On ne découvrira qu’au bout de 9 mois à quoi ressemble le bébé, et, espérons le, s’il est viable.

Seconde idée : reprendre petit à petit des fonctionnalités

Je privilégie cette idée, mais attention à la méthode ! Sachant que l’application legacy est amenée à être jetée (normalement), il est indispensable de ne pas en être dépendant.

👉 C’est l’inverse qui doit être fait : l’application legacy doit dépendre de la nouvelle, sinon, que se passera-t-il lorsque nous voudrons jeter la première ?

L’architecture fonctionnelle et technique doit être revue en apprenant des erreurs commises précédemment.
Un des impératifs de cette refonte est de garder le nouveau système propre. Il est hors de question de propager la “maladie” du legacy vers cette nouvelle, elle s’y installerait partout à terme.

💡 Malheureusement, ce n’est pas toujours possible de faire ainsi, et ce que je préconise dans ce cas est de développer un adaptateur, bien isolé du reste, pour faire office de couche isolante entre ces deux zones. La maladie ne doit pas se propager !

La reprise des fonctionnalités peut se faire lors d’évolutions ou d’ajouts de fonctionnalités. L’existant va alors appeler le nouveau service au lieu de l’ancien.

Exemple : Si je dois enrichir la fonctionnalité de recherche d’informations, plutôt que d’adapter le service actuel avec tous ses défauts, je mets en place un nouveau service refait à neuf dans un nouveau composant isolé et le rend disponible pour que l’existant le sollicite (pas de dépendance !).

Dans le lexique médical, cette solution serait plutôt comparée à l’apprentissage donné par une personne âgée à un enfant, qui prend de plus en plus de responsabilités et déleste la personne âgée.

Le vaccin, ça existe ?

Il existe différentes façon d’éviter que la maladie se déclare.
Les symptômes cités doivent être détectés au plus tôt et il faut s’attaquer à plusieurs axes d’amélioration en parallèle.
Les boucles de retour doivent être les plus courtes possibles, que ce soit avec le client, l’utilisateur ou par le système de build.

👉 Si vous ne l’avez pas encore lu, je vous conseille de lire un de mes précédents articles qui aborde une partie de ce sujet : Livrer de la qualité tout en restant productif

Les bonnes pratiques de développement doivent mises en place dès le début et être suivies tout au long du développement du produit. Plus on laisse traîner, plus il sera difficile de s’en tirer sans en laisser des plumes.

L’image d’une construction est souvent prise pour expliquer l’évolution du code. Cependant, ce n’est pas l’image la plus fidèle, je préfère celle du jardinage. Il faut voir le code comme étant un être vivant, qui évolue, d’une manière des fois imprévue, et qu’il faut régulièrement entretenir. Le développeur serait alors un jardinier, qui arrose l’arbre et coupe des branches pour lesquelles il était à l’origine et pour lesquelles il assurait la maintenance.

L’équipe de développement doit être responsabilisée mais aussi sensibilisée aux problèmes de qualité de code. Les katas, sessions de revue de code sont d’excellents moyens pour y remédier.

👉 En effet, en plus de permettre d’améliorer la qualité de l’application à court et à long terme, la revue de code permet de faire grandir chaque personne, que ce soit le relecteur ou le relu. J’y ai d’ailleurs consacré tout un article, alors n’hésitez pas à le lire : Travailler efficacement en équipe avec la revue de code

La sensibilisation à la qualité passe par tout le monde !

📖 “In order to increase business agility, and have a good return on investment, keeping code quality high is paramount” (Sandro Mancuso, dans son livre The Software Craftsmanship, Professionalism, Pragmatism, Pride)

Et vous ?

Avez-vous rencontré des symptômes cités ? Envisagez-vous une résorption de la dette ou un refonte intégrale de l’application ? Comment vous-y prenez-vous ?
Je serai ravi d’avoir vos retours en commentaire !

Dans un prochain article, j’essaierai d’aborder des méthodes pour minimiser le risque d’échec des projets et commencer un projet sur de bonnes bases.