Fundamentals 13 min read

Understanding Cyclomatic Complexity and Code Quality Metrics

This article explains cyclomatic complexity, its calculation formulas, practical examples, and how to measure and improve code quality using tools like SonarQube, ESLint, and codeMetrics, while also presenting refactoring techniques such as single‑responsibility, open‑closed, polymorphism, early returns, and functional programming to reduce complexity.

TAL Education Technology
TAL Education Technology
TAL Education Technology
Understanding Cyclomatic Complexity and Code Quality Metrics

Cyclomatic complexity, introduced by Thomas J. McCabe in 1976, quantifies the number of linearly independent paths through a program's control‑flow graph, indicating the minimum number of test cases needed to achieve thorough coverage; higher values suggest lower code quality and harder maintenance.

Measurement Formulas

Three common formulas are used:

V(G) = e - n + 2p (edges, nodes, connected components; p is usually 1).

V(G) = number of decision nodes + 1 (region count).

V(G) = R (number of regions in the control‑flow graph).

For a sample function, the calculation yields V(G) = 9 - 7 + 2 = 4.

Example Calculation

function sort(A: number[]): void {
  let i = 0;
  const n = 4;
  let j = 0;
  while (i < n - 1) {
    j = i + 1;
    while (j < n) {
      if (A[i] < A[j]) {
        const temp = A[i];
        A[i] = A[j];
        A[j] = temp;
      }
    }
    i = i + 1;
  }
}

The above function has a cyclomatic complexity of 4.

Detection Tools

Popular static‑analysis tools that report cyclomatic complexity include:

Project

SonarQube

ESLint

codeMetrics

Complexity Metric

Supported

Supported

Supported

Detection Efficiency

High

Medium

Low

Accuracy

High

Medium

Low

Supported Languages

Many

General

General

Guidance for High Complexity

High

Medium

Low

Installation steps for SonarQube involve downloading the server, configuring the database, installing the scanner, and linking projects. For ESLint, install the core package and the eslint-plugin-complexity plugin:

npm install eslint --save-dev
npm install eslint-plugin-complexity --save-dev

Configure ESLint with a .eslintrc.js file:

module.exports = {
  env: {
    browser: true,
    es6: true,
  },
  extends: ['eslint:recommended'],
  plugins: ['complexity'],
  rules: {
    'complexity': ['error', { max: 10 }],
  },
};

Refactoring Practices to Reduce Complexity

1. Single‑Responsibility Principle

class User {
  login(username: string, password: string): boolean { /* ... */ }
  getProfile(userId: number): object { /* ... */ }
}

Refactored into separate classes:

class Authenticator {
  login(username: string, password: string): boolean { /* ... */ }
}

class UserProfile {
  getProfile(userId: number): object { /* ... */ }
}

2. Open‑Closed Principle

function quickSort(data: number[]) { /* implementation */ }
function mergeSort(data: number[]) { /* implementation */ }

Refactored using strategy pattern:

interface SortStrategy {
  sort(data: number[]): number[];
}

class QuickSortStrategy implements SortStrategy { /* ... */ }
class MergeSortStrategy implements SortStrategy { /* ... */ }

class Sorter {
  private strategy: SortStrategy;
  constructor(strategy: SortStrategy) { this.strategy = strategy; }
  sort(data: number[]) { return this.strategy.sort(data); }
}

3. Remove Duplicate Code

function calculateTotalPrice(products) {
  let totalPrice = 0;
  for (let i = 0; i < products.length; i++) {
    const product = products[i];
    totalPrice += product.price * product.quantity;
    if (product.isOnSale) { totalPrice -= product.discount; }
  }
  return totalPrice;
}

After extracting price calculation:

function calculateTotalPrice(products) {
  let totalPrice = 0;
  for (let i = 0; i < products.length; i++) {
    const product = products[i];
    totalPrice += calculateProductPrice(product);
  }
  return totalPrice;
}

function calculateProductPrice(product) {
  let productPrice = product.price * product.quantity;
  if (product.isOnSale) { productPrice -= product.discount; }
  return productPrice;
}

4. Introduce Polymorphism

abstract class Animal {
  abstract makeSound(): void;
}

class Dog extends Animal { makeSound() { console.log('汪汪汪!'); } }
class Cat extends Animal { makeSound() { console.log('喵喵喵!'); } }

const animals: Animal[] = [new Dog(), new Cat()];
animals.forEach(animal => animal.makeSound());

5. Early Return

function calculateBonus(salary: number, level: string) {
  if (salary <= 0) { return 0; }
  let bonus = 0;
  switch (level) {
    case 'A': bonus = salary * 0.2; break;
    case 'B': bonus = salary * 0.1; break;
    case 'C': bonus = salary * 0.05; break;
    default: break;
  }
  return bonus;
}

6. Use Small Functions

function processItems(items: any[]) {
  const results = [];
  for (let i = 0; i < items.length; i++) {
    const item = items[i];
    const result = processItem(item);
    if (result !== null) { results.push(result); }
  }
  return results;
}

function processItem(item: any) {
  const result1 = processItemPart1(item);
  const result2 = processItemPart2(item);
  if (result1 !== null && result2 !== null) {
    return result1 * 2 + result2 * 3;
  }
  return null;
}

function processItemPart1(item: any) { /* ... */ }
function processItemPart2(item: any) { /* ... */ }

7. Functional Programming

function sum(array) {
  return array.reduce((acc, val) => acc + val, 0);
}

Assistance from Copilot Chat

When cyclomatic complexity becomes too high, developers can use AI assistants like Copilot Chat to suggest refactorings, extract functions, and apply the above best practices automatically.

Overall, understanding the metric, using appropriate static‑analysis tools, and applying systematic refactoring techniques help keep code maintainable and testable.

JavaScriptsoftware qualityrefactoringstatic analysiscyclomatic complexitysonarqubecode metrics
TAL Education Technology
Written by

TAL Education Technology

TAL Education is a technology-driven education company committed to the mission of 'making education better through love and technology'. The TAL technology team has always been dedicated to educational technology research and innovation. This is the external platform of the TAL technology team, sharing weekly curated technical articles and recruitment information.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.