Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Metrics Reference

Comprehensive guide to all metrics calculated by Debtmap and how to interpret them.

Metric Categories (Spec 118)

Debtmap distinguishes between two fundamental categories of metrics:

Measured Metrics

Definition: Metrics directly computed from the Abstract Syntax Tree (AST) through precise analysis.

These metrics are:

  • Deterministic: Same code always produces the same metric value
  • Precise: Exact counts from syntax analysis, not estimates
  • Suitable for thresholds: Reliable for CI/CD quality gates
  • Language-specific: Computed using language parsers (syn for Rust, tree-sitter for others)

Measured metrics include:

MetricDescriptionExample
cyclomatic_complexityCount of decision points (if, match, while, for, etc.)Function with 3 if statements = complexity 4
cognitive_complexityWeighted measure of code understandabilityNested loops increase cognitive load
nesting_depthMaximum levels of nested control structures3 nested if statements = depth 3
locLines of code in the functionPhysical line count
parameter_countNumber of function parametersfn foo(a: i32, b: String) = 2

Estimated Metrics

Definition: Heuristic approximations calculated using formulas, not direct AST measurements.

These metrics are:

  • Heuristic: Based on mathematical formulas and assumptions
  • Approximate: Close estimates, not exact counts
  • Useful for prioritization: Help estimate effort and risk
  • Not suitable for hard thresholds: Use for relative comparisons, not absolute gates

Estimated metrics include:

MetricFormulaPurposeExample
est_branchesmax(nesting, 1) × cyclomatic ÷ 3Estimate test cases needed for branch coverageComplexity 12, nesting 3 → ~12 branches

Important: The est_branches metric was previously called branches. It was renamed in Spec 118 to make it explicit that this is an estimate, not a precise count from the AST.

Why the Distinction Matters

For Code Quality Gates

# GOOD: Use measured metrics for CI/CD thresholds
debtmap validate . --threshold-complexity 15

# AVOID: Don't use estimated metrics for hard gates
# (est_branches is not exposed as a threshold flag)

Rationale: Measured metrics are deterministic and precise, making them suitable for build-breaking quality gates.

For Prioritization

# GOOD: Use est_branches for prioritization
debtmap analyze . --top 10  # Sorts by est_branches (among other factors)

# GOOD: Estimated metrics help understand testing effort
debtmap analyze . --lcov coverage.info --verbose

Rationale: Estimated metrics provide useful heuristics for understanding where to focus testing and refactoring efforts.

For Comparison Across Codebases

  • Measured metrics: Comparable across projects (cyclomatic 10 means the same everywhere)
  • Estimated metrics: Project-specific heuristics (est_branches depends on nesting patterns)

Detailed Metric Descriptions

Cyclomatic Complexity (Measured)

What it measures: The number of linearly independent paths through a function’s control flow.

How it’s calculated:

  • Start with a base of 1
  • Add 1 for each decision point:
    • if, else if
    • match arms
    • while, for, loop
    • &&, || in conditions
    • ? operator (early return)

Example:

#![allow(unused)]
fn main() {
fn example(x: i32, y: i32) -> bool {
    if x > 0 {        // +1
        if y > 0 {    // +1
            true
        } else {      // implicit in if/else
            false
        }
    } else if x < 0 { // +1
        false
    } else {
        y == 0        // no additional branches
    }
}
// Cyclomatic complexity = 1 + 3 = 4
}

Thresholds:

  • 1-5: Simple, easy to test
  • 6-10: Moderate, manageable complexity
  • 11-20: Complex, consider refactoring
  • 21+: Very complex, high maintenance cost

Cognitive Complexity (Measured)

What it measures: How difficult the code is for humans to understand.

How it differs from cyclomatic:

  • Weights nested structures more heavily (nested if is worse than sequential if)
  • Ignores shorthand structures (early returns, guard clauses)
  • Focuses on readability, not just logic paths

Example:

#![allow(unused)]
fn main() {
fn cyclomatic_low_cognitive_low(status: Status) -> bool {
    match status {  // Cyclomatic: 4, Cognitive: 1
        Status::Active => true,
        Status::Pending => false,
        Status::Closed => false,
        Status::Error => false,
    }
}

fn cyclomatic_low_cognitive_high(x: i32, y: i32, z: i32) -> bool {
    if x > 0 {
        if y > 0 {      // Nested: +2 cognitive penalty
            if z > 0 {  // Deeply nested: +3 cognitive penalty
                return true;
            }
        }
    }
    false
}
// Cyclomatic: 4, Cognitive: 7 (nesting penalty applied)
}

Thresholds:

  • 1-5: Easy to understand
  • 6-10: Moderate mental load
  • 11-15: Difficult to follow
  • 16+: Refactor recommended

Estimated Branches (Estimated)

What it estimates: Approximate number of execution paths that would need test coverage.

Formula:

est_branches = max(nesting_depth, 1) × cyclomatic_complexity ÷ 3

Why this formula:

  • Nesting multiplier: Deeper nesting creates more combinations
  • Cyclomatic base: Higher complexity → more paths
  • ÷ 3 adjustment: Empirical factor to align with typical branch coverage needs

Example scenarios:

CyclomaticNestingest_branchesInterpretation
311Simple linear code
1214Multiple sequential branches
12312Nested conditions, many paths
20533Complex nested logic

Use cases:

  • Estimating test case requirements
  • Prioritizing untested complex code
  • Understanding coverage gaps

Limitations:

  • Not a precise count: This is a heuristic approximation
  • Don’t use for coverage percentage calculation: Use actual coverage tools
  • Varies by code style: Heavily nested code scores higher

Terminology Change (Spec 118)

Before: branches

Previously, this metric was displayed as branches=X, which was confusing because:

  1. Users thought it was a precise count from AST analysis
  2. It was mistaken for cyclomatic complexity (actual branch count)
  3. The estimation nature was not obvious

After: est_branches

Now displayed as est_branches=X to:

  1. Make estimation explicit: “est_” prefix indicates this is approximate
  2. Avoid confusion: Clearly different from cyclomatic complexity
  3. Set correct expectations: Users know this is a heuristic, not a measurement

Migration Guide

Terminal Output:

  • Old: COMPLEXITY: cyclomatic=12, branches=8, cognitive=15
  • New: COMPLEXITY: cyclomatic=12, est_branches=8, cognitive=15

Code:

  • Internal variable names updated from branches to est_branches
  • Comments added explaining the estimation formula

JSON Output:

  • No change: The ComplexityMetrics struct does not include this field
  • est_branches is calculated on-demand for display purposes only

Practical Usage Examples

Example 1: Code Quality Gate

# Fail build if any function exceeds cyclomatic complexity 15
debtmap validate . --threshold-complexity 15 --max-high 0

# Why: Cyclomatic is measured, precise, and repeatable

Example 2: Prioritize Testing Effort

# Show top 10 functions by risk (uses est_branches in scoring)
debtmap analyze . --lcov coverage.info --top 10

# Functions with high est_branches and low coverage appear first

Example 3: Understanding Test Requirements

# Verbose output shows est_branches for each function
debtmap analyze . --verbose

# Output:
# └─ COMPLEXITY: cyclomatic=12, est_branches=8, cognitive=15, nesting=2
#
# Interpretation: ~8 test cases likely needed for good branch coverage

Example 4: Explaining Metrics to Team

# Display comprehensive metric definitions
debtmap analyze --explain-metrics

# Shows:
# - Measured vs Estimated categories
# - Formulas and thresholds
# - When to use each metric

Metric Selection Guide

When to Use Cyclomatic Complexity

Use for:

  • CI/CD quality gates
  • Code review guidelines
  • Consistent cross-project comparison
  • Identifying refactoring candidates

Don’t use for:

  • Estimating test effort (use est_branches)
  • Readability assessment (use cognitive complexity)

When to Use Cognitive Complexity

Use for:

  • Readability reviews
  • Identifying hard-to-maintain code
  • Onboarding difficulty assessment

Don’t use for:

  • Test coverage planning
  • Strict quality gates (more subjective than cyclomatic)

When to Use est_branches

Use for:

  • Estimating test case requirements
  • Prioritizing test coverage work
  • Understanding coverage gaps

Don’t use for:

  • CI/CD quality gates (it’s an estimate)
  • Calculating coverage percentages (use actual coverage data)
  • Cross-project comparison (formula is heuristic)

Combining Metrics for Insights

High Complexity, Low Coverage

cyclomatic=18, est_branches=12, coverage=0%

Interpretation: High-risk code needing ~12 test cases for adequate coverage.

Action: Prioritize writing tests, consider refactoring.

High Cyclomatic, Low Cognitive

cyclomatic=15, cognitive=5

Interpretation: Many branches, but simple linear logic (e.g., validation checks).

Action: Acceptable pattern, tests should be straightforward.

Low Cyclomatic, High Cognitive

cyclomatic=8, cognitive=18

Interpretation: Deeply nested logic, hard to understand despite fewer branches.

Action: Refactor to reduce nesting, extract functions.

High est_branches, Low Cyclomatic

cyclomatic=9, nesting=5, est_branches=15

Interpretation: Deep nesting creates many path combinations.

Action: Flatten nesting, use early returns, extract nested logic.

Frequently Asked Questions

Q: Why is est_branches different from cyclomatic complexity?

A: Cyclomatic is the measured count of decision points. est_branches is an estimated number of execution paths, calculated using nesting depth to account for path combinations.

Q: Can I use est_branches in CI/CD thresholds?

A: No. Use measured metrics (cyclomatic_complexity, cognitive_complexity) for quality gates. est_branches is a heuristic for prioritization, not a precise measurement.

Q: Why did the metric name change from “branches” to “est_branches”?

A: To make it explicit that this is an estimate, not a measured value. Users were confused, thinking it was a precise count from the AST.

Q: How accurate is est_branches for estimating test cases?

A: It’s a rough approximation. Actual test case requirements depend on:

  • Business logic complexity
  • Edge cases
  • Error handling paths
  • Integration points

Use est_branches as a starting point, not an exact requirement.

Q: Should I refactor code with high est_branches?

A: Not necessarily. High est_branches indicates complex logic that may need thorough testing. If the logic is unavoidable (e.g., state machines, complex business rules), focus on comprehensive test coverage rather than refactoring.

Further Reading