Accueil/Docs/Dette technique/CppDepend : estimation et gestion de la dette technique

CppDepend : estimation et gestion de la dette technique

Introduction

Aujourd'hui, la métaphore de la dette technique a été largement adoptée par l'industrie logicielle. Elle a été introduite par Ward Cunningham en 1992.

Ceci article de référence de Martin Fowler décrit la métaphore de la dette technique en grand détail. Pour citer M. Fowler :

Dans cette métaphore, faire les choses rapidement et salement nous charge d'une dette technique, qui est similaire à une dette financière. Comme une dette financière, la dette technique engendre intérêts paiements, qui prennent la forme de l'effort supplémentaire que nous devrons fournir dans le développement futur à cause du choix de conception rapide et sale. Nous pouvons choisir de continuer à payer les intérêts, ou nous pouvons rembourser le principal en refactorisant la conception rapide et sale vers la meilleure conception. Bien que rembourser le principal ait un coût, nous gagnons grâce aux paiements d'intérêts réduits à l'avenir.

Avec CppDepend, les règles de code peuvent être écrites via des requêtes LINQ C#. Appliquée sur une base de code, une règle produit des problèmes. Une API de dette dédiée est proposée pour estimer à la fois la dette technique et l'intérêt annuel du problème via des formules écrites en C#. La dette technique et l'intérêt annuel d'un problème sont tous deux mesurés en temps-homme.

  • Le dette-technique est le temps humain estimé nécessaire pour corriger le problème.
  • Le intérêt-annuel est le temps humain estimé consommé par an si le problème n'est pas corrigé. Cela fournit une estimation de impact métier du problème.

Par exemple :

warnif count > 0
from m in Methods
where m.CyclomaticComplexity > 10
select new {
   m,
   m.CyclomaticComplexity,
   Debt = (3*(m.CyclomaticComplexity-10)).ToMinutes().ToDebt(),
   AnnualInterest = (m.PercentageCoverage == 100 ? 10 : 120).ToMinutes().ToAnnualInterest()
}

Dans cet exemple, la règle correspond aux méthodes trop complexes, la complexité étant mesurée via Complexité cyclomatique métrique de code. Nous voyons que :

  • Le dette-technique est proportionnelle à la complexité au-delà d'un certain seuil.
  • Le intérêt-annuel est de 10 minutes par an si la méthode est couverte à 100 % par les tests, sinon 2 heures par an.

Laisser une méthode complexe à la fois non refactorisée et non couverte par les tests est une situation propice aux erreurs. Au mieux, une telle situation nuit à la maintenabilité du code, au pire elle se termine par des bogues en production. L'intérêt annuel estime le moyen coût par an si la méthode complexe n'est pas refactorée. Cela s'aggrave si la méthode n'est pas non plus couverte par les tests. Le mot moyen est mis en évidence ici du fait que, par exemple, sur 8 méthodes complexes et non testées, une seule peut-être contient un bogue qui coûtera 2 jours de travail humain (2x8 heures) pour être découvert, investigué, corrigé et livré.

Chaque règle de l'ensemble de règles par défaut contient des formules pour calculer la dette technique et l'intérêt annuel de chaque problème. Les règles et formules peuvent être créées et personnalisées pour mieux correspondre aux besoins et habitudes de vos équipes, car il s'agit simplement de C# brut qui peut être édité dans Visual Studio. Le principal avantage est que l'estimation de la dette technique est entièrement transparente et facilement personnalisable avec CppDepend.

Intérêt annuel et gravité

L’intérêt annuel est une mesure d’un gravité du problème. La sévérité et l'intérêt annuel représentent le même concept où l'intérêt annuel est une mesure continue tandis que la sévérité est une mesure discrète.

CppDepend définit 5 niveaux de sévérité, et la sévérité d'un problème est estimée via des seuils basés sur l'intérêt annuel.

  • Faible : Un problème avec un niveau de sévérité Low représente une petite amélioration, une façon de rendre le code plus élégant. Seuil Annual Interest par défaut : zéro ou moins de 2 minutes-homme par an.
  • Moyen : Un problème avec un niveau de sévérité Medium représente un avertissement pour un problème qui, même s'il n'est pas corrigé, n'aura pas d'impact significatif sur le développement. Seuil Annual Interest par défaut : moins de 20 minutes-homme par an.
  • Élevé : Un problème avec un niveau de sévérité High devrait être corrigé rapidement, mais peut attendre le prochain intervalle planifié. Seuil Annual Interest par défaut : moins de 2 heures-homme par an.
  • Critique : Un problème avec un niveau de sévérité Critical ne devrait pas passer en production. Cela reste possible pour des impératifs commerciaux, mais il doit au pire être corrigé lors des prochaines itérations. Seuil Annual Interest par défaut : moins de 10 heures-homme par an.
  • Bloquant: Un problème avec un niveau de sévérité Blocker ne peut pas passer en production, il doit corrigés. Seuil d'intérêt annuel par défaut : plus de 10 heures-homme par an.

Notez que la notion de problème critique est différent de la notion de règle critique. La sévérité d'un problème n'est pas liée au fait que sa règle soit critique ou non. Une règle peut être marquée comme critique pour imposer une contrainte sur elle, par exemple on peut écrire un quality gate qui échoue en cas de violation de règle critique.

Règles critiques

Paramètres de dette

Le calcul et les résultats de la dette technique peuvent être affinés via les paramètres du panneau CppDepend > Propriétés du projet > Issues and Debt.

Paramètres de dette technique CppDepend

Vous voyez :

  • Seuils relatifs à la sévérité des problèmes et à l'intérêt annuel, expliqués dans la section précédente
  • Seuils relatifs à la note de dette SQALE, expliqués dans la section suivante
  • Deux facteurs multiplicatifs qui peuvent être appliqués à toutes les valeurs estimées de dette technique et d'intérêts annuels. Par défaut, ces facteurs sont fixés à 1.
  • Pour s'assurer que les estimations de dette sont affichées en mesures de temps humain significatives, les paramètres concernant nombre d’heures de travail par jour ou nombre de jours ouvrés par an peut être ajusté.
  • Il existe aussi des paramètres pour choisir comment les valeurs de dette sont formatées et pour convertir valeurs de dette en temps-homme dans valeurs de dette en coût monétaire.
valeurs de dette en temps-homme

Ratio de dette et note de dette SQALE

Le Méthode SQALE (communément prononcé « scale ») est une méthode standardisée pour évaluer la dette technique. CppDepend implémente Ratio de dette et le Note de dette qui font partie de la méthode SQALE.

Le Ratio de dette sur une base de code, ou sur un élément de code, est exprimé en pourcentage de la dette technique estimée, comparé à l'effort estimé qu'il faudrait pour réécrire l'élément de code à partir de zéro. L'effort estimé pour réécrire l'élément de code à partir de zéro est déduit de la taille de l'élément de code en lignes de code, et du paramètre de dette nommé Nombre estimé de jours-homme pour développer 1 000 lignes de code logiques (voir la capture d'écran dans la section précédente sur les paramètres de dette).

La valeur du Nombre estimé de jours-homme pour développer 1 000 lignes de code logiques paramètre n'est qu'une estimation, donc à court terme il n'a pas de sens. Après quelques mois-homme, voire années-homme de développement, cette valeur est généralement suffisamment stable pour être fiable à des fins d'estimation. Ce paramètre estimé doit également prendre en compte le coût d'écriture des tests unitaires. La valeur par défaut est de 18 jours-homme, ce qui représente une moyenne de 55 nouvelles lignes de code logiques, 100 % couvert par des tests unitaires écrites par jour, par développeur.

Le Note de dette d'une base de code ou d'un élément de code est déduit de seuils appliqués au Debt Ratio. Le Debt Rating est dans la plage A, B, C, D, E. Les quatre seuils sont personnalisables dans le panneau des paramètres de dette (voir la capture d'écran dans la section précédente sur les paramètres de dette). Les seuils par défaut sont :

  • [ 0 , 5 % [ de Debt Ratio conduit à une note de dette A.
  • [ 5 % , 10 % [ de Debt Ratio conduit à une note de dette B.
  • [ 10 % , 20 % [ de Debt Ratio conduit à une note de dette C.
  • [ 20 % , 50 % [ de Debt Ratio conduit à une note de dette D.
  • 50 % ou plus de Debt Ratio conduisent à une note de dette E.

Les valeurs Debt Rating et Debt Ratio de la base de code sont affichées dans le tableau de bord. Dans la section Parcourir la dette technique nous montrerons que de simples requêtes de code C# peuvent afficher les valeurs Debt Ratio et Rating pour tout élément de code.

Tableau de bord CppDepend et note de dette

Prioriser les corrections de problèmes et la métrique Breaking-Point

Le Point de rupture d'un problème ou d'un ensemble de problèmes, est le point dans le temps à partir duquel le coût estimé pour corriger le(s) problème(s) atteindra le coût estimé pour laisser le(s) problème(s) non corrigé(s).

Le point de rupture est le dette divisée par l’intérêt annuel. Par exemple, si le coût estimé pour rembourser la dette est de 10 jours-homme et que l'intérêt annuel estimé est de 2 jours-homme par an, alors le point de rupture est égal à 5 ans à partir de maintenant.

Notez qu’un point de rupture qui est inférieur à par an signifie que, durant les 12 prochains mois, il est estimé qu'il serait moins coûteux de corriger la dette que de ne pas la corriger.

Notez également qu'un point de rupture n'est pas mesuré en temps-homme comme la dette ou l'intérêt annuel (un mois-homme ou une année-homme), mais plutôt en durée régulière (mois ou années). Les valeurs de point de rupture sont typées avec TimeSpan.

Quand il s’agit de prioriser les problèmes à corriger en premier, la sévérité du problème est un paramètre important. Pour rappel : la sévérité est la mesure discrète de l'intérêt annuel. Par conséquent, plus l'intérêt annuel est élevé, plus il est important de corriger.

Cependant, pour un niveau de sévérité donné, tous les problèmes ne sont pas égaux. Certains demanderont plus d'efforts à corriger. Cela est estimé via la mesure de la dette technique. Par conséquent, pour estimer le Retour sur investissement (ROI) d'une correction de problème, il est logique d'estimer la dette divisée par l'intérêt annuel. Cette estimation est le point de rupture pour lequel plus la valeur est faible, plus le ROI est élevé.

Précisons que dans l'ensemble des règles par défaut, les problèmes relatifs à de nouveaux problèmes depuis la baseline, comme changements cassants d’API, qualité des éléments de code qui se dégrade encore, nouveaux éléments de code non testés... sont des problèmes qui produisent un intérêt annuel plus élevé, et donc une sévérité plus élevée que les autres problèmes. Cela est conforme à la bonne pratique consistant à corriger d'abord les problèmes récemment introduits.

Priorité de correction des problèmes

Parcourir la dette technique

Dans l’introduction, nous avons vu que les règles de code sont implémentées via des requêtes LINQ C# et nous avons aussi vu que les estimations de dette et d'intérêt annuel sont déduites de formules embarquées dans ces requêtes LINQ.

Ceci Schéma de requêtes LINQ C# va plus loin et peut être utilisé pour parcourir et explorer la dette technique. Le domaine Problèmes est une énumération de tous les problèmes trouvés dans la base de code. Évidemment, les requêtes qui reposent sur ce domaine sont exécutées après que toutes les règles ont été exécutées.

Par exemple, en cliquant sur un nombre de problèmes sur le tableau de bord, comme nouveaux problèmes majeurs depuis la baseline dans l'exemple ci-dessous, une requête de code est générée pour lister les problèmes pertinents. Notez que les problèmes peuvent être groupés par règles ou par éléments de code. Dans la capture d'écran ci-dessous, les problèmes sont groupés par règle.

Problèmes majeurs depuis la baseline

Remarquez le menu Explore Debt sur le Dashboard, qui génère des requêtes sur les règles, les problèmes et les éléments de code pour explorer en profondeur la dette technique.

Menu Explorer la dette du tableau de bord

Clic droit sur Catégorie de règles, comme le Couverture de code catégorie ici, affiche des menus pour interroger les problèmes de cette catégorie :

Sélectionner les problèmes par catégorie

Certaines requêtes par défaut de dette et de problèmes se trouvent dans Points chauds groupe. Par exemple la requête Points chauds de types liste d’abord les types avec le plus de dette.

Points chauds de types

Le Règles domaine est une énumération de toutes les règles actives. Il liste les règles enfreintes comme non enfreintes. Des requêtes peuvent être écrites pour lister les règles par dette et nombre de problèmes. Les règles correspondantes peuvent être groupées par catégories.

Sans surprise, la couverture, la qualité du code et l'architecture sont des catégories qui génèrent souvent le plus de dette et de problèmes.

Dette et problèmes par règle

La baseline joue un rôle majeur lorsqu'il s'agit d'explorer l'ensemble des problèmes, car les problèmes nouveaux ou corrigés depuis la baseline évaluent la qualité du travail récent.

Par défaut, la baseline est le résultat d'analyse historique le plus proche d'il y a 30 jours et, par défaut, un résultat d'analyse historique est conservé au maximum une fois par jour.

Parce que lors de l'évaluation de la qualité du travail récent, on voudra certainement jongler entre les baselines d'hier, de la semaine dernière et du mois dernier, le tableau de bord CppDepend vous permet d'appliquer une temporaire baseline en un seul clic. L'ensemble de la dette et des problèmes est alors recalculé en quelques secondes en conséquence.

Choisir une baseline temporaire

Et comme l'évaluation des problèmes et de la dette depuis la baseline est importante, comme nous venons de le voir, tous Points chauds les requêtes par défaut sont fournies avec depuis la baseline version. Par exemple, voici une requête pour évaluer Nouvelle dette et problèmes par règle depuis la baseline.

Nouvelle dette et problèmes par règle

Mentionnons une subtilité en matière de requêtes sur la dette et les problèmes. Les types contiennent des méthodes et des champs, les namespaces contiennent des types et les assemblys contiennent des namespaces. Ainsi, les types, namespaces et assemblys sont des parents d'éléments de code.

Tous les éléments liés aux problèmes ICodeElement méthodes d’extension comme elem.Debt(), elem.AnnualInterest(), elem.Issues(), dont la version commence par Tous qui renvoie la dette et les problèmes pour l'élément de code parent et tous ses éléments enfants. D'où :

  • elem.AllIssues() retourne une énumération des problèmes dans l'élément de code parent et des problèmes sur ses éléments de code enfants. Dans le produit, nous utilisons parfois la terminologie problèmes cumulés d'un élément de code parent comme un assembly, un namespace ou un type.
  • elem.AllDebt() renvoie la dette estimée cumulée pour l'élément de code parent et ses éléments enfants.
  • elem.AllAnnualInterest() renvoie l'intérêt annuel estimé cumulé pour l'élément de code parent et ses éléments enfants.
  • elem.AllBreakingPoint() renvoie le breaking-point estimé pour l'élément de code parent et ses éléments enfants.

Dette technique et quality gate

Vous trouverez des Quality Gates par défaut relatifs à la dette technique et aux problèmes, notamment Pourcentage de dette, Nouvelle dette depuis la baseline ou Nouveaux problèmes bloquants / critiques / majeurs. Les quality gates relatifs à la valeur absolue de la dette technique sont désactivés par défaut car les seuils appropriés ne peuvent être définis que dans le contexte d'un projet particulier.

Édition des quality gates

De la même façon Problèmes et Règles sont prédéfinis comme des domaines interrogeables fournissant une énumération de problèmes ou de règles, le domaine QualityGates est une énumération de quality gates. La requête par défaut ci-dessous estime la tendance des quality gates depuis la baseline. Notez que les quality gates qui reposent sur la baseline (comme Nouvelle dette depuis la baseline) n'ont ni valeur ni statut définis sur la baseline.

Évolution des quality gates

Raisons pour lesquelles la dette technique peut être nulle ou incomplète

  • Mon estimation de dette technique affiche zéro ou ?
    Si la dette technique est zéro ou ?, vous analysez probablement un projet créé avec une version plus ancienne de CppDepend (v6 ou inférieure). L'ensemble de règles des versions précédentes de CppDepend n'avait pas de formules de dette, et donc par défaut, les problèmes sans formules de dette ont une dette nulle.
    Dans le Tableau de bord > panneau Dette vous devriez voir un lien nommé Créez un fichier de règles avec les règles par défaut.
    Créez un fichier de règles avec les règles par défaut
    Cliquer sur ce lien créera automatiquement un fichier de règles contenant toutes les nouvelles règles par défaut, celles avec des formules d'estimation de la dette. Une fois fait, il est recommandé de remplacer les règles actuelles du projet par les règles qui estiment la dette technique. Pour cela, le glisser-déposer peut être utilisé depuis le Explorateur de requêtes et règles panneau (à la fois pour les règles et pour les groupes de règles). Notez que les formules de dette provoquent des erreurs de compilation de règles lorsqu'elles sont lues par des versions antérieures de CppDepend (v6 et inférieures). Si vous prévoyez d'utiliser ce projet depuis CppDepend v6 ou inférieur, veuillez d'abord le cloner.
    Pour les règles personnalisées, nous recommandons de modifier leur code source pour écrire des formules d'estimation de dette personnalisées.
    Enfin, veuillez noter que le fichier de règles par défaut sera créé dans le même répertoire que le fichier projet et sera attaché au projet avec un chemin de fichier relatif. Ce chemin peut être modifié depuis Propriétés du projet CppDepend > Paths Referenced.
  • Mon estimation de dette technique est incomplète car aucune donnée de couverture de code n'a été fournie
    Le code non testé, ou partiellement testé par des tests unitaires, représente une grande source de dette technique. En fait, chaque ligne de code non couverte par les tests contribue à la dette technique. C'est pourquoi la section Debt du tableau de bord affiche un message d'avertissement lorsque import de fichiers de couverture n’est pas configuré dans le projet CppDepend.
    Dette incomplète car aucune donnée de couverture spécifiée
  • Données de couverture de code non disponibles sur la baseline
    Lorsque la couverture de code est disponible dans le résultat d'analyse actuel mais pas dans le résultat d'analyse de la baseline, les règles liées à la couverture de code ne produisent pas de problèmes. En effet, dans cette situation, les problèmes de couverture ne peuvent pas être estimés sur la baseline et tous les problèmes de couverture apparaîtraient alors comme nouveaux.
    Souvent, cette situation apparaît lorsqu'un projet a été créé et que le premier résultat d'analyse obtenu ne contient pas de données de couverture. Dans le projet CppDepend, le paramètre de baseline par défaut consiste à choisir le résultat d'analyse de baseline le plus proche de obtenue il y a 30 jours, donc ce problème pourrait persister pendant un mois.
    Généralement pour corriger cette situationnous conseillons de vous débarrasser des résultats d'analyse de l'historique qui n'ont pas de données de couverture de code. Pour cela, vous devez ouvrir le dossier contenant les résultats d'analyse de l'historique défini dans Propriétés du projet CppDepend > Analysis > Baseline for Comparison > Historic Analysis Results (par défaut défini sur le dossier de sortie du projet). Identifiez ensuite le dossier contenant le résultat d'analyse de l'historique à supprimer et supprimez simplement le dossier.
    Par exemple, dans la capture d'écran ci-dessous, le dossier sélectionné représente le résultat d'analyse de l'historique obtenu le 13 décembre 2016 à 8 h 59.
    Aucune date de couverture disponible sur la baseline
    Nous comprenons que cette manipulation manuelle de dossiers n'est pas la façon optimale de résoudre une telle situation. Si vous souhaitez que nous fournissions une interface qui listerait les résultats d'analyse de l'historique, qui montrerait ceux qui n'ont pas de données de couverture (ou d'autres défauts comme du code source non résolu), et qui permettrait de les supprimer.
    Nous pourrions également fournir un filtre au moment de l'analyse qui ne conserverait pas un résultat d'analyse dans l'historique s'il ne satisfait pas certains critères (comme la disponibilité des données de couverture).

Essayez CppDepend aujourd'hui

Commencez votre essai gratuit de 14 jours avec accès complet à toutes les fonctionnalités de documentation. Sans carte bancaire.