- En examinant récemment une codebase, l’auteur a constaté une fatigue mentale malgré la qualité du code
- Cela tenait moins à la complexité du code qu’à sa lisibilité
- Il en a tiré 8 motifs pour améliorer la lisibilité du code
Métriques de lisibilité du code et métriques alternatives de complexité
- Il n’existe pas de métrique universelle et largement utilisée pour mesurer la lisibilité du code
- On ne trouve que des articles académiques peu utilisés en pratique ou des avis personnels
- Plutôt que de créer une nouvelle métrique, l’accent est mis sur des motifs visuels que tout le monde peut facilement discuter
- Conditions importantes pour une métrique de complexité :
- Elle doit fonctionner sur des snippets de code source ou des fonctions individuelles
- Elle doit se concentrer sur la manière d’écrire le code plutôt que sur la complexité algorithmique
- Elle ne doit pas se focaliser sur les éléments de style (noms de variables, espaces, indentation, etc.)
Métrique de complexité de Halstead
- Une métrique de complexité du code développée par Maurice Halstead dans les années 1970
- Elle permet de quantifier la façon dont le code est écrit, indépendamment du langage et de la plateforme
- Elle calcule la longueur, le volume et la difficulté d’un programme à partir du nombre d’opérateurs et d’opérandes
- Principales mesures :
- nombre d’opérateurs distincts (
n1)
- nombre d’opérandes distincts (
n2)
- nombre total d’opérateurs (
N1)
- nombre total d’opérandes (
N2)
- Plus le code utilise d’opérateurs et d’opérandes, plus sa complexité augmente
- Comme la définition des opérateurs et des opérandes n’est pas claire dans tous les langages, il est important d’utiliser des outils cohérents
Enseignements tirés de la complexité de Halstead
- Les fonctions courtes avec peu de variables sont plus lisibles
- Il vaut mieux limiter l’usage des opérateurs spécifiques à un langage ou du sucre syntaxique (
syntactic sugar)
- Les chaînes de programmation fonctionnelle (
map/reduce/filter, etc.) deviennent moins lisibles lorsqu’elles s’allongent trop
Complexité cognitive (Cognitive Complexity)
- Une métrique de complexité développée par SonarSource
- Une tentative de mesurer plus précisément la difficulté de lecture du code
- Trois principes majeurs :
- Les constructions abrégées (
shorthand constructs) réduisent la difficulté de lecture
- Les ruptures dans un flux non linéaire augmentent la difficulté
- Les flux de contrôle imbriqués augmentent la difficulté
Enseignements tirés de la complexité cognitive
- Les constructions abrégées sont concises, mais comportent un risque potentiel de bugs
- Les conditions et opérateurs logiques nuisent à la lisibilité lorsqu’ils sont utilisés à l’excès
- La gestion des exceptions est l’une des principales causes de complexité du code
goto doit en général être évité, mais peut être utile dans certains cas
- Il est préférable de réduire autant que possible les structures de contrôle imbriquées
Forme des fonctions, motifs et variables
- La « forme » visuelle d’une fonction joue un rôle important dans la lisibilité du code
- Trois principes pour améliorer la lisibilité :
- Utiliser des noms de variables clairs et spécifiques
- Éviter le masquage de variables (
shadowing)
- Utiliser des noms visuellement distincts (éviter des noms proches comme
i et j)
- Réduire la durée de vie (
liveness) des variables
- Plus la portée d’utilisation d’une variable est courte, mieux c’est
- Les variables conservées longtemps au-delà des frontières d’une fonction augmentent la complexité
- Réutiliser des motifs de code familiers
- Maintenir des motifs de code cohérents améliore la lisibilité
- Privilégier les motifs déjà connus plutôt que de nouvelles approches
8 motifs pour améliorer la lisibilité du code
- Réduire le nombre de lignes/opérateurs/opérandes – de petites fonctions et peu de variables améliorent la lisibilité
- Éviter les nouvelles approches – conserver des motifs familiers dans la codebase
- Regrouper – isoler les longues chaînes de fonctions, itérateurs, etc. dans des fonctions auxiliaires
- Simplifier les conditions – garder des conditions courtes et limiter le mélange d’opérateurs logiques
- Limiter
goto – ne l’utiliser que de façon restreinte, si nécessaire, pour la gestion d’erreurs
- Minimiser l’imbrication – réduire la logique imbriquée et, si besoin, l’extraire dans des fonctions
- Utiliser des noms de variables explicites – employer des noms spécifiques et non redondants
- Raccourcir la durée de vie des variables – les garder brèves dans une fonction et éviter qu’elles ne traversent les frontières de fonction
Conclusion
- La lisibilité du code est un élément important de la qualité du code
- Halstead et la Cognitive Complexity permettent de quantifier les problèmes de lisibilité et d’indiquer des pistes d’amélioration
- Un code concis et clair facilite la maintenance et réduit le risque de bugs
- Écrire un code optimal consiste à privilégier la simplicité, la cohérence et la clarté
1 commentaires
Avis Hacker News
Enchaîner des structures de programmation fonctionnelle comme
map,reduceetfilterest concis, mais les longues chaînes ont tendance à nuire à la lisibilitémapetfilterau hasardUn aspect important du bon code est qualitatif et littéraire
Le problème le plus fatigant quand on lit du code, c’est la mutabilité
GOTOsont nuisibles parce qu’il est difficile de connaître l’état des variables mutablesLes petites fonctions et un nombre réduit de variables sont généralement plus faciles à lire
TypeScript rend le code difficile à lire
La fonction
getOddness4introduit une asymétriegetOddness2offre un choix symétriqueL’article est intéressant, mais peu satisfaisant
map,reduceetfilter, bien utilisées, remplacent d’autres opérateurs et réduisent le « volume »La tentative de définir la lisibilité mérite des éloges
La complexité du code s’exprime par la taille de l’arbre syntaxique
Pour les longues chaînes de fonctions ou les callbacks, il vaut mieux les diviser en petits groupes et utiliser des variables bien nommées