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:
| Metric | Description | Example |
|---|---|---|
cyclomatic_complexity | Count of decision points (if, match, while, for, etc.) | Function with 3 if statements = complexity 4 |
cognitive_complexity | Weighted measure of code understandability | Nested loops increase cognitive load |
nesting_depth | Maximum levels of nested control structures | 3 nested if statements = depth 3 |
loc | Lines of code in the function | Physical line count |
parameter_count | Number of function parameters | fn 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:
| Metric | Formula | Purpose | Example |
|---|---|---|---|
est_branches | max(nesting, 1) × cyclomatic ÷ 3 | Estimate test cases needed for branch coverage | Complexity 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 ifmatcharmswhile,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:
| Cyclomatic | Nesting | est_branches | Interpretation |
|---|---|---|---|
| 3 | 1 | 1 | Simple linear code |
| 12 | 1 | 4 | Multiple sequential branches |
| 12 | 3 | 12 | Nested conditions, many paths |
| 20 | 5 | 33 | Complex 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:
- Users thought it was a precise count from AST analysis
- It was mistaken for cyclomatic complexity (actual branch count)
- The estimation nature was not obvious
After: est_branches
Now displayed as est_branches=X to:
- Make estimation explicit: “est_” prefix indicates this is approximate
- Avoid confusion: Clearly different from cyclomatic complexity
- 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
branchestoest_branches - Comments added explaining the estimation formula
JSON Output:
- No change: The ComplexityMetrics struct does not include this field
est_branchesis 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.