Back

Métricas de Código Explicadas: O Que É Complexidade Ciclomática?

Métricas de Código Explicadas: O Que É Complexidade Ciclomática?

Você está a rever um pull request e uma função cresceu para lidar com oito condições diferentes — funções de utilizador, feature flags, casos extremos, fallbacks. Passa nos testes. Funciona. Mas algo não parece certo. Esse sentimento tem um nome e um número.

A complexidade ciclomática é uma métrica de qualidade de código que mede quantos caminhos de execução independentes existem através de uma função. Quanto maior o número, mais lógica de ramificação o seu código contém — e mais difícil se torna lê-lo, testá-lo e mantê-lo.

Principais Conclusões

  • A complexidade ciclomática conta o número de caminhos independentes através de uma função, fornecendo um sinal mensurável da lógica de ramificação.
  • Calcule-a rapidamente começando em 1 e adicionando 1 para cada instrução de ramificação, como if, &&, ||, case ou um ternário.
  • Difere da complexidade cognitiva, que mede o quão difícil o código é de ler por um humano, em vez de quantos caminhos contém.
  • Ferramentas como ESLint e SonarQube podem rastrear automaticamente a complexidade e sinalizar funções que excedam um limiar configurável.
  • Reduza a complexidade com guard clauses, helpers extraídos, variáveis booleanas descritivas e lookup tables.

Como a Complexidade Ciclomática É Calculada

Desenvolvida por Thomas McCabe em 1976, a métrica é derivada do grafo de fluxo de controlo de uma função. A fórmula prática para um único componente conectado é:

M = E − N + 2P

Onde E é o número de arestas, N é o número de nós, P é o número de componentes conectados (geralmente 1 para uma única função) e M é a pontuação de complexidade.

Para a maioria dos programadores JavaScript, não é necessário calcular isto manualmente. O atalho: comece em 1 e, em seguida, adicione 1 para cada instrução de ramificaçãoif, else if, &&, ||, for, while, case, operadores ternários e cláusulas catch. Algumas ferramentas também contam construções como optional chaining, valores predefinidos e logical assignment. As regras exatas de cálculo podem variar ligeiramente entre ferramentas como ESLint e SonarQube.

Um Exemplo em JavaScript: Como a Ramificação Aumenta a Complexidade

// Cyclomatic complexity: 1
function getDisplayName(user: User): string {
  return user.name;
}
// Cyclomatic complexity: 6
function getDisplayName(user: User | null): string {
  if (!user) return "Guest";                     // +1
  if (user.isAdmin) return "Admin";              // +1
  if (user.displayName) return user.displayName; // +1
  if (user.firstName && user.lastName)           // +1 (if) +1 (&&)
    return `${user.firstName} ${user.lastName}`;
  return user.email;
}

Cada condição adiciona uma ramificação. Mais ramificações significam mais caminhos a testar — e mais formas de uma alteração futura quebrar algo de forma inesperada.

Este padrão aparece constantemente em código frontend: lógica de renderização de componentes React, reducers Redux com muitos tipos de ações, handlers de validação de formulários e fluxos de UI baseados em permissões.

Complexidade Ciclomática vs. Complexidade Cognitiva

São métricas relacionadas, mas distintas. A complexidade ciclomática conta ramificações estruturais — é um sinal de testabilidade. A complexidade cognitiva (popularizada pelo SonarQube) mede o quão difícil o código é de ler por um humano, penalizando mais fortemente o aninhamento e o fluxo não linear.

Uma função pode ter uma pontuação baixa em complexidade ciclomática e ainda assim ser difícil de seguir — por exemplo, chamadas de métodos profundamente encadeadas sem variáveis intermédias. Ambas as métricas são úteis e nenhuma conta a história completa sozinha.

Medindo-a no Seu Codebase JavaScript

Duas ferramentas práticas para equipas frontend:

Configure o ESLint desta forma:

{
  "rules": {
    "complexity": ["warn", { "max": 10 }]
  }
}

O limiar é configurável — e deve ser. Um utilitário de validação e um reducer Redux não precisam do mesmo limite. Ajuste os limiares para corresponder ao contexto do seu código, e não a uma regra universal.

Formas Práticas de Reduzir Complexidade Desnecessária

Quando a pontuação de uma função sobe, estas técnicas ajudam:

  • Extrair funções — separar lógicas distintas em helpers nomeados
  • Usar guard clauses — retornar cedo em vez de aninhar condições
  • Simplificar condicionais — substituir cadeias booleanas complexas por variáveis descritivas
  • Usar lookup tables — substituir longas instruções switch por objetos ou Map

O objetivo não é uma pontuação baixa por si só. É código que seja mais fácil de testar, mais fácil de alterar e mais fácil de entender pelo próximo programador.

Conclusão

A complexidade ciclomática fornece um sinal concreto e mensurável sobre a lógica de ramificação no seu código. Use ESLint ou SonarQube para a rastrear, defina limiares que se adequem ao seu codebase e trate pontuações crescentes como um estímulo para refatorar — não como uma crise. Combine-a com a complexidade cognitiva para uma imagem mais completa da manutenibilidade.

FAQs

Uma diretriz comum é manter as funções em 10 ou abaixo. Pontuações de 1 a 10 são consideradas geríveis, de 11 a 20 sugerem que a função está a tornar-se complexa, e qualquer valor acima de 20 é normalmente um forte candidato a refatoração. O limiar adequado depende do tipo de código, por isso ajuste-o ao contexto da sua equipa.

A complexidade ciclomática conta cada instrução de ramificação de forma igual, independentemente da profundidade do aninhamento. Uma função com três instruções if planas e outra com três instruções if aninhadas podem ter a mesma pontuação. Esta é uma das razões pelas quais existe a complexidade cognitiva, uma vez que adiciona peso extra ao aninhamento e reflete melhor o quão difícil o código é de ler.

Nem sempre. Uma pontuação alta sinaliza que uma função merece uma análise mais atenta, mas alguma lógica é genuinamente pesada em ramificações, como parsers, máquinas de estados ou pipelines de validação. Use a métrica como um estímulo para revisão, em vez de uma regra estrita. Se a função estiver bem testada, claramente escrita e estável, refatorar pode adicionar risco sem benefício real.

As linhas de código medem o tamanho, enquanto a complexidade ciclomática mede pontos de decisão. Uma função de 200 linhas sem ramificações tem uma complexidade de 1, enquanto uma função de 20 linhas cheia de condições pode ter uma pontuação muito mais elevada. A complexidade é um melhor preditor da testabilidade e do esforço de manutenção, porque reflete quantos caminhos os seus testes precisam de cobrir.

Gain control over your UX

See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay