Analyse statique de code pour C# et .NET avec NDepend

En tant qu'architecte logiciel j'ai souvent besoin de faire un contrôle de qualité du code de mes clients.

Le code a-t-il une bonne tête ? Qu'en est-il de sa complexité et de la couverture de test ? Puis-je le considérer comme facilement maintenable avec une bonne évolutivité ?

Bien sûr, je ne vais pas passer tout mon temps à lire chaque fichier source, ce serait trop long et probablement peu efficace. Heureusement un ensemble de règles et d'outils peuvent être d'un grand secours si vous êtes dans la même situation.

Pour ceux qui utilisent .NET comme leur principale technologie, je vous invite fortement à essayer chacun de ces outils pour voir comment ils peuvent vous aider à être plus efficace dans vos analyses:

  1. Sonar est un analyseur de dette et prend en charge plus de 25 langues
  2. ReSharper fait un focus sur la productivité et propose une analyse statique de code ainsi que plusieurs autres fonctionnalités
  3. JustCode est également un outil d'aide à la productivité
  4. FxCop effectue une analyse statique suivant les bonnes pratiques et recommandations du framework .NET
  5. NDepend propose une analyse statique de code pour**.NET** et se concentre sur les relations entre les objets

Chacun d'eux aura ses avantages et inconvénients ainsi que son domaine d'utilisation spécifique. C'est pourquoi, dans certains cas, Sonar pourra être un meilleur choix que NDepend ou ReSharper et vice versa !

Dans cet article je présenterai NDepend.

Qu'est-ce que NDepend?

NDepend fait de l'analyse statique de code pour .NET. C'est un outil commercial et vous pouvez l'essayer gratuitement pendant 14 jours.

Patrick Smacchia a créé NDepend en 2004.

psmacchia

NDepend peut être utilisé en mode standalone ou intégré Visual Studio.

Personnellement je préfère le mode intégré à Visual Studio car il offre toutes les fonctionnalités basiques et plus tout en restant dans votre IDE.

NDepend vous donne accès en un clic à de nombreuses métriques de votre code avec une représentation graphique. C'est un vrai plus !

Pour moi, le point fort de NDepend est le langage de requêtage sur lequel il est construit : CQLinq.

CQLinq, qui signifie Code Query LINQ, est un langage de requêtage que vous pouvez exécuter sur un modèle abstrait de votre code. Concrètement, vous pouvez faire des requêtes sur votre code de la même manière que vous interrogeriez les vues ou tables d'une base de données. Par exemple, pour obtenir toutes les méthodes ayant plus de 30 lignes de code, j'écrirais la requête suivante dans l'éditeur CQLinq:

from m in Methods where m.NbLinesOfCode > 30 select m

Dans Visual Studio, vous pouvez voir côte à côte la requête et la représentation graphique des résultats dans la fenêtre "Code Metrics" :

NDepend_query_metric

Grâce à CQLinq il n'y a plus grand-chose à faire, toutes les métriques peuvent être traduites en requêtes CQLinq et c'est en cela que NDepend est très puissant !

Aussi, NDepend donne accès à toute sa logique dans une API que vous trouverez dans le dossier lib du répertoire d'installation: NDepend.API.dll

Vous pouvez utiliser l'API de NDepend pour construire votre propre outil d'analyse de code. Pour cela il vous suffit d'inclure le fichier NDepend.API.dll en tant que référence dans votre projet. Voici un petit exemple de l'utilisation de l'API.

from m in Methods
where m.NbLinesOfCode > 30
orderby m.ILCyclomaticComplexity descending
select new { m }

Cela peut facilement être traduit dans une fonction C# de votre projet ainsi :

using NDepend.CodeModel;
using NDepend.CodeQuery;

public List GetComplexMethods(ICodeBase codeBase)
{
var complexMethods = (from m in codeBase.Application.Methods 
                      where m.NbLinesOfCode > 30
                      orderby m.ILCyclomaticComplexity descending
                      select m).ToList();

return complexMethods;
}

Pour en savoir plus, la documentation de l'API NDepend est accessible en ligne.

Maintenant, tout ce dont vous avez besoin c'est un peu d'imagination et vous pourrez construire VOTRE outil d'analyse de code.

Règles NDepend

NDepend arrive avec de nombreuses requêtes pré-configurées en suivant un standard de qualité assez commun. Pour explorer les règles prédéfinies il suffit d'ouvrir la fenêtre "Explorer Panel" :

NDepend_menu

Et puis, vous obtenez cette vue:

NDepend_q&rexplorer

En fait, plus de 240 règles sont déjà définies pour vous et prêtes à l'emploi.

Je vous conseille quand même de relire les règles avant de vous en servir, comme pour tout ce qui est pré-défini en général. Par exemple, selon les règles NDepend, le filtre suivant identifie les méthodes "trop complexes". Si cette définition ne vous convient pas, vous pouvez la modifier ou en créer une nouvelle :

from m in  JustMyCode.Methods
           where m.NbLinesOfCode > 30 ||
                 m.CyclomaticComplexity > 20 ||
                 m.ILCyclomaticComplexity > 50 ||
                 m.ILNestingDepth > 5 ||
                 m.NbParameters > 5 ||
                 m.NbVariables > 8 ||
                 m.NbOverloads > 6
select new { m }

Même si les règles NDepend sont le plus souvent très proches de ce que nous pourrions considérer comme des règles de référence, je recommande fortement de prendre le temps de les affiner ou même écrire vos propres requêtes !

NDepend_createcustomeq

A ce niveau vous devriez probablement vous demander ce qu'est JustMyCode?

Ne paniquez pas, vous vous posez la bonne question ! JustMyCode est juste un filtre qui permet de distinguer le code écrit par les développeurs du code généré par des frameworks ou des outils.

Comme il n'y a pas grand intérêt à analyser du code généré, JustMyCode doit toujours être utilisé dans vos requêtes.

Vous pouvez étendre la définition de JustMyCode très facilement :

notmycode
from m in Application.Namespaces.WithNameLike("NameSpace.Of.GeneratedCode").ChildMethods() select m

Dans cet exemple, je dis que tout le code du namespace "NameSpace.Of.GeneratedCode" est à considérer comme code généré. Vous pouvez également filtrer par attributs, noms de fichiers, convention de nommage, d'héritage ou autre très facilement ! Par défaut NDepend a déjà une configuration de JustMyCode qui filtre la plupart des cas.

Vues graphiques

Vous disposez de quatre vues graphiques dans NDepend. Deux d'entre elles font un focus sur les liens de dépendance. La troisième est la vue "Code Metric" dont j'ai rapidement parlé au début. Et la quatrième vue,  plus générique, est l'export sous forme graphique des résultats de votre requête CQLinq.

Côte à côte la matrice et le graphe de dépendance :

NDepend_matrix_graph

Si vous n'êtes pas familier avec ces graphiques, pas de panique, en général personne ne l'est ! Par chance, NDepend vous explique via des infobulles comment interpréter les résultat et valeurs. La matrice et le graphr de dépendance vous aident à comprendre comment les assemblies, namespace, classes et méthodes dépendent les uns des autres.

La vue graphique est plus pratique pour mettre en évidence un "code spaghetti" et la matrice sera plus adaptée pour vérifier si oui ou non le code suit le principe de couplage faible et une forte cohésion. Ainsi, la plupart du temps, il vaudra mieux jeter un œil aux deux.

Par contre, je ne suis pas convaincu de l’intérêt d'avoir des courbes aussi sinueuses dans le graphe.  Même avec très peu d’éléments, les lignes sont courbes ! De mon point de vue cela ajoute une confusion inutile, je préférerai avoir des lignes droites. Regardez par vous-même:

NDepend_curves

Voici ce que l'équipe de NDepend dit à ce sujet :

The graph algorithm comes from an older version of MsAgl. Actually we don't find the result that over-curly, but anyway, Graph is an important feature that will face major enhancements in the mid-term

Ensuite, la vue "Metrics" affiche des bloc de taille directement proportionnelle à leur masse selon la métrique sélectionnée.  Par exemple vous avez le choix parmi le nombre de lignes de code, nombre d'instructions IL... :

NDepend_metricchange

En sélectionnant le filtre de métrique "#lignes de code" j'ai eu ce message à plusieurs reprises:

NDepend_errormessage

Comme vous pouvez le voir, même si le message est très clair, il n'est pas utile, car il ne vous en dit pas plus sur ce qui est manque exactement !

Au cas où vous seriez dans la même situation, vérifiez manuellement que chaque projet est configuré pour générer les fichiers pdb dans le même répertoire que celui des assemblies. Aussi, les warning émis par NDepend au moment de la génération du rapport peuvent être utiles.

Intégration continue

Vous pouvez facilement configurer NDepend pour faire partie de votre serveur de build dans votre processus d'intégration continue. Pour cela vous pouvez le configurer en ligne de commande comme une build task ou tout simplement utiliser l'extension NDepend TFS 2010 integration on Codeplex.

NDepend est compatible avec CCNet, TFS, FinalBuilder, Team City et probablement beaucoup d'autres, pour en savoir plus sur le sujet c'est par ici.

Open Source

J'ai présenté NDepend comme un outil commercial. Ce n'est pas faux, mais l'API NDepend est complètement libre d'utilisation. En fait NDepend est livré avec un outil de ligne de commande appelé "NDepend.PowerTools" et son code source :

NDepend_powertools_opensource

Comme il est dit dans la documentation:

NDepend.PowerTools are a set of short open-source static analyzers, packed into the Visual Studio solution.

Donc, vous êtes libres d'étendre le code pour votre propre usage.

Une fonctionnalité très cool du PowerTools est le détecteur de duplication de code :

NDepend_powertools

Je pense que cette fonctionnalité devrait être pleinement intégrée dans l'interface utilisateur NDepend et voici le retour que nous avons eu à ce sujet :

Certainly code cloning detection is a future flagship feature

Documentation

La documentation de NDepend est complète et à jour. Elle couvre l'ensemble des fonctionnalités de l'outil avec pas mal d'illustrations et d'exemples. On y retrouve également une vidéo d'introduction de 3 minutes. Malheureusement, la vidéo est enregistrée pour la version 4 de NDepend alors que la version actuelle est la version 5. Je pense que Patrick Smacchia aurait pu faire mieux en enregistrant plus de vidéos, voici sa réponse :

More videos is definitively something we need to offer and will offer

Autres fonctionnalités

Au-delà de toutes ces bonnes fonctionnalités, NDepend propose également:

  1. Génération de rapport HTML
  2. Analyse de la couverture de test
  3. Analyse en continu
  4. Mise en échec du build en cas de violation d'une règle

Ce qui manque à NDepend?

Pour moi NDepend est un excellent outil qui pourrait encore mieux faire avec quelques améliorations.

En fait, vous ne pouvez pas passer à coté du fait que la majorité des applications combinent différents langages. La plupart du temps, votre application web sera un ensemble de lignes de C#, ou autre langage, et JavaScript. Pour cette raison, il faut que votre analyse de code soit polyglotte, ou au moins bilingue. Et puisque NDepend ne comprend pas le JavaScript, il vous faudra naviguer entre plusieurs outils pour analyser toute votre application.

Cela peut être un très mauvais point pour certains utilisateurs qui préféreront un outil tel que Sonar avec son support multi-langage.

Par exemple, dans une application SPA en C# ASP.NET, la plupart du code sera probablement écrit en JavaScript et je devrai compléter le rapport NDepend en utilisant un autre outil.

Le deuxième élément manquant serait le rapport d'analyse de dette. Patrick Smacchia a choisi de se concentrer sur les faits sans faire d’interprétation. Mais je pense que justement l'interprétation intelligente de l'analyse via un rapport de dette serait très apprécié par de nombreux développeurs. Voici ce que nous a répondu l'équipe de NDepend:

Same as code cloning, debt analysis is a future flagship feature

Dernier Mot

En tant que développeur .NET, j'ai trouvé NDepend très puissant et très facile à utiliser. Je pense vraiment que le langage CQLinq et l'API NDepend sont en fait les meilleures fonctionnalités de l'outil et en plus je n'ai rien trouvé d'équivalent à ce niveau.

L'équipe  de NDepend est très active et on peut s'attendre à beaucoup de bonnes évolutions dans les prochaines versions.

Je vous invite vivement à l'essayer, c'est par ici!