Une complexité NPath de plus de seize octillions est-elle réaliste? Ou ai-je cassé l'outil?

13

Je viens de mesurer un gros morceau de code PHP (1153 lignes) en utilisant PHPMD ( http://phpmd.org/ ) et il me dit que le code a une complexité NPath de 16244818757303403077832757824.

Cela ressemble à un chiffre incroyablement grand pour moi, ce qui suggère que PHPMD s'est peut-être cassé d'une manière ou d'une autre. Est-il même possible qu'un morceau de code écrit par des humains ait une complexité NPath aussi élevée? La complexité cyclomatique est de 351.

Deux détails éventuellement importants -

  1. C'était du code procédural, mélangé avec du HTML, et PHPMD ne mesurera que le code orienté objet. Pour contourner cela, j'ai enveloppé le fichier entier dans une classe avec une seule fonction - c'est représentatif de la façon dont il est utilisé.

  2. Le fichier se compose d'une série d'instructions de commutateur imbriquées, et à l'intérieur de celles-ci, il y a beaucoup d'instructions if..else - donc c'est certainement assez compliqué.

Éditer

Je tiens à préciser que je ne me demande pas si PHPMD me ment. Je sais que le code est un gâchis terrible, je me demande simplement s'il est possible qu'un code soit vraiment si mauvais. Il semble que la réponse soit oui, c'est très possible.

Jez
la source
2
Je ne sais pas si vous avez cassé l'outil, mais # 2 indique que le code pourrait probablement être refactorisé un peu.
LindaJeanne
1
@LindaJeanne Je suis d'accord. Je suis juste curieux de savoir exactement à quel point il est en désordre.
Jez
2
WordPress ' WP_Query::get_posts()avait une complexité NPath de 1,435 Quindecillion en 2013. C'est encore pire de nos jours…
fuxia
@toscho c'est ma nouvelle information préférée. Merci!
Jez

Réponses:

24

C'est tout à fait possible. Supposons que nous ayons 35 constructions de cas de commutation de 10 cas chacune, ce qui nous donnerait une complexité cyclomatique approximative de 350 lorsque chaque changement se produit l'un après l'autre. Le premier commutateur nous donne 10 chemins. Le deuxième commutateur nous donne un autre 10 chemins indépendants, de sorte que nous avons 10 · 10 chemins jusqu'à ici. Avec le troisième interrupteur, nous obtenons 10 · 10 · 10 = 10³ chemins, et ainsi de suite jusqu'à ce que nous obtenions 10 35 chemins au total! Ceci est encore plus élevé que votre résultat de 1,6 · 10 28 chemins, ce qui est probablement dû à un facteur de branchement différent et à des instructions de flux de contrôle imbriquées qui réduisent le nombre de chemins dans votre code.

Dans le pire des cas pour une complexité cyclomatique donnée c, nous pouvons avoir un maximum de 2 c chemins acycliques à travers le code (ici: 2 351 = 4,6 · 10 105 ).

Le jugement de l'outil est clair: le code avec lequel vous traitez est un gâchis compliqué, non testable et non maintenable. Envisagez de le diviser en fonctions indépendantes plus petites et d'abstraire la répétition. Par exemple, vous pouvez séparer la génération HTML de la logique principale de votre script PHP.

amon
la source
14
Merci pour l'analyse. Je ressens le besoin de préciser que ce n'est pas mon code ... mais, comme c'est souvent le cas, il me semble que c'est mon problème.
Jez
1
@Jez, si c'est une consolation, vous n'êtes pas dans une position unique.
Daniel Hollinrake
5

Selon cette description , la complexité de NPath est exponentielle en complexité cyclomatique.

En prenant simplement des instructions if simples, si vous avez deux de ces instructions, cela représente essentiellement 4 itinéraires à travers votre code correspondant aux quatre combinaisons possibles de true / false pour les deux conditions de l'instruction. Ajoutez une autre instruction if et vous obtenez 8.

En d'autres termes, si toute votre complexité cyclomatique et NPath provenait d'une longue liste d'instructions if, votre égalité le serait NPath = 2^cyclomatic. En comparant cela avec vos chiffres, 2 ^ 351 = 4,6 * 10 ^ 105, beaucoup, beaucoup plus élevé que la complexité NPath que vous avez rapportée.

Je ne sais pas combien PHPMD fait pour éviter de compter les chemins qui sont réellement impossibles (par exemple, deux conditions mutuellement exclusives évaluant toutes les deux à vrai). Une analyse manuelle pourrait révéler que de nombreux chemins sont en fait impossibles, donc le code est écrit d'une manière qui gonfle la métrique NPath. Pour continuer ce qui précède, si vous aviez une liste de 351 instructions if, mais que vous pouviez vérifier qu'une seule était réellement entrée, vous pouvez la transformer en une chaîne d'instructions if ... else, réduisant votre complexité NPath de 4,6 * 10 ^ 105 à 353.

Mais avec seulement les informations dans votre question, ne sachant pas combien de ce type de simplification pourrait être fait ou est déjà fait par PHPMD, le nombre semble réaliste.

Ben Aaronson
la source