La qualité du code des développements .NET

Qu’est-ce que la qualité du code ?
Définition
La qualité du code source ne concerne pas tout le monde. Tout d’abord la machine ne sait pas ce que c’est. Elle se contente de compiler ou d’interpréter ce code en quelque chose qu’elle est capable d’exécuter.
La qualité ne lui importe pas. Et personne en dehors de l’équipe de développement ne voit le code. Les seuls concernés font donc partie de l’équipe.
Et du point de vue de l’intérieur de l’équipe, les critères de qualification d’un code de qualité sont souvent restreint à la lisibilité, la maintenabilité et la couverture des tests.
Qui cela intéresse-t-il, dans l’équipe ?
- Le nouvel arrivant
- Les développeurs
- L’architecte
- Les responsables de projet
- … tout le monde finalement.
La qualité est-elle quantifiable ?
OUI ! Il existe un ensemble de métriques permettant de mesurer la qualité du code. Nous aurons donc une approche quantitative de la qualité.
Pourquoi la mesurer ?
Il existe un ensemble de raisons justifiant la mesure de la qualité du code. Les principales sont :
- un code mal maîtrisé entraîne mécaniquement une augmentation régulière et constante de la dette technique
- une surveillance des métriques permet une diminution du coût de maintenance à moyen et long terme
- une accélération de la prise en main du code : un code homogène sera mieux pris en charge par l’équipe, et l’intégration de nouveaux arrivant s’en retrouve également facilitée
- un refactoring plus aisé : c’est un effet de bord direct du point précédent. En facilitant la prise en main, on diminue l’effet boîte noire. Combiné au précept YagNi d’XP et aux gardes-fous de l’Intégration Continue, l’adaptation permanente du code au besoin s’en retrouve fortement facilité.
- Qui dit approche quantitative dit processus automatisable et donc peu coûteux !
Que mesurer ?
L’ensemble des métriques que nous allons voir par la suite veillent à mesurer en priorité les points suivants :
- la complexité
- la clarté
- l’uniformité
- la couverture par les tests
Deux principes fondamentaux
Less is more : moins il y a de code, le mieux. Un code minimaliste assure une meilleure factorisation et donc une meilleure évolutivité.
KISS : Keep it simple, stupid. Le plus simple, le mieux. Un code simple sera plus facile à appréhender et à maintenir dans le temps.
Ces 2 principes découlent du “YagNi” mentionné plus haut.
Les métriques de mesure de la qualité du code
L’indice de spécialisation d’une classe
SPE = (S*P)/Nb
S = Nombre de méthodes surchargées
P = Profondeur d’héritage depuis System.Object
Nb = nombre de méthodes de la classe
Une classe dont le SPE est trop élevé devra être refactorée.
L’indice d’instabilité d’une librairie
INS = Out / (In + Out)
Out = Nombre de classes externes dépendant de la librairie (responsabilité)
In = Nombre de classes de la librairie dépendant de classes externes
0 <= INS <= 1
Pour la classe System.String, qui ne dépend pas de grand monde, mais dont au contraire, énormément d’autres classes dépendent, INS tend vers 1, et un refactoring de cette classe sera donc risqué.
Au contraire, votre classe MaLibrairie.MesUtilitairesMetier, INS tend vers 0.
Le coefficient d’abstraction d’une librairie
ABS = I / T
I = Nombre d’interfaces de la librairie
T = Nombre total de types de la librairie (classes et interfaces)
0 <= ABS <= 1
La distance de la bonne conception d’une librairie
D = | INS + ABS – 1 |
Idéalement, D tend vers 0. Les 2 cas idéaux sont
- INS = 0 et ABS = 1 : la librairie est totalement abstraite et parfaitement stable.
- INS = 1 et ABS = 0 : la librairie est parfaitement concrète et très instable, car elle dépend d’une multitude d’autres librairies.
La complexité cyclomatique d’une méthode
CYC = nombre de noeuds if, case, while…
Il s’agit du nombre de chemins possibles possibles dans une méthode.
- avec CYC > 30, un refactoring est nécessaire
- avec CYC <= 30, la CYC est acceptable si le taux de couverture est élevé
Le taux de couverture d’une méthode
COUV = (NbTest / Nb) * 100
NbTest = Nombre de lignes couvertes par les tests unitaires (TU)
Nb = Nombre total de lignes de la méthode
Si COUV = 100%, le nombre de TU = CYC
Quelques autres unités mesurables
- Duplication de code
- Ratio lignes de commentaires/nombre de lignes
- Pourcentage de méthodes trop longues
- Nombre de classes par librairie
- Nombre de méthodes par classe
- …
Quels outils pour mesurer la qualité du code .NET ?
Microsoft StyleCop
StyleCop analyse le code source, et applique les règles de syntaxe suivantes :
- documentation
- présentation
- maintenabilité
- nomenclature
- classement
- lisibilité
- indentation.
Des ensembles de règles prédéfinies sont disponibles et paramétrables. Il peut être intégré à Visual Studio, ainsi qu’à MSBuild et donc à votre Intégration Continue, de façon à lever des alertes, voire de casser le build en cas de violation d’une de ces règles. Quelques exemples de règles : les accolades doivent se trouver sur une ligne dédiée, les variables privées doivent commencer par une minuscule…
A noter que le projet est Open Source depuis 2010.
JetBrains Resharper
ReSharper (R#) expose nativement un ensemble de règles concernant le code. La différence est que les fonctionnalités de refactoring de ReSharper sont bien plus puissantes que celles embarquées nativement dans Visual Studio, même si VS2010 a fait des progrès dans ce domaine. Là où les choses deviennent intéressantes, c’est qu’il est possible de faire cohabiter R# et StyleCop de façon à bénéficier d’un ensemble de règles communes. R# sera utile durant le développement, et StyleCop pourra être utilisé pour l’Intégration Continue.
Depuis 2009, Telerik, autre excellent éditeur de solutions pour développeurs Microsoft, s’est lancé sur le terrain et propose JustCode.
Microsoft FxCop
FxCop s’attèle quant à lui à l’analyse du code compilé MSIL et applique des règles de :
- Design
- Interopérabilité, portabilité
- Conventions de nommage, de globalisation
- Sécurité…
L’idée est ici de vérifier si vos librairies sont conformes aux recommandations du Framework .NET.
Campwood SourceMonitor
SourceMonitor analyse la complexité du code source : méthodes et librairies. L’outil propose la génération de rapports XML et CSV, ainsi que les corrections à apporter.
A la différence des outils précédents, il est multilangage et n’est pas nativement intégré à l’usine logicielle.
Mono Gendarme
Mono Gendarme, hérité du projet Mono, se veut un complément de FxCop. Il s’intéresse lui aussi au code compilé et s’attèle à détecter et anticiper des bugs connus laissés passés par le compilateur.
Ncover
NCover est un outil d’analyse du taux de couverture par les tests unitaires et génération de rapport d’évolution du taux de couverture dans le temps, fonctions de recherche…
Il s’intégre avec les principaux outils liés aux TU du marché : NUnit, MSTest, NDepend, et les servers d’Intégration Continue (MS Team Foundation Server, JetBrains TeamCity, CruiseControl.NET).
Il existe une alternative Open Source : PartCover.
Conclusion
Les outils cités dans cet article sont tous complémentaires et abordent chacun un aspect précis de la qualité du code. Tous ne sont pas nécessaires. Néanmoins, chacun trouve sa place dans une usine de développement logicielle. Il faut les voir comme un contrôle qualité automatisé qui participe à la création de logiciels mieux conçus et mieux développés. Comme dans tout processus agile, ils peuvent être implémentés progressivement.
Et surtout, ils doivent être compris et voulus par les développeurs. En effet, ces outils leur sont destinés, et ne seront réellement utiles que si les développeurs les estiment utiles.
A ce propos, Sonar et son plugin .NET forment un excellent orchestrateur : ils agrègent un ensemble de métriques calculées par les produits précédents dans une base de données, les historisent et les exposent via une interface web pour le suivi. Cela fera l’objet d’un article à part entière.