Technologies and Software Engineering

Cyclomatic Complexity and CRAP Metrics Guide

Learn how Cyclomatic Complexity and CRAP metrics evaluate code maintainability execution paths and change risk.

Overview

Cyclomatic Complexity and Change Risk Anti-Patterns (CRAP) are essential software engineering metrics used to evaluate code maintainability, testability, and modification risk. Cyclomatic Complexity measures execution paths within a function, while CRAP combines complexity with code coverage to quantify the risk of introducing defects during changes.

Key Insights

  • Execution Path Tracking: Cyclomatic Complexity quantifies the number of independent execution paths in code, directly impacting test effort and readability.
  • Exponential Risk Penalty: The CRAP score heavily penalizes complex logic that lacks automated tests, highlighting high-risk areas in pull requests and code reviews.
  • Dual-Path Remediation: High CRAP scores can be lowered either by reducing code complexity through refactoring or by increasing test coverage.
  • Target Thresholds: Maintain a Cyclomatic Complexity score below 10 and a CRAP score under 30 to ensure code stability.

Technical Details

Cyclomatic Complexity

Cyclomatic Complexity calculates structural complexity based on control flow branches. Every function starts with a baseline score of 1 and increases by 1 for each conditional branch or iteration construct.

Common complexity drivers include:

  • Control Structures: if, elseif, case, match
  • Loops: for, foreach, while
  • Null-Coalescing & Operators: ??, ?:, ternary expressions

Complexity Score Matrix

Score RangeComplexity LevelAssessment
1–6LowIdeal; clean and easy to test.
7–9ModerateAcceptable; still manageable.
10–20HighDifficult to maintain; split logic where possible.
20+Very HighCritical risk; high defect probability and hard to test.

Code Path Progression

Evaluating how conditional branching increments complexity:

// Cyclomatic Complexity: 1
function getUserStatus($user) {
    return $user->status;
}

// Cyclomatic Complexity: 2 (1 conditional statement)
function getUserStatus($user) {
    if ($user->isActive()) {
        return 'active';
    }
    return 'inactive';
}

// Cyclomatic Complexity: 4 (3 conditional statements)
function getUserStatus($user) {
    if (!$user->isActive()) {
        return 'inactive';
    }
    if ($user->isPremium()) {
        return 'premium';
    }
    if ($user->isTrial()) {
        return 'trial';
    }
    return 'active';
}

Complexity Reduction Strategies

When complexity exceeds acceptable limits, apply the following design patterns:

  • Extract Methods: Split large functions into smaller, single-responsibility methods.
  • Guard Clauses: Use early returns to flatten nested conditional trees.
  • Polymorphism: Replace conditional blocks (switch/case or large if/else chains) with polymorphic classes.
  • Lookup Tables: Map inputs directly to outputs using configuration arrays or dictionaries.

Note: Necessary business logic may justify moderate complexity, provided it is fully covered by automated tests.

Change Risk Anti-Patterns (CRAP)

The CRAP metric measures the risk of changing code by balancing Cyclomatic Complexity (CC) against code coverage.

Mathematical Formula

$$\text{CRAP} = \text{CC}^2 \times (1 - \text{coverage}/100)^3 + \text{CC}$$

The cubic exponent on uncovered code causes CRAP scores to rise exponentially when complex functions lack adequate unit tests.

Risk Thresholds

  • 0–30: Low Risk (Acceptable)
  • 30–60: Moderate Risk (Requires additional unit tests or targeted refactoring)
  • 60+: High Risk (Prioritize for immediate refactoring and test implementation)

Search

Find technical notes