Skip links

Réduction de la dette technique grâce aux linters et au clean code

La dette technique et le clean code sont deux concepts centraux dans le développement logiciel. Pour autant, il n’est pas facile de bien les comprendre et surtout de savoir quoi faire sur son propre projet. Faut-il diminuer la dette ? Empêcher son augmentation ? Changer tout son code en suivant les pratiques du clean code ? Et surtout comment faire ? Avec quels outils ?

Dans ce billet, je vous propose un exemple tiré d’un cas concret, qui vous permettra de bien faire la part des choses. Cela vous aidera à comprendre tous les tenants et aboutissants de la dette technique et du clean code. L’objectif est de vous expliquer quoi faire en fonction de vos propres objectifs.

Ce billet s’adresse principalement aux développeurs qui souhaitent s’améliorer mais aussi aux managers qui veulent agir en toute connaissance de cause sur leur infrastructure de développement. En lisant ce billet vous saurez comment gérer votre dette et évaluer dans quelle mesure vous pouvez respecter les principes du clean code. En outre, vous saurez bénéficier des linters (ESLint) et surtout les configurer à vos propres objectifs.

 

Dette et clean code, des concepts cousins !

La dette technique est un concept du siècle dernier pointant « le code mal écrit, qu’on écrira mieux plus tard » [Cun 92]. Si vous voulez plus d’information sur le coût de la dette, je vous encourage à lire notre livre blanc La dette technique expliquée.

Certains font la différence entre la dette volontaire qui pointe le code volontairement mal écrit et la dette subie (involontaire) qui pointe le code involontairement mal écrit, (à l’insu de mon plein gré… seuls les lecteurs du siècle dernier comprendront cette référence…).

Personnellement, je ne fais pas la différence entre ces deux notions car volontaire ou pas, il faut la gérer.

Pour faire simple, je considère que la dette technique apparaît dès qu’il y a des défauts dans du code. Ces défauts n’entraînent pas de bug mais… le rendent moins lisible, moins maintenable, plus complexe etc.

L’exemple de dette technique que je vais utiliser dans ce billet est celui des callbacks JavaScript. Je présente ici un morceau du code de mon crawler (Mrs Sam), où on voit bien une grosse dette technique, la bien nommée callback hell !!!

Mon morceau de code est pourtant très simple. Il vérifie que mon crawler est bien en train de crawler un site (un check dans une base de donnée) et si tel est le cas récupère des messages dans RabbitMQ. Simple mais il faut se connecter à RabbitMQ en créant une connexion (ligne 1), puis un channel (ligne 5). Puis, il faut se connecter à MongoDB en créant une connexion (ligne 10) et en récupérant la collection (ligne 15). Enfin, on peut checker la base de données (ligne 16). Et finallement, lire les messages dans la queue (ligne 22). L’enchaînement des callbacks et la gestion des erreurs rend ce code presque illisible.

En revoyant ce code aujourd’hui, on voit bien qu’il souffre d’une dette technique. Pourtant, à l’époque, ce genre de code était très fréquent et personne ne parlait de dette volontaire ou même involontaire.

A l’opposé de la dette technique, il y a le clean code qui plébiscite l’écriture de code “propre”. Par “propre”, il faut surtout comprendre lisible. Le livre Clean code de R.C. Martin est une véritable bible sur ce sujet et j’encourage tout le monde à le lire. 

La lisibilité d’un code se mesure en regardant plusieurs aspects, tous décrits dans le livre Clean Code. La largeur des lignes de code est un de ces aspects. Plus les lignes sont larges, moins le code est lisible. Un autre aspect réside dans l’imbrication des blocs. Plus il y a de blocs imbriqués les uns dans les autres, moins c’est lisible.

Quand on regarde mon code avec les callbacks, on voit bien qu’il n’est pas très clean. Il y a peu, nous avons décidé de changer ce code vraiment moche pour le rendre plus lisible, en respectant les principes du clean code. Nous avons alors exploité les nouvelles promise de NodeJS et avons donc produit le code suivant :

Alors ? Il n’y a pas photo quand même !!!

Le code est plus lisible. Déjà, toutes la gestion des erreurs se retrouve à la fin (ligne 24). Ensuite, la largeur des lignes est beaucoup plus lisible. Enfin, l’enchaînement des promises permet de bien comprendre les différentes étapes de la fonction.

Grâce à cet exemple, j’espère que vous voyez bien que dette technique et clean code sont des concepts cousins, opposés, un peu comme le yin et le yang.

En simplifiant à l’extrême on peut dire que la dette technique c’est du code contenant des défauts, il faut donc l’améliorer. Le clean code c’est du code propre, plus lisible, de sorte qu’il est plus facile à maintenir dans le temps et qu’il est plus simple de collaborer dessus pour le faire évoluer.

 

Les 3 étapes pour faire la chasse à la dette technique et rendre le code propre ?

Le code donné en exemple illustre bien le fait qu’idéalement il faudrait pouvoir supprimer toute la dette technique et la remplacer par du code propre. Pour autant, cela serait contre productif. En effet, corriger de la dette a un coût qui peut devenir très important. Dans le cas de mon projet relativement simple, transformer tous les callbacks en promises nous a pris environ 1 homme mois. Mais mon projet a d’autres dettes que les callBack hell. Il nous faudrait alors des mois pour rendre le code intégralement propre.

Avant de se lancer dans une correction massive de la dette, la première étape à faire est d’analyser sa dette. Il faut en prendre conscience, connaître son ampleur et sa spécificité. C’est là où les linters entrent en scène.

Les linters sont des outils d’analyse de code qui embarquent des ensembles de règles identifiant des défauts causant de la dette technique.  Par exemple, le linter ESLint embarque plusieurs règles spécifiant des défauts à ne pas commettre lorsqu’on écrit du code JavaScript. Dans sa configuration de base, il vous dit par exemple qu’il vaut mieux ne pas utiliser la fonction “eval()”, qui est une grosse source de dette ou bien qu’il faut préférer la notation “arrow” des callback ( () => {}) etc.

Bonne nouvelle, pour notre exemple, ESLint dispose d’une règle qui cible l’imbrication des callbacks. La règle “enforce a maximum depth that callbacks can be nested (max-nested-callbacks)” permet de spécifier un niveau maximum d’imbrication. Si ce niveau est dépassé, ESLint affiche alors un message d’erreur et pointe vers le morceau de code qui viole la règle. En utilisant ESLint sur notre projet, nous avons alors vu que l’imbrication des callbacks était une source importante de dette.

Une fois que la dette a été analysée, la deuxième étape consiste à définir une stratégie de correction de la dette. Cette stratégie doit préciser deux aspects que sont : (1) quelles sont les règles à respecter et (2) quand et quoi corriger.

Le premier aspect vise à bien définir quelles règles proposées par les linters sont couvertes par votre stratégie. Les linters proposent en effet bien trop de règles et toutes ne sont pas nécessaires. Il faut alors sélectionner les règles qui comptent et supprimer celles qui ne comptent pas. Pour savoir si une règle compte, il n’y a malheureusement pas de méthode magique. La plupart du temps une période d’évaluation des règles par les développeurs est nécessaire dans l’objectif de faire ressortir les règles importantes. Il est aussi possible de recourir à des analyses d’impact des règles sur le nombre de bugs mais cela nécessite de disposer d’information sur le passé du projet.

Le deuxième aspect vise à définir un rythme de correction de la dette. L’objet est de préciser quand les corrections doivent être effectuées et sur quelles parties du code. Pour les gros projets, il est évident que ce deuxième aspect calibre l’effort mis dans la correction de la dette. La règle du boyscout est souvent appliquée et sert une stratégie relativement simple et efficace. L’objectif est de corriger la dette qui est présente dans les fichiers qu’on édite (il faut laisser le camp plus propre que lorsqu’on est arrivé). C’est la stratégie que nous avons mise en oeuvre dans notre projet. Nous sommes bien conscients qu’il reste encore quelques callBack hell dans certains fichiers que nous n’avons pas édités. Ces fichiers seront corrigés au fur et à mesure de leur réécriture.

La troisième et dernière étape à mettre en place est le suivi de la correction de la dette. Corriger une dette à un moment donnée n’a aucun impact si on réintroduit la même dette peu de temps après. Il faut donc être très vigilant quant au suivi de la dette. C’est là où les linters ont quelques limites et où les outils de gestion de dette technique (tel que le nôtre : Themis) trouvent leur intérêt. Ces outils permettent en effet de suivre les contributions de tous les développeurs sur le code, d’observer leur impact sur la dette et pouvoir prendre les décisions nécessaires.

 

En résumé

Au delà des débats d’experts sur ces notions importantes que sont la dette technique, le clean code et les linters, cet article propose, via un exemple concret, des préconisations pour gérer efficacement la dette.

Les trois étapes essentielles à réaliser sont :

  1. Analyser la dette : c’est lors de cette étape que les Linters sont plus qu’appréciables car ils analysent automatiquement le code source d’une application et identifient toutes les parties de votre code qui contiennent de la dette.

  2. Définir la stratégie de correction : l’objectif étant (1) de configurer les linters et choisir les règles importantes pour votre projet et (2) définir quand et où corriger la dette.

  3. Faire un suivi des corrections : grâce aux outils de gestion de dette technique pour assurer une amélioration continue de la qualité.

Cet exemple vous a-t-il parlé ? Suivez vous ces étapes pour gérer votre dette technique ? Parlez-nous de vos projets et n’hésitez pas à nous faire parvenir vos commentaires !

[Cun 92] Cunningham, Ward. “The WyCash Portfolio Management System.” In Addendum to the Proceedings on Object-Oriented Programming Systems, Languages, and Applications (Addendum), 29– 30. OOPSLA ’92. New York, NY, USA: ACM, 1992.

Réduction de la dette technique et clean code grâce aux linters