Tableless

Busca Menu

Medindo a complexidade do seu código JavaScript

Seja o primeiro a comentar por

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:

function authenticate() {
  if (user.isValid() === true) { 
    user.login(); 
  } else { 
    showMessage('Invalid credentials', 'error'); 
  } 
}

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:

Complexidade Ciclomática Probabilidade de “bad fix”
1-10 5%
20-30 20%
>50 40%
próximo de 100 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

complexityplato

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:

npm install -g plato

A forma mais básica de uso é a seguinte:

plato -d report src

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 <regex> 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:

Bugs estimados

bugs

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).

Integração com Grunt

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:

npm install grunt-plato --save-dev

Uma vez instalado o pacote, basta carregar a task no seu Gruntfile.js e rodar a task com o comando grunt plato:

grunt.initConfig({
  plato: {
    your_task: {
      files: {
        'report/output/directory': ['src/**/*.js', 'test/**/*.js'],
      }
    },
  },
});
grunt.loadNpmTasks('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!

Publicado no dia