Contexte: Je suis un développeur d'entreprise dans une boutique All-MS.
Quelqu'un peut-il recommander un bon moyen de de mesurer objectivement la maintenabilité d'un morceau de code ou d'une application?
Pourquoi la maintenabilité : Je suis fatigué des métriques de "qualité" de mon groupe qui ne tourne que du nombre de bugs et de couverture de code. Les deux métriques sont faciles à jouer, en particulier lorsque vous ne mesurez pas la maintenabilité. Le shortSightness et les délais entraînent d'énormes quantités de dettes techniques qui ne sont jamais vraiment traitées.
Pourquoi la capacité de mesurer objectivement : je travaille dans un groupe de grand entreprise. Si vous ne pouvez pas le mesurer de manière objective, vous ne pouvez pas tenir les gens responsables de cela ou les rendre d'aller mieux à cela. Les mesures subjectives ne se produisent pas ou ne se produisent pas de manière cohérente.
Je regarde - Metrics de code VS201 , mais je me demande si quelqu'un a des autres recommandations.
La mise en garde avec la maintenabilité de mesure est que vous essayez de prédire l'avenir. CoDage de code, nombre de bugs, localisation, complexité cyclomatique toutes affaire avec le présent.
La réalité est que si vous n'avez que des preuves concrètes que le code n'est pas maintenu, comme ... la fixation d'un bug a causé n des heures d'heures de temps indispensable en raison du code non maintenable; Ensuite, avoir une jambe à rester debout sera intrinsèquement difficile. Dans cet exemple, il aurait pu être causé par le fait qu'une méthodologie trop complexe a été utilisée lorsque quelque chose de beaucoup plus simple aurait suffi. Naviguer dans une zone où vous essayez de mesurer les méthodologies, les paradigmes et les meilleures pratiques deviennent de plus en plus difficiles avec un gain peu à long terme.
En descendant ce chemin est malheureusement une route pour nulle part. Concentrez-vous sur la découverte des problèmes fondamentaux ayant un mérite substantiel et ne sont pas liés aux sentiments personnels concernant une question comme un manque de conventions de nommage dans la base du code et de trouver un moyen de mesurer le succès et les échecs autour de ce problème de racine. Cela vous permettra ensuite de commencer à organiser un ensemble de blocs de construction à partir desquels vous pouvez alors commencer à formuler des solutions autour.
Eh bien, la mesure que j'utilise ou aime penser que j'utilise, est-ce:
Pour chaque exigence fonctionnelle indépendante, unique, une ligne, une seule ligne, une seule ligne, instantanée la base de code avant de la mettre en œuvre. Ensuite, impliquez-la, y compris la recherche et la correction des bugs introduits dans le processus. Puis exécutez un diff
entre la base de code avant et après. Le diff
_ vous montrera une liste de toutes les insertions, suppressions et modifications qui ont mis en œuvre le changement. (Comme l'insertion de 10 lignes consécutives de code est un changer.) Combien de changements y avait-il? Plus le nombre est petit, c'est typiquement le plus maintenu le code.
J'appelle que le redondance du code source, car c'est comme la redondance d'un code de correction d'erreur. Les informations étaient contenues dans 1 morceau, mais ont été codées sous forme de n morks, qui doivent tous être faits ensemble, pour être cohérents.
Je pense que c'est l'idée derrière sec, mais c'est un peu plus général. La raison pour laquelle il est bon de pouvoir être faible est faible, si cela prend des modifications pour mettre en œuvre une exigence typique, et en tant que programmeur faillible, vous n'obtenez que N-1 ou N-2 de ceux-ci correctement effectués au début, vous avez mis 1 ou 2 bugs. En plus du O(N) Effort de programmation, ces bugs doivent être découverts, localisés et réparés. C'est pourquoi le petit n est bon.
Entretien ne signifie pas nécessairement lisible à un programmeur qui n'a pas appris le fonctionnement du 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, c'est si le programmeur tente d'anticiper les changements futurs et laisse comment les directions du programme du programme.
Je pense que lorsque n est suffisamment réduit (l'optimum est 1) Le code source lit plus comme une langue spécifique au domaine (DSL). Le programme ne signifie pas tant "résoudre" le problème que "indique" le problème, car idéalement, chaque exigence est juste retraité comme un seul morceau de code.
Malheureusement, je ne vois pas que les gens apprennent à faire cela beaucoup. Ils semblent plutôt penser que les noms mentaux devraient devenir des cours et que les verbes deviennent des méthodes, et tout ce qu'ils doivent faire, c'est transformer la manivelle. Cela entraîne un code avec N de 30 ou plus, dans mon expérience.
La main-d'œuvre n'est pas aussi mesurable. C'est une vue subjective d'une personne basée sur ses expériences et ses préférences.
Pour un morceau de code donne une idée d'une conception parfaite.
Ensuite, pour toute déviation du code réel de ce parfait, on diminue la valeur de 100 par un nombre. Par ce qui dépend exactement des conséquences d'une approche choisie non parfaite.
Un exemple:
Un morceau de code lit et importe un 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 endroit commun. Si votre solution les a bien codée sous forme de constantes de chaîne directement dans le code, vous prenez, dites 15 de rabais. Donc, votre indice de maintenabilité devient donc 85.
Un résultat du code difficile à maintenir est qu'il vous faudra plus longtemps (en moyenne ") pour résoudre des bugs. Ainsi, au premier coup d'œil, une métrique semblerait être le temps nécessaire pour corriger un bug de quand il est attribué (c'est-à-dire que le correctif est démarré) au moment où il est "prêt à tester".
Maintenant, cela ne fonctionnera pas vraiment après avoir réparé un nombre raisonnable de bogues pour obtenir la "moyenne" (quel que soit ce que cela signifie) temps. Vous ne pouvez pas utiliser le chiffre pour un bogue particulier car il est difficile de suivre la trajectoire ne dépend pas de la "maintenabilité" du code.
Bien sûr, lorsque vous réparez plus de bugs, le code devient "plus facile" de maintenir car vous le rendez mieux (ou au moins, vous devriez être) et que vous devenez plus familier avec le code. Contrairement à ce que le fait, les bugs tenteront d'être plus obscurs et donc encore plus difficiles à suivre.
Cela souffre également du problème que si les gens auront tendance à précipiter des corrections de bugs pour obtenir un score inférieur ainsi, ce qui entraîne de nouveaux bugs ou ne répartissant pas correctement l'existant menant encore plus de travail et éventuellement pire du code.
Je trouve les métriques de code Visual Studio pour être assez décente pour fournir une métrique "de la maintenabilité" rapide. 5 Les métriques principales sont capturées:
L'indice de maintenabilité est celui que je trouve pratique. C'est un indice composite, basé sur:
De temps en temps, je vais regarder mes méthodes avec un index de faible maintenabilité (faible = mauvais pour celui-ci). Presque sans échec, les méthodes de mon projet avec l'indice de maintenabilité le plus faible sont les plus nécessitant une réécriture et la plus difficile à lire (ou à maintenir).
Voir le papier blanc pour plus d'informations sur les calculs.
énormes quantités de dette technique qui ne sont jamais vraiment traitées
Qu'en est-il de la dette technique "dépassée par des événements"?
J'écris du code de merde et je me précipite dans la production.
Vous obserez - correctement - que ce n'est pas maintenu.
Ce code est cependant la dernière série de fonctionnalités d'une gamme de produits qui sera déclensé car le contexte juridique a changé et que la gamme de produits n'a pas d'avenir.
La "dette technique" est éliminée par un changement législatif qui rend tout obsolète.
La métrique "de la maintenabilité" est passée de "mauvais" à "non pertinents" en raison de considérations extérieures.
Comment cela peut-il être mesuré?
Deux qui seront significatifs sont significatifs complexité cyclomatique et couplage de classe. Vous ne pouvez pas éliminer la complexité, tout ce que vous pouvez faire est de la classer en pièces gérables. Ces 2 mesures devraient vous donner une idée de l'endroit où le code difficile à maintenir peut être localisé, ou du moins d'être le plus difficile.
La complexité cyclomatique est une mesure du nombre de chemins dans le code. Chaque chemin doit être testé (mais probablement pas). Quelque chose avec une complexité supérieure à environ 20 devrait être divisé en modules plus petits. Un module avec une complexité chycomatique de 20 (on pourrait dupliquer ceci avec 20 _ successifs if then else
Blocs) aura une limite supérieure de 2 ^ 20 chemins à tester.
Le couplage de classe est une mesure de la manière dont les classes sont étroitement liées. Un exemple de mauvais code que j'ai travaillé avec mon ancien employeur comprend un composant "couche de données" avec environ 30 éléments du constructeur. La personne "responsable" pour ce composant a permis d'ajouter des paramètres de couche d'entreprise et d'interface utilisateur aux appels constructeur/ouvert jusqu'à ce qu'il s'agisse d'une boule de boue vraiment grande. Si la mémoire me sert correctement, il y avait environ 15 nouveaux appels neufs/ouverts (certains autres utilisaient plus), tous avec des ensembles de paramètres légèrement différents. Nous avons mis en place des critiques de code dans le seul but de l'empêcher de faire plus de choses comme ça - et d'éviter de le faire ressembler à la sortie de l'équipe, nous avons examiné le code de chacun de l'équipe, nous avons donc perdu environ une demi-journée pendant 4-6 ans. Les gens chaque jour parce que nous ne voulions pas blesser les sentiments d'un idiot.
En fin de compte, la maintenabilité ne peut vraiment être mesurée que après requise, pas avant. C'est-à-dire que vous ne pouvez indiquer que si un morceau de code est maintenu, lorsque vous devez le maintenir.
Il est relativement évident de mesurer à quel point il était facile d'adapter un morceau de code à modifier les exigences. Il est proche de la mesure impossible à l'avance, de la manière dont elle répondra aux modifications des exigences. Cela signifierait que vous devez prédire les modifications des exigences. Et si vous pouvez le faire, vous devriez obtenir un prix Nobel;)
La seule chose que vous puissiez faire, c'est d'être d'accord avec votre équipe, sur un ensemble de règles concrètes (telles que SOLID principes), que vous croyez tous accroître généralement la maintenabilité.
[.____] Si les principes sont bien choisis (je pense aller avec SOLID _ serait un bon choix pour commencer par), vous pouvez manifester clairement qu'ils sont violés et que les auteurs responsables de cela.
[.
La meilleure chose à faire pour créer une architecture professionnelle avant de coder une unité ou un produit. Red-Green-Refactor est un moyen assez propre d'y aller. Avoir un mec Sr. jeter ensemble une interface de travail et diviser le travail. Tout le monde peut prendre leur morceau de puzzle et rouge-vert leur chemin à la victoire. Après cela, un examen et un refacteur de code par des pairs seraient en ordre. Cela a bien fonctionné bien sur un ancien produit majeur que j'ai travaillé.
Je trouve souvent que la solution "l'équivalente la plus courte" a tendance à être la plus maintenue.
Ici, le plus court signifie que les moins d'opérations (pas des lignes). Et équivalent signifie que la solution plus courte ne devrait pas avoir pire de temps ou de complexité de l'espace que la solution précédente.
Cela signifie que tous les modèles de répétition logiquement similaires doivent être extraits sur l'abstraction appropriée: des blocs de code similaires? Extraire-le à fonctionner. Variables qui semblent se produire ensemble? Extrayez-les dans une structure/classe. 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 dans de nombreux endroits? Calculez au début et stockez la valeur dans une variable. Cela entraînera un code plus court. C'est le DRY principe fondamentalement.
Nous pouvons également convenir que les abstractions inutilisées doivent être supprimées: les classes, les fonctions qui ne sont plus nécessaires sont du code mort. Il devrait donc être supprimé. Le contrôle de la version se souviendra si nous n'avions jamais besoin de le rétablir.
Ce qui est souvent débattu, des abstractions ne sont référencées qu'une fois: des fonctions non rappelées qui sont appelées une fois sans raison pour être appelées plus d'une fois. Un générique instancié à l'aide d'un seul type, et il n'y a aucune raison pour laquelle il sera instancié avec un autre type. Interfaces qui ne sont implémentées qu'une seule fois et qu'il n'y a pas de vraie raison pour laquelle il serait jamais mis en œuvre par une autre classe et ainsi de suite. Mon opinion que ces choses sont inutiles et devraient être supprimées, c'est fondamentalement le principe de Yagni.
Il devrait donc y avoir un outil capable de repérer la répétition de code, mais je pense que le problème est de trouver la compression optimale, qui est le problème de la complexité de Kolmogorov indéfinissable. Mais sur l'autre extrémité inutilisée et sous les abstractions utilisées sont faciles à repérer en fonction du nombre de références: une vérification de celle-ci peut être automatisée.
Tout est subjectif et toute mesure basée sur le code lui-même n'est finalement pas pertinente. À la fin, cela revient à votre capacité à répondre aux demandes. Pouvez-vous toujours livrer les fonctionnalités qui sont demandées et si vous le pouvez, à quelle fréquence ces changements vous reviendront-ils, car quelque chose n'est pas encore juste et à quel point ces problèmes sont-ils vraiment?
Je viens de (ré) la maintenabilité définie, mais c'est toujours subjectif. D'autre part, cela peut importer tout cela beaucoup. Nous devons juste satisfaire notre client et en profiter, c'est ce que nous visons.
Apparemment, vous sentez que vous devez prouver à votre patron ou vos collaborateurs que quelque chose doit être fait pour améliorer l'état de la base de code. Je dirais que cela devrait être suffisant pour que vous disiez que vous êtes frustré par le fait que, pour chaque petite chose que vous devez modifier ou vous ajouter, vous devez résoudre ou travailler environ 10 autres problèmes qui auraient pu être évités. Nommez ensuite une zone notoire et faites un étui pour le transformer à l'envers. Si cela n'engage aucun soutien dans votre équipe, vous pouvez être meilleur ailleurs. Si les gens autour de vous ne vous soucient pas, prouvant que votre argument ne va pas changer d'avis de toute façon.
questionnaire
Qu'en est-il de faire un questionnaire anonyme pour les développeurs, à remplir une fois par mois ou plus? Les questions iraient quelque chose comme:
(N'hésitez pas à ajouter des questions supplémentaires que vous jugez utiles pour mesurer la maintenabilité dans les commentaires et je les ajouterai.)
Je peux penser à deux façons de regarder la maintenabilité (je suis sûr qu'il y ait plus d'espoir que d'autres peuvent trouver de bonnes définitions.
Un correctif de bogue peut-il entrer dans le code et résoudre un problème sans avoir à comprendre comment fonctionne l'ensemble du système.
Cela peut être réalisé en fournissant des tests d'unités complètes (tests de régression). Vous devriez pouvoir vérifier que tout changement sur le système ne modifie pas la manière dont le système se comporte avec une bonne entrée spécifique.
Dans cette situation, un correctif de bug devrait être capable d'entrer et de réparer un bug (simple) avec seulement une connaissance minimale du système. Si le correctif fonctionne, alors aucun des tests de régression ne devrait échouer. Si des tests de régression échouent, vous devez passer à la phase 2.
maintainabilty1 = K1 . (Code Coverage)/(Coupling of Code) * (Complexity of API)
Si une solution de bogue devient non triviale et que vous devez comprendre le système. Alors quelle est la documentation du système comme. Nous sommes non Documentation parle de l'API externe (ils sont relativement inutiles). Ce que nous devons comprendre, c'est la manière dont le système fonctionne là où des astuces intelligentes (Lecture Hacks) utilisées dans les implémentations, etc.
Mais la documentation n'est pas suffisante, le code doit être clair et compréhensible. Pour mesurer la compréhensibilité d'un code, nous pouvons utiliser un petit tour. 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 dans une certaine mesure qu'une jetée peut désormais comprendre le système. Si le code est relativement facile à comprendre, il devrait être rapide. S'il est mal écrit, ils prendront plus de temps pour déterminer ce qu'ils ont construit et écrivent la documentation.
Alors peut-être que nous pourrions proposer une certaine mesure de cela:
maintainability2 = K2 . (Size of doc)/(Time to write doc)