NDepend, la pleine maturité !

Il y a quelques bonnes années déjà, j’avais demandé à NDepend si je pouvais bénéficier d’une licence d’essai grâce à mon statut de MVP (beaucoup d’éditeurs le font) et Patrick, le responsable, avait bien voulu accéder à ma requête. Déjà, j’avais été impressionné et j’avais fait acheter une licence à une entreprise pour laquelle je travaillais à l’époque.

Il y a peu, j’ai eu envie de faire quelques tests de couplage d’une application par rapport à une autre, suite à une interop conçue il y a longtemps, dans une galaxie très lointaine où les développeurs ne connaissaient pas le concept de couplage lâche. Bon d’accord, je voulais savoir à quel point j’avais mal codé à l’époque, et si le travail que j’avais supervisé avec mon stagiaire était aujourd’hui regardable sans avoir honte. J’ai donc demandé à Patrick à nouveau s’il voulait me faire faire un test de son outil, et il a encore accepté, en me prévenant qu’il y avait du nouveau, en l’occurrence un graphe de dépendances réécrit. Pour être honnête, je pensais que ça allait surtout être du relookage, une ergonomie améliorée ou quelques efforts pour la performance… En fait, la refonte n’a pas usurpé son nom et le résultat est assez exceptionnel ! Je ne résiste pas au plaisir de renvoyer sur l’animation qui décrit ça dans le site NDepend :

Imaginez que vous puissiez d’un coup voir toutes les dépendances dans votre code, en zoomant à n’importe quel niveau et en revenant en arrière avec un simple scroll de souris. Ca paraît aussi magique que ces images dans lesquelles on zoome quasiment sans limite, sans que l’image serait dynamique en plus. Mais ça marche… et en plus avec des performances de dingue. De quoi voir votre code complètement différemment, car on peut sans arrêt jongler entre l’architecture de haut niveau et le pourquoi de la dépendance dans le code. La difficulté principale du logiciel, qui était liée à la difficulté de lire la matrice de dépendances, est donc complètement levée.

Retour sur un vieux projet

Il y a presque dix ans, le framework Bamboo permettait de faire de la prévalence (persistance de données en mémoire, y compris post-extinction du processus), ce qui était phénoménal en termes de performance et de capacité de développement rapide. Honnêtement, je n’ai jamais compris pourquoi cette approche n’a pas plus percée, mais je pense que le pas psychologique était trop grand. Trop en avance sur son temps, mais c’est comme toutes les technos, ça reviendra dans dix ans et on hurlera au génie et à l’innovation incroyable. Bref…

En son temps, je me disais que peut-être que rendre compatible Bamboo avec SQL permettrait de faciliter le passage à certains, et j’ai donc eu un stagiaire, excellent de surcroit, qui s’appelait Damien et qui a créé sous ma supervision un fournisseur ADO.NET pour Bamboo, comme j’en ai parlé ici. Le code est en open source et vous pourrez le trouver sur ce dépôt Github.

J’étais en train de chercher une solution pour du prototypage très rapide d’API métier avec des règles business et je me suis rappelé que la prévalence était le meilleur moyen de faire cela. Ayant besoin d’une compatibilité SQL, je me suis rappelé de ce projet, mais était-il vraiment au point ? Je me rappelais de l’avoir présenté au BreizhCamp avec Damien, mais était-ce encore à l’état de prototype ou bien terminé ? Gros blanc…

Comment savoir si ce code était à peu près correct ? En retournant dans le code source ? C’est certainement ce que j’ai fait de plus compliqué conceptuellement avec un stagiaire et je n’avais pas trop envie de me replonger dans le code. Quoi de mieux que NDepend pour reprendre la main.

Allô, Patrick ?

La même recette a encore fonctionné et le responsable de cet outil de merveille a été d’accord pour m’accorder encore une licence d’utilisation. Me voilà donc reparti à l’assaut du projet, mais bien équipé.

Il faut reconnaître que ce fameux graphe est assez incroyable :

icpglfhcaomnplnj

En un coup d’oeil, j’ai retrouvé le fonctionnement du provider, avec un analyseur de syntaxe Irony et un fournisseur complètement compatible avec ADO.NET.

Tiens, quand on zoome, on voit vite quelque chose d’intéressant : une
dépendance circulaire qui traine !

poomapmenohalmip

Je suis pourtant assez maniaque sur le sujet et le stagiaire était excellent, donc ça vaut le coup d’aller voir en faisant un clic droit et en envoyant dans la matrice de dépendances (un bête clic-droit sur la flèche, comme ça semble logique, tombe sous la main) :

fgodlmahidbpkngo

Oui, juste une petite dépendance mais l’exception aurait dû être dans un espace de nommage commun au client et à l’extracteur de code pour éviter ce problème…

Problème trouvé en… allez une minute top chrono, alors qu’une analyse de code sans l’outil ne m’aurais pas permis de le détecter. Et si je l’avais cherché avec les méthodes traditionnelles, j’aurais mis au moins un quart d’heure à faire le tour des classes concernées, sans parler des risques d’erreur, surtout que quand on se concentre sur les dépendances fonctionnelles, on a vite fait de passer complètement à côté de la partie non fonctionnelle et les exceptions en font partie.

Vision complète d’un codebase

Un autre graphique permet de voir en visite la structure globale du fonctionnement de l’application exemple, et donc de retrouver tout de suite comment fonctionne le test du provider ADO.NET :

phiaoojdgjnjniof

Evidemment, si on regarde tout au niveau méthodes et champs, on en bave, et ce même si on peut zoomer comme on veut !

nogcnaapjcandfei

Mais le miracle vient de la fonction de clustering, qui permet de trouver des ensembles intelligents de dépendances :

bcbnhbmpplgdpmlm

Ce qui est surtout très fort est que le graphe est très réactif. Tous les calculs sont faits en amont et même ça, ça ne prend qu’une dizaine de secondes pour un gros projet comme celui-ci.

L’outil de recherche nous permet de localiser en quelques secondes la classe à analyser dans tout ce plat de spaghettis :

poajehbgmjelkljf

C’est là qu’on se rend compte qu’on est bien de peu de chose avec nos petits projets à côte du framework .NET, sachant que là, on ne voit que System.Data !

jpnnpppefecfobjm

Eh oui, tout à gauche, le petit bout ridicule correspond au graphe
montré précédemment. Tout ce qui est à droite est en dépendance, et
on voit en bleu foncé les appels indirects. Là encore, on se rend
compte qu’un appel relativement simple pour nous mobilise en fait
toute une tringlerie dans le parser (Irony, dans le cas étudié) mais
aussi dans les dépendances de la BCL, en l’occurrence surtout
System.Data comme expliqué plus haut, le projet consistant à créer
un fournisseur de données ADO.NET pour le moteur de prévalence
Bamboo.

Une autre façon de voir ce ratio est sur les métriques en treemap :

nfpaieefpmllllfj

System.Data est énorme en termes d’instructions IL mais aussi en namespaces utilisés. Étonnamment, le framework Bamboo n’est pas si important qu’on pourrait le croire, et contient à peine deux fois plus d’instructions qu’Irony, lui-même correspondant en gros à la taille du provider, qui inclue toutefois la description de la grammaire à parser, en l’occurrence SQL, alors qu’elle vient elle-même d’Irony.

Gestion de la qualité du code

Le dashboard est ultra-complet :

njgmdhmlpkphmalh

Et encore, je n’avais pas activé la gestion de la couverture de code par les tests ni la comparaison par rapport à une baseline, vu que c’était la dernière version de code du provider et que je n’ai pas de version ancienne ou nouvelle à opposer à celle étudiée.

Je me suis toujours posé la question de la façon dont était étudiée la dette, donc c’est l’occasion de voir le mécanisme grâce à l’aide contextuelle (voir ci-dessus). Ce qui est bien est qu’on peut toujours revenir en arrière et changer facilement le contenu du projet d’analyse, ce qui dans mon cas était particulièrement important pour cette analyse de la dette technique, car je n’allais évidemment pas prendre en compte les 177 jours de résolution de System.Data et autres dépendances. En relançant pour la seule assembly correspondant au provider, on retombe sur quelque chose de plus logique… et rassurant :

lfehblnffbocbkjg

Encore deux règles critiques violées, je me demande ce que ça peut être. Là encore, l’ergonomie est top et un clic nous amène directement sur les deux problèmes :

ocoeckhofjmbbhmj

Encore une fois cette dépendance cyclique, et on sait maintenant qu’il y aura un peu de boulot, car il y a 20 occurrences. Un double-clic sur la règle, et nous voilà avec la liste tout prête des endroits où porter une correction :

gdcfbodhamghnlfl

On retrouve la dépendance en boucle vue plus haut et causée par le fait que l’exception n’a pas été externalisée.

Pour les autres, le problème est au niveau du namespace SampleApplication.Queries qui appelle SampleApplication. Pour voir ce qui se passe précisément, on peut copier les types dans la matrice :

nohaekaijkfagpoi

Un coup d’œil nous permet alors de trouver le point exact du problème :

jfobiobakpjhbdec

L’autre possibilité est de passer par l’ouverture du code piloté par NDepend :

fjhfhnfadojfcpeo

La fenêtre permet de choisir lequel des deux problèmes est à traiter :

belhepjoigjemilk

Et un clic nous renvoie alors directement sur le cœur du problème :

kgankpgkccmaimhj

L’exécution pourrait effectivement être plus propre si on n’avait pas à caster l’objet passé dans des types qui sont sur SampleApplication, à savoir le PersistenceSet et le PersistenceEngine.

Conclusion

Au final, je n’avais pas utilisé NDepend depuis quelques temps vu que je faisais plus d’architecture et d’urbanisation des SI que de code, mais je vois que l’outil a encore grandi et s’est renforcé. Sa puissance peut paraître difficile à maitriser au premier abord, mais l’interface fait intelligemment des liens multiples entre toutes les fonctions, ce qui fait qu’on s’y retrouve d’une façon ou d’une autre, et que finalement chacun aura peut-être une façon différente de naviguer entre les multiples outils, mais c’est sans importance.

La fonction de graphe, quant à elle, est proprement bluffante. La performance est même telle qu’on se demande s’il n’y aurait pas de l’accélération des traitements par la carte graphique, avec des approches vectorielles. La possibilité de zoomer quasi à l’infini fait penser à ces images à ultra-haute résolution, mais ce n’est visiblement pas cela qui est utilisé. Dans tous les cas, la méthode fait des miracles.

Bien sûr, si votre code est très complexe, il restera compliqué à lire et déboguer, même avec NDepend, mais vous aurez un pilote pour vous y retrouver. Et même dans le cas où le code est relativement bien connu, on peut retomber sur des choses à améliorer comme je l’ai constaté sur ce petit projet !

Je ne peux pas finir sans féliciter l’équipe NDepend, car cet outil est vraiment un bijou. Je ne sais pas si Patrick est tout seul derrière, mais j’ai du mal à imaginer ça, vue la puissance et l’utilisabilité du produit. Et encore, je n’ai pas parlé de toutes les règles et alertes, ainsi que les indicateurs sur la qualité du produit ! Bref, chapeau Smile.

En me baladant sur le site, je vois que NDepend est même intégré à Azure DevOps. Manque plus que le support de Visual Studio Code et on aura atteint l’absolue perfection !

About JP Gouigoux

Jean-Philippe Gouigoux est Architecte Logiciel, MVP Connected Systems Developer. Il intervient régulièrement à l'Université de Bretagne Sud ainsi qu'à l'Agile Tour. Plus de détails sur la page "Curriculum Vitae" de ce blog.
This entry was posted in .NET, Performance, Prevalence and tagged . Bookmark the permalink.

2 Responses to NDepend, la pleine maturité !

  1. Françoise FARAG says:

    Excellent article compréhensible même pour les non-initiés au code

  2. Vincent says:

    Ça me donne (presque) envie de refaire du code ☺️. Merci Jean-Phi pour ce sympathique article.

Répondre à Françoise FARAG Annuler la réponse.

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha Captcha Reload