Uma complexidade do NPath de mais de dezesseis octillion é realista? Ou eu quebrei a ferramenta?

13

Acabei de medir uma grande parte do código PHP (1153 linhas) usando o PHPMD ( http://phpmd.org/ ) e ele me diz que o código tem uma complexidade NPath de 16244818757303403077832757824.

Parece-me um número loucamente grande, sugerindo que talvez o PHPMD tenha quebrado de alguma forma. É possível que um pedaço de código escrito por humanos tenha uma complexidade de NPath tão alta? A complexidade ciclomática é 351.

Dois detalhes possivelmente importantes -

  1. Este era um código processual, misturado com HTML, e o PHPMD medirá apenas o código orientado a objetos. Para contornar isso, agrupei o arquivo inteiro em uma classe com uma única função - isso é representativo de como é usado.

  2. O arquivo consiste em uma série de instruções de switch aninhadas e, dentro delas, existem muitas instruções if..else - então é certamente bastante complicado.

Editar

Quero esclarecer que não estou questionando se o PHPMD está mentindo para mim. Eu sei que o código é uma bagunça terrível, só me pergunto se é possível que algum código seja realmente tão ruim assim. Parece que a resposta é sim, é muito possível.

Jez
fonte
2
Não sei se você quebrou a ferramenta, mas o nº 2 indica que o código provavelmente pode ser refatorado um pouco.
21715 LindaJeanne
1
@LindaJeanne Eu concordo. Eu sou apenas curioso para saber exatamente o quanto de uma confusão que está.
Jez
2
WordPress' WP_Query::get_posts()teve uma complexidade nPath de 1.435 Quindecillion em 2013. Ele é ainda pior hoje em dia ...
fuxia
@toscho essa é minha nova informação favorita. Obrigado!
Jez

Respostas:

24

Isso é inteiramente possível. Vamos supor que temos 35 construções de casos de switch de 10 casos cada, o que nos daria uma complexidade ciclomática aproximada de 350 quando cada switch ocorre um após o outro. A primeira opção nos dá 10 caminhos. O segundo comutador nos fornece outros 10 caminhos independentes, de modo que temos 10 · 10 caminhos até aqui. Com o terceiro comutador, obtemos 10 · 10 · 10 = 10³ caminhos e assim sucessivamente até obter 10 35 caminhos no total! Isso é ainda mais alto que o resultado de 1,6 · 28 caminhos, o que provavelmente se deve a um fator de ramificação diferente e a instruções de fluxo de controle aninhadas que reduzem o número de caminhos através do seu código.

Como um cenário de pior caso para uma determinada complexidade cyclomatic C, que pode ter um máximo de 2 c caminhos acíclicos através do código (aqui: 2 351 = 4,6 · 10 105 ).

O julgamento da ferramenta é claro: o código com o qual você está lidando é uma bagunça complicada, não testável e inatingível. Considere dividi-lo em funções menores e independentes e abstrair a repetição. Por exemplo, você pode separar a geração de HTML da lógica principal do seu script PHP.

amon
fonte
14
Obrigado pela análise. Sinto a necessidade de salientar que esse não é o meu código ... mas, como costuma ser o caso, parece-me o meu problema.
Jez
1
@Jez, se houver algum consolo, você não está em uma posição única.
Daniel Hollinrake
5

De acordo com esta descrição , a complexidade do NPath é exponencial na complexidade ciclomática.

Tomando apenas instruções if simples, se você tiver duas dessas instruções, são essencialmente 4 rotas através do seu código, correspondentes às quatro combinações possíveis de verdadeiro / falso para as duas condições da instrução. Adicione outra instrução if e você obtém 8.

Em outras palavras, se toda a sua complexidade ciclomática e NPath vinha de uma longa lista de instruções if, sua equivalência seria NPath = 2^cyclomatic. Comparando isso com seus números, 2 ^ 351 = 4,6 * 10 ^ 105, muito, muito mais alto que a complexidade do NPath que você relatou.

Não sei quanto o PHPMD faz para evitar a contagem de caminhos que são realmente impossíveis (por exemplo, dois condicionais mutuamente exclusivos, ambos avaliando como verdadeiros). Possivelmente, uma análise manual revelaria que muitos dos caminhos são realmente impossíveis; portanto, o código é escrito de maneira a aumentar a métrica do NPath. Para continuar o exposto acima, se você tivesse uma lista de 351 instruções if, mas pudesse verificar se apenas uma foi realmente inserida, poderá transformá-la em uma cadeia de instruções if ... else, diminuindo a complexidade do NPath para 4,6 * 10 ^ 105 a 353.

Mas, apenas com as informações da sua pergunta, sem saber quanto desse tipo de simplificação poderia ser feito ou já está sendo feito pelo PHPMD, o número parece realista.

Ben Aaronson
fonte