debtmap 0.16.5

Code complexity and technical debt analyzer
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
# Boilerplate vs Complexity

## Overview

Debtmap distinguishes between **boilerplate code** (necessary but mechanical patterns) and **true complexity** (business logic requiring cognitive effort). This distinction is critical for:

- Avoiding false positives in complexity analysis
- Focusing refactoring efforts on actual problems
- Understanding which high-complexity code is acceptable
- Providing actionable recommendations

This chapter explains how Debtmap identifies boilerplate patterns, why they differ from complexity, and how to interpret the analysis results.

## The Distinction

### What is Boilerplate?

Boilerplate code consists of repetitive, mechanical patterns that are:

1. **Required by language/framework** - Type conversions, trait implementations, builder patterns
2. **Structurally necessary** - Match arms for enums, error propagation, validation chains
3. **Low cognitive load** - Pattern-based code that developers scan rather than deeply analyze
4. **Not actual complexity** - High cyclomatic complexity but mechanistic structure

**Examples:**
- `From` trait implementations converting between types
- `Display` formatting with exhaustive enum match arms
- Builder pattern setters with validation
- Error conversion implementations
- Serialization/deserialization code

### What is True Complexity?

True complexity consists of business logic that requires:

1. **Domain understanding** - Knowledge of problem space and requirements
2. **Cognitive effort** - Careful analysis to understand behavior
3. **Algorithmic decisions** - Non-obvious control flow or data transformations
4. **Maintainability risk** - Changes may introduce subtle bugs

**Examples:**
- Graph traversal algorithms
- Complex business rules with multiple conditions
- State machine implementations with non-trivial transitions
- Performance-critical optimizations
- Error recovery with fallback strategies

## Real Example: ripgrep's defs.rs

The ripgrep codebase provides an excellent real-world example of boilerplate vs complexity.

### File: `crates/printer/src/defs.rs`

This file contains type conversion implementations with high cyclomatic complexity scores but minimal actual complexity:

```rust
impl From<HyperlinkFormat> for ColorHyperlink {
    fn from(format: HyperlinkFormat) -> ColorHyperlink {
        match format {
            HyperlinkFormat::Default => ColorHyperlink::default(),
            HyperlinkFormat::Grep => ColorHyperlink::grep(),
            HyperlinkFormat::GrepPlus => ColorHyperlink::grep_plus(),
            HyperlinkFormat::Ripgrep => ColorHyperlink::ripgrep(),
            HyperlinkFormat::FileNone => ColorHyperlink::file_none(),
            // ... 10+ more variants
        }
    }
}
```

**Analysis:**
- **Cyclomatic Complexity**: 15+ (one branch per enum variant)
- **Cognitive Complexity**: Low (simple delegation pattern)
- **Boilerplate Confidence**: 95% (trait implementation with mechanical structure)

### Why This Matters

Without boilerplate detection, this file would be flagged as:
- High complexity debt
- Requiring refactoring
- Priority for review

With boilerplate detection, it's correctly classified as:
- Necessary type conversion code
- Low maintenance risk
- Can be safely skipped in debt prioritization

## Detection Methodology

Debtmap uses a multi-phase analysis pipeline to detect boilerplate:

### Phase 1: Trait Analysis

Identifies trait implementations known to produce boilerplate:

**High-confidence boilerplate traits:**
- `From`, `Into` - Type conversions
- `Display`, `Debug` - Formatting
- `Default` - Default value construction
- `Clone`, `Copy` - Value semantics
- `Eq`, `PartialEq`, `Ord`, `PartialOrd` - Comparisons
- `Hash` - Hashing implementations

**Medium-confidence boilerplate traits:**
- `Serialize`, `Deserialize` - Serialization
- `AsRef`, `AsMut`, `Deref`, `DerefMut` - Reference conversions
- Custom builder traits

See `src/debt/boilerplate/boilerplate_traits.rs:10-58` for complete trait categorization.

### Phase 2: Pattern Analysis

Analyzes code structure for boilerplate patterns:

**Pattern 1: Simple Delegation**
```rust
fn operation(&self) -> Result<T> {
    self.inner.operation()  // Single delegation call
}
```
Score: 90% confidence

**Pattern 2: Trivial Match Arms**
```rust
match variant {
    A => handler_a(),
    B => handler_b(),
    C => handler_c(),
}
```
Each arm calls a single function with no additional logic.
Score: 85% confidence

**Pattern 3: Validation Chains**
```rust
fn validate(&self) -> Result<()> {
    check_condition_1()?;
    check_condition_2()?;
    check_condition_3()?;
    Ok(())
}
```
Sequential validation with early returns.
Score: 75% confidence

**Pattern 4: Builder Setters**
```rust
pub fn with_field(mut self, value: T) -> Self {
    self.field = value;
    self
}
```
Simple field assignment with fluent return.
Score: 95% confidence

See `src/debt/boilerplate/pattern_detector.rs:18-82` for pattern detection logic.

### Phase 3: Macro Analysis

Detects macro-generated code and provides recommendations:

**Derivable Traits:**
Debtmap suggests using `#[derive(...)]` when it detects manual implementations of:
- `Clone`, `Copy`, `Debug`, `Default`
- `Eq`, `PartialEq`, `Ord`, `PartialOrd`
- `Hash`

**Custom Macros:**
Recommends creating custom derive macros for:
- Repeated builder pattern implementations
- Repeated conversion trait implementations
- Repeated validation logic

**Existing Crates:**
Suggests established crates for common patterns:
- `derive_more` - Extended derive macros
- `thiserror` - Error type boilerplate
- `typed-builder` - Builder pattern macros
- `delegate` - Delegation patterns

See `src/debt/boilerplate/macro_recommender.rs:9-136` for macro recommendation logic.

## Common Boilerplate Patterns

### Type Conversions

```rust
// High complexity (15+), but boilerplate
impl From<ConfigFormat> for Config {
    fn from(format: ConfigFormat) -> Config {
        match format {
            ConfigFormat::Json => Config::json(),
            ConfigFormat::Yaml => Config::yaml(),
            ConfigFormat::Toml => Config::toml(),
            // ... many variants
        }
    }
}
```

**Boilerplate Confidence**: 90%+
**Recommendation**: Consider using a macro if pattern repeats

### Error Propagation

```rust
// High nesting, but boilerplate pattern
fn complex_operation(&self) -> Result<Output> {
    let step1 = self.step_one()
        .context("Step one failed")?;
    let step2 = self.step_two(&step1)
        .context("Step two failed")?;
    let step3 = self.step_three(&step2)
        .context("Step three failed")?;
    Ok(Output::new(step3))
}
```

**Boilerplate Confidence**: 75%
**Recommendation**: Acceptable pattern for error handling

### Builder Patterns

```rust
// Many methods, but all boilerplate
impl ConfigBuilder {
    pub fn with_timeout(mut self, timeout: Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    pub fn with_retries(mut self, retries: u32) -> Self {
        self.retries = Some(retries);
        self
    }

    // ... 20+ more setters
}
```

**Boilerplate Confidence**: 95%
**Recommendation**: Use `typed-builder` or similar crate

### Display Formatting

```rust
// High complexity due to match, but boilerplate
impl Display for Status {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Status::Pending => write!(f, "pending"),
            Status::Running => write!(f, "running"),
            Status::Success => write!(f, "success"),
            Status::Failed(err) => write!(f, "failed: {}", err),
            // ... many variants
        }
    }
}
```

**Boilerplate Confidence**: 90%
**Recommendation**: Consider using `strum` or `derive_more`

## Decision Table

Use this table to interpret boilerplate confidence scores:

| Confidence | Interpretation | Action |
|-----------|----------------|--------|
| 90-100% | Definite boilerplate | Exclude from complexity prioritization; consider macro optimization |
| 70-89% | Probable boilerplate | Review pattern; likely acceptable; low refactoring priority |
| 50-69% | Mixed boilerplate/logic | Investigate; may contain hidden complexity; medium priority |
| 30-49% | Mostly real complexity | Standard complexity analysis; normal refactoring priority |
| 0-29% | True complexity | High priority; focus refactoring efforts here |

### Example Classifications

**Boilerplate (90%+ confidence):**
```rust
// Simple trait delegation - skip in debt analysis
impl AsRef<str> for CustomString {
    fn as_ref(&self) -> &str {
        &self.inner
    }
}
```

**Mixed (50-70% confidence):**
```rust
// Match with some logic - review case by case
fn process_event(&mut self, event: Event) -> Result<()> {
    match event {
        Event::Simple => self.handle_simple(),  // Boilerplate
        Event::Complex(data) => {                // Real logic
            if data.priority > 10 {
                self.handle_urgent(data)?;
            } else {
                self.queue_normal(data)?;
            }
            self.update_metrics()?;
            Ok(())
        }
    }
}
```

**True Complexity (0-30% confidence):**
```rust
// Business logic requiring domain knowledge
fn calculate_optimal_strategy(&self, market: &Market) -> Strategy {
    let volatility = market.calculate_volatility();
    let trend = market.detect_trend();

    if volatility > self.risk_threshold {
        if trend.is_bullish() && self.can_hedge() {
            Strategy::hedged_long(self.calculate_position_size())
        } else {
            Strategy::defensive()
        }
    } else {
        Strategy::momentum_based(trend, self.confidence_level())
    }
}
```

## Integration with Complexity Analysis

### Boilerplate Scoring

Debtmap calculates a `BoilerplateScore` for each function:

```rust
pub struct BoilerplateScore {
    pub confidence: f64,              // 0.0-1.0 (0% to 100%)
    pub primary_pattern: Pattern,     // Strongest detected pattern
    pub contributing_patterns: Vec<Pattern>,
    pub macro_recommendation: Option<MacroRecommendation>,
}
```

### Complexity Adjustment

High-confidence boilerplate reduces effective complexity:

```
effective_complexity = raw_complexity × (1.0 - boilerplate_confidence)
```

**Example:**
- Raw cyclomatic complexity: 15
- Boilerplate confidence: 0.90 (90%)
- Effective complexity: 15 × (1.0 - 0.90) = 1.5

This prevents boilerplate from dominating debt prioritization.

### Output Display

Debtmap annotates boilerplate functions in analysis output:

```
src/types/conversions.rs:
  ├─ from (complexity: 15, boilerplate: 92%)
  │    Pattern: Trait Implementation (From)
  │    Recommendation: Consider #[derive(From)] via derive_more
  │    Priority: Low (boilerplate)

  ├─ process_request (complexity: 12, boilerplate: 15%)
  │    Priority: High (true complexity)
```

## Best Practices

### When to Accept Boilerplate

**Accept** high-complexity boilerplate when:

1. **Required by language** - Trait implementations, type conversions
2. **Pattern is clear** - Developers can scan quickly without deep analysis
3. **Covered by tests** - Mechanical patterns verified by unit tests
4. **No simpler alternative** - Refactoring would reduce clarity

**Example:** Exhaustive match arms for enum variants with simple delegation.

### When to Refactor Boilerplate

**Refactor** boilerplate when:

1. **Pattern repeats extensively** - 10+ similar implementations
2. **Macro alternative exists** - Can use derive or custom macro
3. **Maintenance burden** - Changes require updating many copies
4. **Error-prone** - Manual pattern increases bug risk

**Example:** 50+ builder setters that could use `typed-builder` crate.

### Configuring Thresholds

Adjust boilerplate sensitivity in `.debtmap.toml`:

```toml
[boilerplate_detection]
enabled = true
min_confidence_to_exclude = 0.85  # Only exclude 85%+ confidence
trait_delegation_threshold = 0.90  # Trait impl confidence
pattern_match_threshold = 0.75     # Match pattern confidence
```

**Strict mode** (minimize false negatives):
```toml
min_confidence_to_exclude = 0.95  # Very high bar for exclusion
```

**Lenient mode** (minimize false positives):
```toml
min_confidence_to_exclude = 0.70  # More aggressive exclusion
```

## Validation and Testing

### Integration Test Example

Debtmap's test suite includes real-world boilerplate validation:

```rust
#[test]
fn test_ripgrep_defs_boilerplate() {
    let code = r#"
        impl From<HyperlinkFormat> for ColorHyperlink {
            fn from(format: HyperlinkFormat) -> ColorHyperlink {
                match format {
                    HyperlinkFormat::Default => ColorHyperlink::default(),
                    // ... 15 variants
                }
            }
        }
    "#;

    let result = analyze_boilerplate(code);
    assert!(result.confidence >= 0.85, "Should detect trait boilerplate");
    assert_eq!(result.primary_pattern, Pattern::TraitImplementation);
}
```

See `tests/boilerplate_integration_test.rs` for complete test cases.

### Performance Overhead

Boilerplate detection adds minimal overhead:

**Measurement:** <5% increase in analysis time
**Reason:** Single-pass AST analysis with cached pattern matching
**Optimization:** Trait analysis uses fast HashMap lookups

See `tests/boilerplate_performance_test.rs` for benchmark details.

## Troubleshooting

### "Why is my code marked as boilerplate?"

**Check:**
1. Is it a trait implementation? (From, Display, etc.)
2. Does it follow a mechanical pattern?
3. Are all branches simple delegations?

**If incorrectly classified:**
- Adjust `min_confidence_to_exclude` threshold
- Report false positive if confidence is very high

### "My boilerplate isn't detected"

**Common causes:**
1. Custom logic mixed with boilerplate pattern
2. Non-standard trait names
3. Complex match arm logic

**Solutions:**
- Extract pure boilerplate into separate functions
- Use standard traits when possible
- Check confidence score - may be detected with lower confidence

### "Boilerplate detection seems too aggressive"

**Adjust configuration:**
```toml
[boilerplate_detection]
min_confidence_to_exclude = 0.95  # Raise threshold
trait_delegation_threshold = 0.95
```

## Related Documentation

- [Complexity Metrics]./metrics-reference.md - Understanding cyclomatic complexity
- [Configuration]./configuration.md - Complete `.debtmap.toml` reference
- [Tiered Prioritization]./tiered-prioritization.md - How boilerplate affects debt ranking

## Summary

Boilerplate detection is a critical feature that:

- Distinguishes mechanical patterns from true complexity
- Reduces false positives in debt analysis
- Provides actionable macro recommendations
- Integrates seamlessly with complexity scoring
- Helps teams focus on real maintainability issues

By identifying boilerplate with 85%+ confidence, Debtmap ensures that high-complexity scores reflect actual cognitive burden rather than necessary but mechanical code patterns.