Já mostramos aqui no Tableless ferramentas para testes e ferramentas para garantir o padrão do seu código JavaScript, mas, enquanto esses utilitários asseguram uma consistência maior, eles nem sempre acabam com complexidades desnecessárias.
Neste artigo vamos falar sobre complexidade ciclomática e mostrar uma ferramenta para análise de códigos JavaScript, a biblioteca Plato.
Complexidade Ciclomática
A primeira regra de funções é que elas devem ser pequenas. A segunda regra de funções é que elas devem ser ainda menores.
— Uncle Bob
Funções devem fazer uma coisa apenas. Fazê-la bem. Fazer somente ela.
— Uncle Bob
Explicando de forma bem direta, complexidade ciclomática é uma métrica do número de caminhos possíveis no seu código. Por exemplo, vejamos o código abaixo:
A função authenticate possui valor 2 de complexidade ciclomática. Na prática, isso quer dizer que precisaríamos escrever dois testes unitários para cobrir todos os possíveis caminhos. Ou seja, quanto mais caminhos, maior a complexidade ciclomática e, quanto maior a complexidade ciclomática, mais difícil será de manter/testar seu código.
Estudos recomendam 10 como o valor máximo que você deve permitir de complexidade ciclomática no seu método ou sua função. Este é um bom valor, mas tenha em mente que 10 já é uma complexidade alta e não deve, de forma alguma, ser a média de complexidade do seu projeto.
Bad Fix
Outra métrica tirada a partir da complexidade ciclomática é a probabilidade de uma correção injetar novos bugs no seu código. O pessoal da Aivosto, uma empresa especializada em ferramentas para desenvolvedores, chegou a seguinte tabela:
Probabilidade de “bad fix”
5%
20%
40%
60%
Segundo a pesquisa da Aivosto, uma correção aplicada em um método com complexidade ciclomática 25 tem 20% de chances de introduzir um novo bug na sua aplicação. Tente lembrar quantas vezes isso já aconteceu com você? E tente lembrar também do tamanho do método ou função que você estava “corrigindo”. Por isso é muito importante tentar medir tudo a respeito do seu código.
Plato
Desenvolvida por Jarrod Overson, a ferramenta Plato aplica na prática todas as teorias de medição de complexidade ciclomática, exibindo na forma de gráficos dados como taxa de mantenabilidade, bugs estimados e erros de lint.
A instalação é feita através do npm, gerenciador de pacotes do nodejs:
A forma mais básica de uso é a seguinte:
Onde -d report é a flag para indicar o diretório report como saída do seu relatório e src é o diretório dos arquivos JavaScript a serem analisados.
Outras opções importantes são as flag -r para ler o diretório recursivamente e -x para excluir arquivos baseados em uma regex.
Os relatórios do Plato armazenam históricos e é bem interessante ver os números subindo e descendo durante o desenvolvimento do seu projeto. Uma prática legal é guardar e exibir o relatório em algum lugar disponível para todo o seu time.
Exemplos de relatórios
Abaixo temos alguns exemplos de relatórios disponibilizados no repositório do projeto, gerados a partir de bibliotecas e utilitários populares:
- jquery
- grunt
- marionettejs
Bugs estimados
Um gráfico que chama a atenção nos relatórios do Plato é o de bugs estimados. Afinal de contas, entregar um produto sem bugs é (ou deveria ser) o objetivo final de qualquer desenvolvedor.
Maurice Howard Halstead criou um conjunto de fórmulas para medir coisas como volume, esforço, dificuldade e bugs estimados em um código. As fórmulas são baseadas nos números únicos e totais de operadores e operandos.
Não vou entrar muito em detalhes sobre os valores e as fórmulas, mas é bem interessante ler sobre esse assunto (não precisa ser o livro, a Wikipedia mesmo fornece uma página bem completa sobre as fórmulas).
Overson também desenvolveu um módulo que disponibiliza uma task Grunt para relatórios Plato.
A instalação segue o padrão de pacotes Grunt:
Uma vez instalado o pacote, basta carregar a task no seu Gruntfile.js e rodar a task com o comando grunt plato:
Métricas, métricas e mais métricas
Medir o código do seu projeto ajuda você e seu time a entender e prevenir problemas. Com a ajuda de métricas você vai conseguir manter um código fácil de ler e entender. Além de métricas dos níveis de complexidade também é importante possuir um relatório visível de cobertura de testes e uma documentação simples e direta do seu projeto.
Apesar do nome pomposo e de muita teoria, não é pra ninguém ficar assustado. Pode parecer um conceito avançado, mas na verdade é uma coisa muito básica: o que você estará fazendo é medir se é fácil (ou difícil) manter o seu código.
E lembrem-se: nunca refatore um código sem que ele possua uma cobertura de testes satisfatória!