Il y a beaucoup de réponses dans ma question précédente sur la simplicité concernant la lisibilité qui m'ont aidé à voir que ma définition et ma compréhension de la simplicité dans le code étaient, très probablement, incorrectes.
Comment puis-je définir la simplicité dans le code? Quelles mesures et mesures logicielles sont disponibles pour mesurer la simplicité du code?
code-quality
Richard
la source
la source
Réponses:
Les métriques les plus courantes pour mesurer la complexité (ou la simplicité, si vous considérez la simplicité comme l'opposé de la complexité) sont la complexité cyclomatique de McCabe et les métriques de complexité de Halstead .
La complexité cyclomatique mesure le nombre de chemins distincts à travers une unité donnée, généralement une méthode ou une fonction, bien qu'il puisse également être calculé sur une classe. À mesure que le nombre de chemins augmente, il devient plus difficile de se souvenir du flux de données à travers un module donné, qui est lié au concept de mémoire de travail . Une complexité cyclomatique élevée tend à indiquer une difficulté dans la capacité de tester un module - davantage de cas de test sont nécessaires pour couvrir les différents chemins à travers le système. Des études ont également établi un lien entre une complexité cyclomatique élevée et des taux de défauts élevés. Typiquement, une complexité cyclomatique de 10 indique qu'une unité doit être revue et éventuellement refactorisée.
Les mesures de complexité Halstead utilisent les entrées d'opérateurs et d'opérandes totaux et distincts pour calculer le volume, la difficulté et l'effort d'un morceau de code. La difficulté, qui est le (nombre d'opérateurs uniques / 2) * (nombre total d'opérandes / nombre d'opérandes uniques), est liée à la capacité de lire et de comprendre le code pour des tâches telles que l'apprentissage du système ou l'exécution d'une révision de code. Encore une fois, vous pouvez compter cela au niveau du système, au niveau de la classe ou au niveau de la méthode / fonction. Il y a quelques articles sur le calcul de ces mesures ici et ici .
Le simple fait de compter des lignes de code peut également vous donner une idée de la complexité. Plus de lignes de code signifie qu'il y a plus à lire et à comprendre dans un module. J'hésiterais à utiliser cela comme une mesure autonome. Au lieu de cela, je l'utiliserais avec d'autres mesures, telles que le nombre de défauts dans un module donné pour obtenir la densité des défauts. Une densité de défauts élevée peut indiquer des problèmes lors de l'écriture de tests et de la réalisation de révisions de code, qui peuvent ou non être causés par un code complexe.
L'entrée et la sortie sont deux autres mesures liées au flux de données. Comme défini ici , le fan in est la somme des procédures appelées, les paramètres lus et les variables globales lues et fan out est la somme des procédures qui appellent une procédure donnée, les paramètres écrits (exposés à des utilisateurs externes, transmis par référence), et les variables globales écrites dans. Encore une fois, une entrée et une sortie élevées peuvent indiquer un module qui peut être difficile à comprendre.
Dans des paradigmes spécifiques, il peut y avoir d'autres mesures ou paramètres qui sont également utiles. Par exemple, dans le monde orienté objet, la surveillance du couplage (désir faible), de la cohésion (désir élevé) et de la profondeur d'héritage (désir faible) peut être utilisée pour évaluer la simplicité ou la complexité d'un système.
Bien sûr, il est important de réaliser que de nombreuses mesures et métriques ne sont que des indicateurs. Vous devez utiliser votre jugement pour déterminer s'il est nécessaire de refactoriser pour augmenter la simplicité ou si cela ne vaut pas la peine de le faire. Vous pouvez effectuer les mesures, calculer les métriques et en savoir plus sur votre code, mais vous ne voulez pas concevoir votre système en fonction des chiffres. En fin de compte, faites ce qui a du sens.
la source
Au lieu de regarder un mode formel de définition de la simplicité, je voudrais plutôt définir la simplicité comme un attribut de la qualité de l'écriture de code.
Je ne mets pas une certaine mesure de simplicité mais quand appelez-vous quelque chose de simple ou non.
1. Traversée du code:
est-il facile de naviguer dans le code? Est-il facile de repérer où les fonctions API sont écrites? Est-il facile de comprendre les flux d'appels, par exemple quelles méthodes appellent les autres (et pourquoi) - y a-t-il de bonnes machines à états implémentées ou des algorithmes clairement identifiés?
Lorsque la traversée du code est facile, le code est simple à suivre.
2. Attribution de noms
Bien que d'autres normes de codage aident à rendre le code plus propre - la chose la plus importante est la dénomination des classes / instances-objet / Variables / méthodes. L' utilisation de noms clairs et sans ambiguïté a clairement un grand impact sur la simplicité du code. Lorsqu'il est difficile d'identifier un nom simple, c'est un signe que vous voudrez peut-être repenser l'idée étant cette variable / méthode.
3. Interprétation et références
Est-ce que chacune de vos méthodes a un rôle clair à jouer? Est-ce que chaque variable / attribut est facile à déterminer le rôle qu'ils jouent? Lorsqu'un morceau de code fait quelque chose qui implique des hypothèses ou affecte un ensemble de variables indépendantes, peut devenir un cauchemar de maintenance.
4. Dépendance ou couplage
Ceci est difficile à juger simplement en regardant le code, mais devient très évident si quelqu'un essaie de corriger vos bugs. Lorsque d'autres choses changent dans un autre objet, l'opération ici change-t-elle? Ces changements sont-ils évidents? Avez-vous besoin de changer l'API si souvent pour s'adapter à des choses? Ceux-ci suggèrent que les relations entre les modules ne sont pas simples
5. Entrées utilisateur ou applications
Enfin, dans quelle mesure les entrées utilisateur ou l'application sont-elles acceptées sur l'API / UI? Lorsque plusieurs utilisateurs / applications possibles (à des fins différentes) doivent vous donner - sont-ils évidents? Y a-t-il des états / détails qui ne sont pas liés à l'abstraction la plus élevée, mais qui continuent à faire reculer l'interface?
Une question simple que je poserais généralement est la suivante: si au lieu d'un programme, si j'avais demandé que la même fonction soit exécutée par un être humain, aurais-je rempli ces informations sur un formulaire papier ? Sinon, je ne suis pas assez simple ici.
Je ne dirai pas que cette liste est exhaustive, mais je suppose que le critère est la facilité ou la difficulté d'utilisation et de modification du logiciel. C’est simple.
la source
Je ne connais pas de bonnes mesures existantes pour la simplicité du code (cela ne signifie pas qu'elles n'existent pas - juste que je ne les connais pas). Je pourrais en proposer, peut-être que certains aideront:
Simplicité des fonctionnalités linguistiques utilisées: si la langue possède des fonctionnalités qui peuvent être considérées comme "avancées" et "simples", vous pouvez compter le nombre d'occurrences des fonctionnalités avancées. La façon dont vous définissez «avancé» pourrait être un peu plus subjective. Je suppose que certains pourraient dire que c'est aussi comme mesurer l'habileté d'un programme. Un exemple courant: certains pourraient dire que l'
?:
opérateur devrait être une fonction «avancée», d'autres pourraient être en désaccord. Je ne sais pas à quel point il serait facile d'écrire un outil qui puisse tester cela.Simplicité des constructions dans le programme: vous pouvez mesurer le nombre de paramètres qu'une fonction acceptera. Si vous avez> n % de toutes les fonctions avec> m paramètres, vous pouvez choisir de le considérer comme non simple, selon la façon dont vous définissez n et m (peut-être n = 3 et m = 6?). Je pense qu'il existe des outils d'analyse statique qui peuvent mesurer cela - je pense que JTest a simplement mesuré des fonctions avec> m paramètres.
Vous pouvez essayer de compter le nombre de boucles imbriquées ou de structures de contrôle. Je pense que ce n'est en fait pas une mauvaise métrique et je pense qu'il y a un nom (je ne me souviens pas du haut de ma tête). Encore une fois, je pense qu'il existe des outils (encore une fois, comme JTest) qui peuvent mesurer cela, dans une certaine mesure.
Vous pouvez essayer de mesurer la «refactorabilité». Si votre code contient beaucoup de morceaux de code qui pourraient être refactorisés mais ne le sont pas , cela ne pourrait peut-être pas être simple. Je me souviens aussi du temps où j'ai travaillé avec JTest qu'il a essayé de mesurer cela aussi, mais je me souviens que je n'étais pas souvent d'accord avec lui dans ce cas, donc YMMV.
Vous pouvez essayer de mesurer le nombre de couches entre différentes parties de votre système. Par exemple: combien de morceaux de code différents toucheront les données provenant d'un formulaire Web avant qu'elles ne soient stockées dans la base de données? Cela pourrait être difficile à mesurer correctement ...
la source
?:
sont un problème quand elles sont imbriquées à 5 profondeurs. Quant aux couches, les couches bien séparées valent mieux qu'une couche alambiquée. Mais 7 couches principalement redondantes, alors que seulement 2 ou 3 étaient nécessaires, c'est une mauvaise chose.