Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Les papiers des lecteurs : Comprendre les métriques de code de VS

J’essaye de laisser la parole aux lecteurs de Dot.Blog car vous avez tous quelque chose à partager. Aujourd’hui c’est Teddy Le Bras qui avec courage s’y est attelé. Comprendre les métriques de code de Visual Studio est en effet un sujet peu abordé et pourtant c’est un outil essentiel dans la bonne maitrise d’un projet.

Mesurer est toujours préférable au “pifomètre” !

On lit un peu partout que notre code doit être fiable, clair, maintenable, ou encore évolutif. Mais comment savoir s’il l’est suffisamment ? Les métriques de code mettent des nombres sur des concepts de qualité, nous permettant de quantifier et d’évaluer rapidement la qualité de nos travaux. Soyons clair dès le début, les métriques ne peuvent pas vous dire si votre code est bon. En revanche, elles peuvent vous dire qu’il est mauvais, ce qui est déjà un bon début avant de se lancer dans des revues de code. De plus, elles sont complètement objectives et facilitent donc la critique du code : Il est plus facile de dire, « attention l’index de maintenabilité est trop faible » plutôt que de chercher les mots juste pour ne pas blesser le développeur parfois susceptible !

Comment générer des métriques de code

Deux options permettent d’accéder aux métriques de code de votre projet. Vous pouvez cliquer droit sur votre projet et allez dans « Analyser » puis « Calculer la métrique du code pour la solution. ». Pardon pour les captures d’écran qui n’ont pas été réalisées sur une version française de Visual Studio !

image

Vous pouvez aussi, dans le menu « Analyser » de VS, cliquer sur « Calculer la métrique du code pour la solution. »

image

Vous obtiendrez une fenêtre de résultat ressemblant à cela :

image

Les lignes représentent les projets, namespaces, classes et méthodes de la solution.

Les colonnes contiennent quant à elles les métriques suivantes : (de droite à gauche, parce que c’est plus facile à expliquer dans cet ordre)

Lignes de code

Vous l’aurez compris, cette colonne contient le nombre de lignes de code. Attention toutefois, c’est sur le code IL que sont comptées les lignes, pas sur le code C# !

Les fonctions et classes ne doivent pas contenir trop de code, si c’est le cas, c’est que les fonctionnalités sont mal fractionnées. Vous vous retrouvez alors avec du code plus difficile à maintenir et à tester.

Couplage de classe

Il s’agit tout simplement du nombre de classes différentes dont dépend votre code. Cela comprend évidement vos variables mais aussi les interfaces que vous implémentez, la classe dont vous dérivez, et les autres classes que vous utilisez même si ce n’est que pour appeler des méthodes statiques. Math.Round, Environment.NewLine ou encore Console.WriteLine compteront tout autant que le reste comme un couplage à une classe externe. L’idée de cet indicateur est d’évaluer l’autonomie de votre code. Si le couplage de classe est trop important, votre code sera difficile à réutiliser et on peut donc douter de son architecture.

Profondeur d’héritage

Il s’agit du nombre de classes successives dont dérive la vôtre. Autrement dit, dans l’arbre d’héritage, c’est le nombre de nœuds entre la feuille (votre classe) et la racine (la classe Object). La classe Object étant à la base de toutes les classes, la valeur minimale de la profondeur d’héritage est 1 (sauf pour la classe Object du coup, c’est l’exception qui confirme la règle).

Plus on est profond, plus la classe aura de méthodes et un comportement d’autant plus difficile à prévoir et à tester. Cela entraîne également une architecture plus complexe. D’un autre côté, avoir une valeur faible peut montrer une faible réutilisabilité du code. Le moins n’est donc pas forcement le mieux mais cet indicateur nous permet tout de même de nous assurer que nous ne sommes pas en train de bâtir une usine à gaz.

Complexité cyclomatique

Cet indicateur est le nombre de « chemins » différents qu’offre votre fonction. Chaque if, switch, while, foreach etc. augmentent donc cette valeur. Si vous faites des tests unitaires, cela correspond également aux nombres de tests unitaires minimums à faire pour une couverture de code totale.

Si la complexité cyclomatique est trop élevée, c’est que votre fonction fait trop de choses et que vous devriez la fragmenter.

Ici encore, c’est sur le code IL que l’indicateur est calculé et le compteur peut parfois anormalement s’affoler, notamment si vous utilisez des expressions lambda qui sont simples en C# mais génèrent un code IL beaucoup plus complexe.

Index de maintenabilité

Indice compris entre 0 et 100, il reflète la maintenabilité générale de votre code. La formule est la suivante :

     MAX(0,(171 - 5.2 * ln(volume d’Halstead) - 0.23 * (complexité cyclomatique)
         - 16.2 * ln(Lignes de code))*100 / 171)

Essayons de déchiffrer. Cette formule contient les variables suivantes :

  • Le volume d’halstead : c’est une autre métrique qui bien que calculée n’est pas présentée par VS. Sans trop rentrer dans les détails car le sujet est suffisamment vaste, cette valeur décrit la « taille de l'implémentation d'un algorithme ».
  • La complexité cyclomatique dont nous avons déjà parlé
  • Le nombre de lignes de code que nous avons aussi évoqué

On peut déjà s’étonner de ne pas trouver l’âge du capitaine dans cette formule ! Mais plus sérieusement, depuis le début de cet article, nous essayons d’évaluer la qualité du code et la première chose qu’on nous apprend à nos débuts c’est … de commenter son code bien sûr ! Visual Studio semble n’avoir que faire des commentaires et à y regarder de plus près, on s’aperçoit que c’est une volonté et non pas un oubli. En effet la formule présentée plus haut n’est pas l’œuvre de Microsoft et la version originale comportait bel et bien le pourcentage de commentaire dans le code. Alors pourquoi Visual Studio ne pend-il pas en compte les commentaires ?

Ici encore c’est parce que VS ne s’intéresse qu’au code IL qui ne contient pas de commentaire. De toute façon, depuis la mise au point de cette formule, en 1977, les mentalités ont clairement évolué à tel point que les avis extrêmes affirment que les commentaires polluent le code et le rendent moins lisible. On peut ainsi lire dans l’excellent livre Clean Code d’uncle Bob que je vous recommande vivement :

« The proper use of comment is to compensate for our failure to express ourself in code. Note that i used the word failure. I meant it. Comments are always failures. We must have them because we cannot always figure out how to express ourselves without them but their use is not a cause for celebration. »

Pas vraiment une déclaration d’amour !

Pour en revenir au sujet, Visual Studio nous indique si l’index de maintenabilité est acceptable à l’aide d’icône de couleur :

  • Verte : Entre 20 et 100, l’index de maintenabilité est jugé bon
  • Jaune : Entre 10 et 20, l’index de maintenabilité est jugé modéré
  • Rouge : Inférieur à 10, l’index de maintenabilité est jugé faible

Valeurs conseillées

Les métriques parfaites correspondent à un projet vide. En effet, quoi de plus évolutif qu’une classe vide et comment générer moins de bug qu’en n’écrivant rien ? Les valeurs parfaites sont donc théoriques mais on peut quand même se fixer des seuils d’acceptabilité. Chacun aura les siens et ils peuvent varier en fonction de la complexité du projet. A titre indicatif, je vous présente tout de même les seuils conseillés dans les articles que j’ai lus :

 

Lignes de code

Couplage de classe

Profondeur d’héritage

Complexité cyclomatique

Index de maintenabilité

Fonction

20

2

-

10

80

Classe

200

9

6

25

80

Trouver les mauvais élèves

C’est bien d’avoir des seuils, mais si j’ai un gros projet, comment puis-je trouver les classes et fonctions les dépassant ? Visual Studio vous propose bien d’ordonner les lignes en cliquant sur la colonne d’une métrique mais les données sont triées tout d’abord par projet puis par namespace et enfin par classe et fonction. Pour trouver facilement notre bonheur, il est préférable d’ouvrir ces résultats avec Excel. Pour se faire, cliquez simplement sur l’icône qui va bien dans le menu :

image

Vous aurez tout le loisir de filtrer et ordonner tout ce que vous voulez, j’imagine que vous savez tous manier un minimum la bête.

Nous avançons dans notre réflexion. Nous savons maintenant interpréter les métriques et nous savons détecter les sources potentielles de problème. Ce qui serait encore mieux, c’est que nous ne soyons pas obligés de faire ses recherches à la main car avouons-le, c’est pénible! Nous n’y pensons pas tous les jours et nous avons tendance à le faire en fin de projet, pire moment pour se lancer dans le refactoring qui aurait dû être fait au fur et à mesure. Visual Studio peut nous aider à trouver les bouts de code suspects en générant des warnings/errors lors de la compilation. Pour cela, rendez-vous dans les propriétés de votre projet et dans l’onglet Analyse de code puis cochez « Activer l’analyse du code sur la build » :

image

Cliquez ensuite sur le bouton Ouvrir pour voir toutes les règles :

image

Les règles qui nous intéressent sont les suivantes :

  • CA1501, Eviter l’excès d’héritage
  • CA1502, Eviter l’excès de complexité
  • CA1505, Eviter le code impossible à maintenir
  • CA1506, Eviter les couplages de classe excessifs

Malheureusement, les seuils de ces règles ne correspondent pas toujours à ce que l’on veut et il n’est pas possible de les modifier directement dans Visual Studio. Dommage ! Il semble exister une solution en utilisant FxCop, un vieil outil sur lequel est en fait basée l’analyse de code dont nous parlons depuis le début. Je n’ai pas creusé cette solution car FxCop n’est plus maintenu, ça ne fait pas rêver mais heureusement l’avenir s’annonce plus sympathique.

A venir

Comme vous avez pu le voir, le fait que l’analyse de code se fasse sur l’IL n’est pas idéal. Initialement, cela a sans doute été un choix judicieux puisque l’outil est compatible avec tous les langages .NET mais l’évolution de notre langage préféré ne lui a pas facilité la vie ! On peut tout de même espérer que Microsoft n’a pas abandonné le combat puisqu’avec Roslyn, leur compilateur de compétition, ils ont toutes les cartes en main pour nous proposer un nouvel outil intégré à Visual Studio et plus adapté aux dernières versions de leurs langages. En attendant quelque chose de plus officiel et de mieux maintenu, vous pouvez toujours utiliser l’extension Code Metrics Viewer 2015 (https://visualstudiogallery.msdn.microsoft.com/ee46c9de-0890-4447-910d-d2b708de71bf), pour VS2015 donc. Elle n’est pas parfaite, pour tout vous dire, elle plante régulièrement chez moi mais je n’ai pas trouvé d’autre alternative pour le moment. Croisons les doigts et espérons que Microsoft nous offre bientôt un bel outil… à moins que l’un d’entre vous ne se sente le courage de le faire !

Pour aller plus loin

Documentation MSDN sur l’analyse de code de VS : https://msdn.microsoft.com/fr-fr/library/bb385910(v=vs.120).aspx

Comment sont prises en compte les méthodes anonymes lors de l’analyse de code : https://msdn.microsoft.com/fr-fr/library/bb514189(v=vs.120).aspx

Détails sur la formule de l’index de maintenabilité et son origine : http://avandeursen.com/2014/08/29/think-twice-before-using-the-maintainability-index/

Détails sur les formules d’Halstead : https://en.wikipedia.org/wiki/Halstead_complexity_measures

Documentation MSDN sur la création de Custom Rule Set : https://msdn.microsoft.com/en-us/library/dd264949.aspx

NDepend

[Coucou c’est moi ! Je reprends la main en fin d’article]

Teddy nous a montré dans ce papier comment exploiter les métriques de Visual Studio. C’est un outil important et pratique d’autant plus qu’il est déjà dans la boite.

Mais ce ne serait pas juste d’aborder un tel sujet sans dire quelques mots de NDEPEND.

NDepend est à la fois un logiciel stand-alone et une extension pour Visual Studio, c’est français, créé par Patrick Smacchia, et ça existe et évolue depuis des années.

Niveau métriques de code ce que Visual Studio offre comparé à NDepend c’est un peu ce qu’est la soupe de légumes de tatie germaine par rapport à la table d’un chef étoilé…

J’ai écrit de nombreux articles sur le sujet et si vous êtes intéressés par les métriques et par l’analyse fine de votre code jetez un coup d’œil par là : articles sur NDepend.

NDepend utilise une sorte de SQL spécifique pour créer des requêtes qui permettent d’interroger le code, vérifier des règles précises. Lorsqu’on doit auditer un code legacy ou même surveiller le sien en cours de développement et de maintenance c’est vraiment un outil fantastique.

Conclusion

Il faut commencer par le commencement… Les métriques de Visual Studio c’est déjà une bonne base. Les comprendre est essentiel. Et une fois qu’on a saisi toute l’importance de ce genre d’outil alors il faut tester NDepend. Et découvrir un nouveau monde !

Dans tous les cas ne négligez pas ces analyses, le pifomètre même bien exercé par l’expérience n’est pas suffisant quand un code atteint une certaine taille et pire encore quand c’est le code de quelqu’un d’autre !

D’ailleurs les philosophes vous expliqueront que “je est un autre” (Rimbaud dans une lettre à Izambard en mai 1871). Cela s’applique à notre joli métier. Reprendre un code qu’on a écrit il y a longtemps est parfois une aventure aussi hasardeuse que de reprendre un code écrit par un tiers… Retrouver ses marques rapidement sans patauger ni ajouter de la confusion et des bogues réclame de bons outils. Ceux de VS et NDepend vous rendrons de grands services !

Et Stay Tuned !

PS: Je remercie beaucoup Teddy pour son article. Que son exemple vous motive vous-aussi à me proposer des papiers !

Faites des heureux, PARTAGEZ l'article !