Comment mesurer de manière significative la maintenabilité?

23

Contexte: je suis développeur d'entreprise dans une boutique 100% MS.

Quelqu'un peut-il recommander un bon moyen de mesurer objectivement la maintenabilité d'un morceau de code ou d'une application?

Pourquoi la maintenabilité : je suis fatigué des mesures de "qualité" dans mon groupe qui tournent uniquement autour du nombre de bogues et de la couverture du code. Les deux mesures sont faciles à jouer, surtout lorsque vous ne mesurez pas la maintenabilité. La myopie et les délais se traduisent par d'énormes montants de dette technique qui ne sont jamais vraiment résolus.

Pourquoi la capacité de mesurer objectivement : je travaille dans un grand groupe d'entreprises. Si vous ne pouvez pas le mesurer objectivement, vous ne pouvez pas en tenir les gens responsables ou les améliorer. Les mesures subjectives ne se produisent pas ou ne se produisent pas de manière cohérente.

Je regarde les métriques de code VS2010 , mais je me demande si quelqu'un a d'autres recommandations.

nlawalker
la source
@Anon - Je suis d'accord, mais au moins cela me donnerait un point de départ. Pour l'instant, il n'y a rien; il n'a même pas besoin d'être joué.
nlawalker le
1
Je ne vois vraiment pas comment vous pourriez faire cela sans revues de code par les pairs. Quelqu'un a besoin de vraiment comprendre la conception globale du système (et il doit en exister une) pour regarder une unité de code et aller ... ... Sur une note similaire, vous pouvez conserver des directives générales telles que "hé les gars ce n'est pas une bonne idée de coder en dur les index dans les vues de grille, d'utiliser des modèles d'élément et de sélectionner des colonnes par nom à la place". En fin de compte, les développeurs doivent être bons et faire équipe. Da Vinci ne peut pas enseigner la génialité.
P.Brian.Mackey
8
Si vous avez déjà des développeurs de mesures de jeu au lieu d'écrire du bon code, l'ajout de nouvelles mesures leur permettra également de jouer ces mesures, mais ne résoudra pas le problème . La solution est de supprimer entièrement les métriques et d'utiliser d'autres moyens (revues de code public, par exemple) pour assurer la qualité du code.
Anon.
3
"Tout ce qui peut être compté ne compte pas nécessairement; tout ce qui compte ne peut pas nécessairement être compté." -Einstein
Jason Baker
@nlawalker En plus des problèmes que les répondeurs ont déjà soulevés, votre question est chargée d'une hypothèse discutable, que si une telle mesure existait, les gens pourraient faire quelque chose. La faible maintenabilité est le résultat de divers facteurs externes au logiciel lui-même: la difficulté ou la définition du problème que le programme tente de résoudre, l'expérience du personnel, le chiffre d'affaires, les délais de mise sur le marché, les changements de portée ... vous ne pouvez tout simplement pas mettre une prime s'attendre à ce que le problème soit une question de bonne volonté.
Arthur Havlicek

Réponses:

7

La mise en garde concernant la mesure de la maintenabilité est que vous essayez de prédire l'avenir. La couverture du code, le nombre de bogues, le LOC, la complexité cyclomatique font tous face au présent .

La réalité est que, sauf si vous avez des preuves concrètes que le code n'est pas maintenable tel quel ... c'est-à-dire ... la correction d'un bogue a causé N heures de temps inutile en raison d'un code non maintenable; alors avoir une jambe sur laquelle se tenir sera intrinsèquement difficile. Dans cet exemple, cela pourrait être dû au fait qu'une méthodologie trop complexe a été utilisée alors que quelque chose de beaucoup plus simple aurait suffi. Entrer dans un domaine où vous essayez de mesurer les méthodologies, les paradigmes et les meilleures pratiques devient de plus en plus difficile avec peu ou pas de gain à long terme.

Suivre cette voie n'est malheureusement pas un chemin vers nulle part. Concentrez-vous sur la découverte de problèmes fondamentaux qui ont un mérite substantiel et qui ne sont pas liés à des sentiments personnels sur un problème tel qu'un manque de conventions de dénomination dans la base de code et trouvez un moyen de mesurer les succès et les échecs autour de ce problème racine. Cela vous permettra ensuite de commencer à assembler un ensemble de blocs de construction à partir desquels vous pourrez alors commencer à formuler des solutions.

Aaron McIver
la source
7

Eh bien, la mesure que j'utilise, ou que je pense utiliser, est la suivante:

Pour chaque exigence fonctionnelle indépendante, unique, d'une ligne, à prendre ou à laisser, prenez un instantané de la base de code avant de l'implémenter. Ensuite, implémentez-le, y compris la recherche et la correction de tous les bogues introduits dans le processus. Exécutez ensuite un diffentre la base de code avant et après. L ' diffaffiche une liste de toutes les insertions, suppressions et modifications qui ont implémenté la modification. (Comme l'insertion de 10 lignes de code consécutives est un changement.) Combien de changements y avait-il? Plus ce nombre est petit, généralement, plus le code est maintenable.

J'appelle cela la redondance du code source, car c'est comme la redondance d'un code correcteur d'erreurs. Les informations étaient contenues dans 1 bloc, mais ont été codées comme N blocs, qui doivent tous être faits ensemble, pour être cohérents.

Je pense que c'est l'idée derrière DRY, mais c'est un peu plus général. La raison pour laquelle il est bon que ce nombre soit faible est que, s'il faut N changements pour implémenter une exigence typique, et en tant que programmeur faillible, vous n'en faites que N-1 ou N-2 correctement au début, vous avez mis en 1 ou 2 bugs. En plus de l'effort de programmation O (N), ces bogues doivent être découverts, localisés et réparés. C'est pourquoi le petit N est bon.

Maintenable ne signifie pas nécessairement lisible, pour un programmeur qui n'a pas appris comment fonctionne le code. L'optimisation de N peut nécessiter de faire certaines choses qui créent une courbe d'apprentissage pour les programmeurs. Voici un exemple. Une chose qui aide est si le programmeur essaie d'anticiper les changements futurs et laisse des instructions pratiques dans le commentaire du programme.

Je pense que lorsque N est suffisamment réduit (l'optimum est 1), le code source ressemble davantage à un langage spécifique au domaine (DSL). Le programme ne «résout» pas tant le problème qu'il «énonce» le problème, car idéalement chaque exigence est simplement reformulée comme un seul morceau de code.

Malheureusement, je ne vois pas beaucoup de gens apprendre à faire cela. Ils semblent plutôt penser que les noms mentaux devraient devenir des classes, et les verbes devenir des méthodes, et tout ce qu'ils ont à faire est de tourner la manivelle. Cela résulte en un code avec N de 30 ou plus, d'après mon expérience.

Mike Dunlavey
la source
Cela ne fait-il pas une très grande supposition - que toutes les exigences fonctionnelles sont à peu près de la même taille? Et cette métrique ne découragerait-elle pas la séparation des responsabilités? J'ai besoin de mettre en œuvre une fonction horizontale; le code le plus "maintenable" est donc une réécriture presque totale d'un programme qui est entièrement contenu dans une méthode monolithique.
Aaronaught
@Aaronaught: Je ne sais pas à quel point c'est grand, mais dans notre groupe, nous travaillons sur des listes d'exigences / fonctionnalités, certaines interdépendantes, d'autres non. Chacun a une description relativement courte. Si cela prend une réécriture majeure, bien sûr que j'ai vu / fait ceux-ci, mais il me dit qu'il y avait probablement une meilleure façon d'organiser le code. Ceci est mon exemple canonique. Je ne dis pas qu'il est facile à apprendre, mais une fois appris, il économise une grande quantité mesurable d'efforts, permettant des changements rapides sans erreur.
Mike Dunlavey
5

La maintenabilité n'est pas vraiment mesurable. C'est une vue subjective d'un individu basée sur ses expériences et ses préférences.

Pour un morceau de code donné, venez avec une idée d'un design parfait .

Ensuite, pour toute déviation du code réel par rapport à celui parfait, diminuez la valeur de 100 d'un certain nombre. Par ce qui dépend exactement des conséquences d'une approche non parfaite choisie.

Un exemple:

Un morceau de code lit et importe un certain format de données et peut afficher un message d'erreur si quelque chose ne va pas.

Une solution parfaite (100) aurait des messages d'erreur conservés dans un seul endroit commun. Si votre solution les a codées en dur sous forme de constantes de chaîne directement dans le code, vous enlevez, disons 15 de moins. Votre indice de maintenabilité devient alors 85.


la source
4

Un résultat du code difficile à maintenir est que cela vous prendra plus de temps (en "moyenne") pour corriger les bogues. Ainsi, à première vue, une mesure semble être le temps nécessaire pour corriger un bogue à partir du moment où il est attribué (c'est-à-dire que le correctif est démarré) au moment où il est "prêt pour le test".

Maintenant, cela ne fonctionnera vraiment qu'après avoir corrigé un nombre raisonnable de bugs pour obtenir le temps "moyen" (quoi que cela signifie). Vous ne pouvez pas utiliser la figure pour un bug particulier, car la difficulté de la recherche ne dépend pas seulement de la "maintenabilité" du code.

Bien sûr, à mesure que vous corrigez davantage de bogues, le code devient "plus facile" à gérer à mesure que vous l'améliorez (ou du moins vous devriez l'être) et que vous vous familiarisez avec le code. Contrer cela, c'est que les bogues auront tendance à être plus obscurs et donc encore plus difficiles à localiser.

Cela souffre également du problème que si les gens ont tendance à précipiter les correctifs de bogues pour obtenir un score inférieur, provoquant ainsi de nouveaux bogues ou ne corrigeant pas correctement celui existant, ce qui entraîne encore plus de travail et peut-être encore pire de code.

ChrisF
la source
2

Je trouve que les métriques de code de Visual Studio sont assez décentes pour fournir une métrique de "maintenabilité" rapide. 5 mesures principales sont capturées:

  • Complexité cyclomatique
  • Profondeur de l'héritage
  • Couling de classe
  • Lignes de code (par méthode, par classe, par projet, peu importe, selon votre niveau de cumul)

L'indice de maintenabilité est celui que je trouve pratique. Il s'agit d'un indice composite, basé sur:

  1. Taille totale (lignes de code)
  2. Nombre de classes ou de fichiers
  3. Nombre de méthodes
  4. Complexité cyclomatique supérieure à 20 (ou 10 - configurable, 10 est ma préférence)
  5. Reproduction

De temps en temps, je vais regarder mes méthodes avec un faible indice de maintenabilité (faible = mauvais pour celui-ci). Presque sans faute, les méthodes de mon projet avec le plus faible indice de maintenabilité sont celles qui ont le plus besoin d'une réécriture et les plus difficiles à lire (ou à maintenir).

Voir le livre blanc pour plus d'informations sur les calculs.

Marcie
la source
1

Deux éléments qui seront significatifs sont la complexité cyclomatique et le couplage de classes. Vous ne pouvez pas éliminer la complexité, tout ce que vous pouvez faire est de la partitionner en morceaux gérables. Ces 2 mesures devraient vous donner une idée de l'endroit où se trouve le code difficile à maintenir, ou du moins où chercher le plus difficile.

La complexité cyclomatique est une mesure du nombre de chemins dans le code. Chaque chemin doit être testé (mais ne l'est probablement pas). Quelque chose d'une complexité supérieure à environ 20 devrait être divisé en modules plus petits. Un module avec une complexité cycomatique de 20 (on pourrait le dupliquer avec 20 if then elseblocs successifs ) aura une limite supérieure de 2 ^ 20 chemins à tester.

Le couplage de classes est une mesure de la façon dont les classes sont étroitement liées. Un exemple de mauvais code avec lequel j'ai travaillé chez mon ancien employeur comprend un composant "couche de données" avec environ 30 éléments dans le constructeur. La personne principalement «responsable» de ce composant a continué d'ajouter des paramètres de couche métier et d'interface utilisateur au constructeur / appels ouverts jusqu'à ce que ce soit vraiment une grosse boule de boue. Si la mémoire est bonne, il y a eu environ 15 appels nouveaux / ouverts différents (certains ne sont plus utilisés), tous avec des ensembles de paramètres légèrement différents. Nous avons institué des révisions de code dans le seul but de l'empêcher de faire plus de choses comme ça - et pour éviter de donner l'impression que nous le singularisons, nous avons examiné le code de tout le monde dans l'équipe, nous avons donc perdu environ une demi-journée pour 4-6 les gens chaque jour parce que nous n'avons pas

Tangurena
la source
2
Honnêtement, avoir des revues de code pour tout le monde n'est pas une mauvaise chose. Vous pouvez avoir l'impression de perdre du temps, mais à moins que tout le monde ne l'utilise comme excuse pour se détendre, vous devriez obtenir de précieuses informations de leur part.
Anon.
1

En fin de compte, la maintenabilité ne peut vraiment être mesurée qu'après avoir été demandée, pas avant . Autrement dit, vous ne pouvez dire, si un morceau de code est maintenable, quand vous devez le maintenir.

Il est relativement évident de mesurer à quel point il était facile d'adapter un morceau de code à des exigences changeantes. Il est presque impossible de mesurer à l'avance la façon dont il répondra aux changements des exigences. Cela signifie que vous devez prévoir les changements dans les exigences. Et si vous pouvez le faire, vous devriez obtenir un prix Nobel;)

La seule chose que vous pouvez faire est de convenir avec votre équipe d'un ensemble de règles concrètes (telles que les principes SOLIDES) qui, selon vous, augmentent généralement la maintenabilité.
Si les principes sont bien choisis (je pense qu'aller avec SOLID serait un bon choix pour commencer), vous pouvez très clairement démontrer qu'ils sont violés et tenir les auteurs responsables de cela.
Vous aurez beaucoup de mal à essayer de promouvoir une mesure absolue de maintenabilité, tout en convainquant progressivement votre équipe de respecter un ensemble convenu de principes établis et réalistes.

back2dos
la source
1

d'énormes dettes techniques qui ne sont jamais vraiment traitées

Qu'en est-il de la dette technique «dépassée par les événements»?

J'écris du code merdique et je le précipite en production.

Vous observez - correctement - que ce n'est pas maintenable.

Ce code, cependant, est la dernière série de fonctionnalités pour une gamme de produits qui sera déclassée car le contexte juridique a changé et la gamme de produits n'a pas d'avenir.

La "dette technique" est éliminée par une modification législative qui la rend obsolète.

La mesure de «maintenabilité» est passée de «mauvaise» à «non pertinente» en raison de considérations extérieures.

Comment cela peut-il être mesuré?

S.Lott
la source
"Dans cent ans, nous serons tous morts et rien de tout cela n'aura d'importance. Cela met les choses en perspective, n'est-ce pas?" S'il y a quelque chose de non pertinent, c'est cette réponse qui n'est pas une réponse à la question.
Martin Maat
0

La prochaine meilleure chose à faire pour un examen de code par les pairs est de créer une architecture fonctionnelle avant de coder une unité ou un produit. Red-green-refactor est une façon assez soignée de s'y prendre. Demandez à un gars principal de créer une interface fonctionnelle et de diviser le travail. Tout le monde peut prendre sa pièce du puzzle et red-green son chemin vers la victoire. Après cela, une révision du code par les pairs et une refonte seraient de mise. Cela a très bien fonctionné sur un produit majeur du passé sur lequel j'ai travaillé.

P.Brian.Mackey
la source
0

Questionnaire

Que diriez-vous de faire un questionnaire anonyme pour les développeurs, à remplir environ une fois par mois? Les questions iraient quelque chose comme:

  • Combien de temps le mois dernier avez-vous consacré au projet X (environ) [0% ... 100%]
  • Comment évalueriez-vous l'état de la base de code en termes de maintenabilité [vraiment médiocre, médiocre, neutre, correct, bon, vraiment bon].
  • Dans quelle mesure évalueriez-vous la base de code par rapport à la complexité du projet [trop complexe, juste, trop simplifié].
  • À quelle fréquence vous êtes-vous senti empêché de résoudre vos tâches en raison de la complexité excessive de la base de code? [pas du tout, de temps en temps, souvent, constamment].

(N'hésitez pas à ajouter des questions supplémentaires qui, selon vous, seraient utiles pour mesurer la maintenabilité dans les commentaires et je les ajouterai.)

Bjarke Freund-Hansen
la source
0

Je peux penser à deux façons d'envisager la maintenabilité (je suis sûr qu'il y a plus d'espoir que d'autres puissent trouver de bonnes définitions.

Modification sans compréhension.

Un correcteur de bogues peut-il entrer dans le code et résoudre un problème sans avoir besoin de comprendre comment fonctionne l'ensemble du système.

Ceci peut être réalisé en fournissant des tests unitaires complets (tests de régression). Vous devriez être en mesure de vérifier que toute modification du système ne change pas la façon dont le système se comporte avec une bonne entrée spécifique.

Dans cette situation, un réparateur de bogues devrait pouvoir venir corriger un bogue (simple) avec une connaissance minimale du système. Si le correctif fonctionne, aucun des tests de régression ne doit échouer. Si un test de régression échoue, vous devez passer à l'étape 2.

maintainabilty1 = K1 . (Code Coverage)/(Coupling of Code) * (Complexity of API)

Modification avec compréhension.

Si une correction de bogue devient non triviale et que vous devez comprendre le système. Alors, à quoi ressemble la documentation du système. Nous ne parlons pas de documentation de l'API externe (elles sont relativement inutiles). Ce que nous devons comprendre, c'est comment le système fonctionne là où des astuces intelligentes (lire les hacks) sont utilisées dans les implémentations, etc.

Mais la documentation ne suffit pas, le code doit être clair et compréhensible. Pour mesurer la compréhensibilité d'un code, nous pouvons utiliser une petite astuce. Une fois que le développeur a fini de coder, donnez-lui un mois pour travailler sur autre chose. Demandez-leur ensuite de revenir et de documenter le système à un point tel qu'une jetée peut maintenant comprendre le système. Si le code est relativement facile à comprendre, il devrait être rapide. S'il est mal écrit, il faudra plus de temps pour déterminer ce qu'il a construit et rédiger la documentation.

Alors peut-être que nous pourrions trouver une certaine mesure de ceci:

maintainability2 = K2 . (Size of doc)/(Time to write doc)
Martin York
la source
0

Je trouve souvent que la solution «équivalent le plus court» a tendance à être la plus maintenable.

Ici, le plus court signifie le moins d'opérations (pas de lignes). Et équivalent signifie que la solution la plus courte ne devrait pas avoir une complexité de temps ou d'espace pire que la solution précédente.

Cela signifie que tous les motifs répétitifs logiquement similaires doivent être extraits vers l'abstraction appropriée: blocs de code similaires? Extrayez-le pour fonctionner. Des variables qui semblent se produire ensemble? Extrayez-les dans une structure / classe. Des classes dont les membres ne diffèrent que par type? Vous avez besoin d'un générique. Vous semblez recalculer la même chose à plusieurs endroits? Calculez au début et enregistrez la valeur dans une variable. Cela entraînera un code plus court. C'est le principe DRY essentiellement.

Nous pouvons également convenir que les abstractions non utilisées doivent être supprimées: les classes, les fonctions qui ne sont plus nécessaires sont du code mort, donc elles doivent être supprimées. Le contrôle de version se souviendra si nous avons besoin de le rétablir.

Ce qui est souvent débattu, ce sont les abstractions qui ne sont référencées qu'une seule fois: des fonctions non-callback qui ne sont appelées qu'une seule fois sans aucune raison d'être appelées plus d'une fois. Un générique qui est instancié en utilisant un seul type, et il n'y a aucune raison qu'il soit jamais instancié avec un autre type. Interfaces qui sont implémentées une seule fois et il n'y a aucune raison réelle qu'elles soient implémentées par une autre classe, etc. Mon avis que ces choses sont inutiles et devraient être supprimées, c'est fondamentalement le principe YAGNI.

Il devrait donc y avoir un outil capable de repérer la répétition du code, mais je pense que ce problème revient à trouver la compression optimale, qui est le problème de complexité de Kolmogorov qui est indécidable. Mais à l'autre extrémité, les abstractions inutilisées et sous-utilisées sont faciles à repérer en fonction du nombre de références: une vérification pour cela peut être automatisée.

Calmarius
la source
0

Tout est subjectif et toute mesure basée sur le code lui-même est finalement hors de propos. En fin de compte, cela dépend de votre capacité à répondre aux demandes. Pouvez-vous toujours fournir les fonctionnalités qui sont demandées et si vous le pouvez, à quelle fréquence ces changements vous reviendront-ils parce que quelque chose ne va pas encore et à quel point ces problèmes sont-ils sérieux?

Je viens de (re) définir la maintenabilité mais elle reste subjective. D'un autre côté, cela n'a peut-être pas beaucoup d'importance. Nous avons juste besoin de satisfaire notre client et d'en profiter, c'est ce que nous visons.

Apparemment, vous sentez que vous devez prouver à votre patron ou à vos collègues que quelque chose doit être fait pour améliorer l'état de la base de code. Je dirais qu'il devrait être suffisant pour vous de dire que vous êtes frustré par le fait que pour chaque petite chose que vous devez changer ou ajouter, vous devez résoudre ou contourner 10 autres problèmes qui auraient pu être évités. Nommez ensuite une zone notoire et faites un étui pour la renverser. Si cela ne suscite aucun soutien dans votre équipe, vous pourriez être mieux ailleurs. Si les gens autour de vous s'en moquent, prouver que votre argument ne changera pas de toute façon leur avis.

Martin Maat
la source