Header Ads

O que é complexidade ciclomática? Medindo a qualidade do código

Shutterstock / fran_kie

Complexidade ciclomática é uma métrica de código que você pode visualizar em muitos IDEs como o Visual Studio. Embora não seja uma ciência exata, ela permite que você tenha uma ideia geral da complexidade de funções, classes e namespaces, o que pode ser útil ao procurar código para refatorar.

O que é complexidade ciclomática?

A complexidade ciclomática basicamente mede o quanto seu código se ramifica. Cada vez que há uma instrução if ou outro bloco de controle como um loop, a complexidade ciclomática aumenta, pois o gráfico se parece cada vez mais com uma árvore.

Se você imaginar seu código como uma série de ações (funções, chamadas de método, atribuições de variáveis) conectadas via fluxo de controle, você obterá um gráfico abstrato que pode ser usado para entender melhor a complexidade. Para fluxos de controle comuns, como instruções if e loops for, os gráficos se parecem com este:

A fórmula para isso é simples; pegue o número de arestas no gráfico (as setas conectando tudo) e subtraia o número de nós no gráfico (as próprias ações).

 Complexidade = Bordas - Nós + 2 

Por exemplo, este código tem uma complexidade ciclomática de um, uma vez que não há ramificações e apenas chama WriteLine repetidamente. Uma vez que é um código perfeitamente linear, o número de nós cancelará o número de arestas, dando uma complexidade ciclomática de um.

publicvoid TestFunction & # 40; & # 41; & # 123; Console. WriteLine & # 40; " Teste " & # 41 ;; Console. WriteLine & # 40; " Teste " & # 41 ;; Console. WriteLine & # 40; " Teste " & # 41 ;; Console. WriteLine & # 40; " Teste " & # 41 ;; Console. WriteLine & # 40; " Teste " & # 41 ;; & # 125;

Para códigos mais complicados com branches, a complexidade será maior. Esse código, que contém uma instrução switch, tem uma complexidade de 6, porque existem muitos caminhos diferentes que o código pode seguir. Cada caso na instrução switch adiciona complexidade, pois pode levar a diferentes saídas com entradas diferentes.

publicvoid TestFunction & # 40; string arg & # 41; & # 123; switch & # 40; arg & # 41; & # 123; case " one & quot ;: Console. WriteLine & # 40; " Teste " & # 41 ;; interromper; caso " dois & quot ;: Console. WriteLine & # 40; " Teste " & # 41 ;; interromper; caso " três & quot ;: Console. WriteLine & # 40; " Teste " & # 41 ;; break; case " four & quot ;: Console. WriteLine & # 40; " Test " & # 41 ;; break; case " five & quot ;: Console. WriteLine & # 40; " Test " & # 41 ;; break; & # 125;   Console. WriteLine & # 40; " Teste " & # 41 ;; & # 125;

A complexidade ciclomática é calculada apenas dentro do escopo da função. Se uma função chama outra função que tem uma alta complexidade ciclomática, ela é contada apenas como um único nó e não adiciona nada ao chamador, apesar de tecnicamente adicionar complexidade ao programa em um sentido geral.

A complexidade ciclomática é útil?

A complexidade ciclomática não é uma métrica perfeita. É uma métrica muito básica e analisa as nuances do próprio código. Claro, você ainda pode ter um código terrível com baixa complexidade ou um código decente com alta complexidade. Mas, em geral, ainda é muito útil para se ter uma ideia indireta de como um programa é complexo.

Para a maior parte, complexidade abaixo de 6 a 8 provavelmente está bem, contanto que o código em si esteja bem formatado. Qualquer coisa entre 8 e 15 é questionável, e qualquer coisa acima de 15 provavelmente não é ótimo. Qualquer coisa acima de 25 é quase certamente um problema, a menos que se prove o contrário.

Embora ter uma alta complexidade ciclomática em qualquer função não seja o fim do mundo, pode ser um indicativo de um problema maior. Funções de alta complexidade são mais difíceis de manter e sujeitas a mais bugs, pois há mais coisas que podem dar errado. E funções de maior complexidade levam diretamente a testes de unidade de maior complexidade, o que pode tornar o código difícil de manter a longo prazo devido à dificuldade de teste.

O Visual Studio e outros IDEs calcularão as complexidades agregadas de classes e namespaces inteiros, que podem ser úteis para rastrear suas classes mais complexas. Você pode classificar pela maior complexidade e detalhar as funções individuais.

Freqüentemente, a revisão de código pode levar a complexidade ciclomática em consideração, até mesmo sinalizando funções problemáticas que podem precisar de revisão manual. Isso pode torná-lo uma ferramenta muito útil para manter uma base de código limpa e organizada.

Procurando Código Ruim

Muitos IDEs, como o Visual Studio, terão ferramentas integradas para calcular a complexidade ciclomática e outras métricas de código para toda a sua base de código.

Para fazer isso no Visual Studio, clique em Analisar > Calcular métricas de código > Para solução.

Isso abrirá a página “ Código de métricas ” painel que mostrará uma análise para sua solução. Você pode classificar por complexidade em ordem decrescente para visualizar os namespaces mais problemáticos.

Além da complexidade, o Visual Studio também apresenta um “ Índice de capacidade de manutenção ” que pontua o método de 0-100 em alto facilmente pode ser mantido, bem como “ Class Coupling, ” que lista quantas classes são referenciadas a partir dessa função ou classe.

Aqui, o Visual Studio apontou um método meu de 400 linhas que marcou 72 na escala de complexidade, bem como 14/100 no índice de sustentabilidade (apresentado como um amarelo sinal de perigo de triângulo) e faz referência a 65 classes diferentes.

Você pode ser enviado diretamente para os cinco estágios de luto com o resultado. “ Mas, esta é uma corrotina realmente longa que tem um monte de tarefas a fazer! ” Digo a mim mesmo, enquanto tento negar que o código que escrevi é matematicamente ruim, a ponto de o Visual Studio lançar um aviso. Uma complexidade de 72 certamente precisa ser limpa.

Nesse caso, a correção foi simples — a co-rotina tem um monte de tarefas a fazer, então divido essas tarefas em co-rotinas menores e substituo o método principal por chamadas a sub-rotinas. O código geral não mudou, nem a complexidade total da própria classe, mas agora a função principal não é uma monstruosidade de 400 linhas.

Nenhum comentário