Pourquoi la complexité cyclomatique est-elle si importante pour une seule méthode?

10

J'utilise SonarLint pour Eclipse depuis récemment, et cela m'a beaucoup aidé. Cependant, cela m'a posé une question sur la complexité cyclomatique.

SonarLint considère comme acceptable un CC de 10, et il y a des cas où je suis au-delà, environ 5 ou 6 unités. Ces parties sont liées aux mappeurs où les valeurs dépendent de différentes variables, par exemple:

  • Le champ A repose sur String sA;
  • Le champ B repose sur String sB;
  • Le champ C repose sur String sC;
  • etc ...

Je n'ai pas d'autre choix que de mettre un ifpour chaque domaine. Ce n'est pas mon choix (heureusement) mais un système déjà existant et complexe que je ne peux pas changer par moi-même.


Le cœur de ma question est: pourquoi est-il si important de ne pas avoir un CC trop élevé dans une seule méthode ? Si vous déplacez certaines de vos conditions dans une ou plusieurs sous-méthodes pour réduire la complexité, cela ne réduit pas le coût de votre fonction globale, cela déplace simplement le problème ailleurs, je suppose?

(Désolé pour les petites erreurs, le cas échéant).


ÉDITER

Ma question ne se réfère pas à la complexité cyclomatique globale, mais seulement à la complexité d'une méthode unique et au fractionnement de la méthode (j'ai du mal à expliquer ce que je veux dire exactement, désolé). Je demande pourquoi est-il permis de diviser vos conditions en méthodes plus petites si elle appartient toujours à une `` super méthode '', qui exécutera simplement chaque sous-méthode, ajoutant ainsi de la complexité à l'algorithme.

Le deuxième lien cependant ( sur l'anti-modèle ) est d'une grande aide.

Yassine Badache
la source
^^^ La question de la "tête de flèche" est probablement un meilleur doublon dans le sens où elle explique comment améliorer votre code mais j'ai choisi la première en raison d' une explication détaillée répondant à la partie de votre question sur la complexité cyclomatique
moucheron
La division d'une méthode en parties plus petites ne réduit pas la quantité totale de code exécutée mais rend évidentes les tâches individuelles qui se produisent; ils peuvent chacun être compris beaucoup plus facilement individuellement que lorsqu'ils sont tous emmêlés dans un tout plus grand. À tout le moins, elle supprime de nombreuses variables intermédiaires à usage unique de la plus grande portée.
Doval
1
Pour votre cas particulier décrit, je ferais quelque chose dans votre méthode principale comme "A = extractAFrom (sA);" pour chaque champ. Vous pouvez probablement trouver de meilleurs noms puisque vous connaissez les champs réels et leurs utilisations.
Tin Man

Réponses:

32

L'essentiel ici: la «capacité cérébrale».

Vous voyez, l'une des principales fonctions du code est ... d'être lu . Et le code peut être facile à lire et à comprendre; ou dur.

Et avoir un CC élevé implique simplement beaucoup de «niveaux» dans une même méthode. Et cela implique: en tant que lecteur humain, vous aurez du mal à comprendre cette méthode.

Lorsque vous lisez le code source, votre cerveau essaie automatiquement de mettre les choses en perspective: en d'autres termes - il essaie de créer une certaine forme de "contexte".

Et quand vous avez une petite méthode (avec un bon nom) qui ne se compose que de quelques lignes et d'un CC très bas; alors votre cerveau peut facilement accepter ce "blocage". Vous le lisez, vous le comprenez; TERMINÉ.

D'un autre côté, si votre code a un CC élevé, votre cerveau passera de nombreux "cycles" de plus pour déduire ce qui se passe.

Une autre façon de dire cela: vous devriez toujours pencher pour préférer un réseau complexe de choses simples à un simple réseau de choses complexes. Parce que votre cerveau comprend mieux les petites choses.

GhostCat salue Monica C.
la source
9
Donc, fondamentalement, il ne s'agit pas de problèmes techniques , mais d' humains ? Cela semble, en effet, un peu intelligent, je ne sais pas comment je n'y avais pas pensé auparavant. Merci !
Yassine Badache
4
Si c'est le cas, je vous recommande de tout coeur d'acquérir "Clean Code" par Robert Martin (vous pouvez trouver le pdf gratuitement sur les filets). Vous voyez, la création de code lisible est l'une des vertus les plus importantes mais très souvent ignorées d'un bon programmeur.
GhostCat salue Monica C.
@YassineBadache CC rend également difficile de tester tous les coins et recoins (couverture complète).
Tulains Córdova
C'était aussi le nœud du papier goto de Dijkstra .
Seth Battin
D'après mon expérience, les bogues sont presque toujours dans les méthodes avec un CC élevé et lorsque les bogues sont dans une méthode à faible CC, ils sont généralement totalement évidents, aucun moyen pour eux de se cacher après la première exécution du code. De plus, je trouve que je n'ai presque jamais à modifier une méthode à faible CC - plus de charge prélevée sur le cerveau.
Loren Pechtel
6

CC, comme toutes les autres règles de base pour les odeurs de code, est une heuristique . Ce n'est pas un critère de sécurité qui vous dit une vérité absolue. Si tel était le cas, la chose raisonnable à faire serait simplement de rendre ces méthodes illégales dans la langue et d'obliger les gens à atteindre leurs fins d'une autre manière.

Mais ce n'est pas ainsi que fonctionnent les indicateurs. La plupart du temps, leur fonction est d'alerter les gens sur des choses dont ils n'étaient pas au courant. Dans votre cas, vous savez que la logique est alambiquée et que les solutions alternatives la rendraient encore plus alambiquée. Par conséquent, il est inutile d'essayer de satisfaire la règle empirique primitive, alors que son objectif principal est d'émettre des avertissements aux personnes qui ne sont pas conscientes de l'existence d'un problème.

Kilian Foth
la source
2
Si "FieldA s'appuie sur String sA" comme le déclare OP, je ne suis pas convaincu que le déplacer dans un CalculateFieldA (String sA) rend le code plus alambiqué.
Taemyr
2

En bref: tout est question de lisibilité et donc de maintenabilité de votre code.

Si vous avez une méthode longue et complexe avec beaucoup de (imbriqués) if, il devient difficile de dire ce qu'elle fait réellement. Si vous extrayez des méthodes privées et les nommez de manière significative, c'est beaucoup plus facile.

André Stannek
la source
Bien que ce soit une bonne réponse, elle est un peu courte. Ce serait bien si vous pouviez fournir un exemple de ce que vous dites et être plus précis concernant la question posée par OP: "pourquoi est-il si important de ne pas avoir un CC trop élevé dans une seule méthode?".
Machado
2

La complexité cyclomatique d'une méthode est liée au nombre de cas de test requis pour une méthode. Plus précisément, une complexité cyclomatique de 10 signifie que 10 est la limite supérieure pour que les cas de test aient une couverture de branche totale pour votre méthode. Il est également lié au nombre de chemins qui doivent être testés, moins tous les chemins impossibles.

Au-delà de cela, je suis d'accord avec les autres réponses pour d'autres considérations - la capacité mentale d'un développeur ou un indicateur de problèmes potentiels ou de refactoring ou une mesure de lisibilité et de maintenabilité du code .

Thomas Owens
la source
0

CC est juste une heuristique, et à quel point un score particulier est «mauvais» dépend de beaucoup de choses.

Cela dit, vous devez toujours voir un CC élevé comme quelque chose qui met en évidence le code qui pourrait / devrait être refactorisé. Vous dites que le déplacement de l' ifinstruction vers une autre méthode cache le problème - mais y a-t-il un modèle que vous pouvez résumer au lieu de copier-coller n fois? S'il s'agit d'une longue if-elsechaîne, pouvez-vous la transformer en une instruction switch, ou peut-être utiliser le polymorphisme, ou autre chose? S'il y a imbrication profonde, certaines de vos clauses conditionnelles peuvent-elles être jointes, ou cela indique-t-il des responsabilités distinctes qui devraient être divisées en différentes classes?

GoatInTheMachine
la source
0

Je vois la complexité cyclomatique comme un avertissement. Si vous pouvez lire le code et qu'il n'est pas trop complexe à comprendre, je ne m'inquiéterais pas trop à ce sujet, il y a probablement des choses plus importantes à éviter, il y en a toujours.

Une façon de réduire le type de CC que vous mentionnez est d'utiliser le polymorphisme, car vous avez marqué votre question avec la balise Java. Ainsi, au lieu que les chemins de code soient typés en chaîne, vous pouvez utiliser des classes bien nommées. Cela peut aider, mais est parfois excessif et peut rendre votre code encore plus difficile à comprendre.

Cependant, cela peut être un signe de code qui sera difficile à maintenir. Lors de la lecture de la méthode, est-il facile de voir quel chemin de code emprunter pour chaque cas? Pourriez-vous ignorer cette méthode si vous ne connaissez pas bien la base de code et recherchez quelque chose de connexe mais plus loin dans le code? Je sais que certaines personnes préconisent de fractionner les méthodes en de nombreuses méthodes 1/2 ligne avec des noms descriptifs, mais parfois je pense que c'est encore plus difficile à lire que le code qu'il était censé remplacer.

En fin de compte, la maintenabilité est un problème difficile et c'est à vous de décider ce qui, selon vous, sera plus facile à lire. Le fait que vous y réfléchissiez signifie que vous êtes sur la bonne voie. N'oubliez pas que le responsable qui doit essayer de déchiffrer ce code dans un an pourrait être vous. Alors, rendez-le aussi facile que possible pour eux.

Encaitar
la source
0

Cela revient à combien de temps est passé à regarder (les cycles cérébraux) sur le code et à comprendre ce que fait le code.

  • Envisagez une méthode en 10 lignes - Prenez probablement quelques minutes pour comprendre ce qu'elle fait.
  • Envisagez une méthode de 100 lignes - Prenez probablement une heure ou plus pour comprendre ce qui se passe.
  • Envisagez une méthode de 1 000 lignes - Prenez probablement un jour ou plus pour comprendre ce qui se passe.

De plus, des méthodes plus importantes sont plus difficiles à tester et plus difficiles à prévoir quel type de comportement pourrait se produire.

La complexité cyclomatique est une mesure. Dans ce cas, des valeurs plus élevées sont des indicateurs de problèmes potentiels. Le code complexe prend plus de temps à comprendre et n'est probablement pas testé aussi minutieusement que les méthodes moins complexes. Il est donc important de noter quels domaines du code sont complexes avec cette mesure à des fins de refactorisation et de maintenance.

Une autre chose à considérer est la mise à jour du code complexe. Lors d'une analyse, un développeur peut signaler que la modification du code est plus ou moins risquée en examinant sa complexité.

Il y a donc beaucoup de valeur à mesurer la complexité qui peut être exploitée et utilisée à des fins de prise de décision.

Jon Raynor
la source
1
Désolé Ghost Cat réponse très similaire, aurait dû rafraîchir la page.
Jon Raynor