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

Boilerplate Detection

Debtmap identifies repetitive code patterns that could benefit from macro-ification or other abstraction techniques. This helps reduce maintenance burden and improve code consistency.

Overview

Boilerplate detection analyzes low-complexity repetitive code to identify opportunities for:

  • Macro-ification - Convert repetitive patterns to declarative or procedural macros
  • Code generation - Use build scripts to generate repetitive implementations
  • Generic abstractions - Replace duplicate implementations with generic code
  • Trait derivation - Use derive macros instead of manual implementations

Boilerplate detection runs automatically as part of the god object analysis pipeline. When a file has many impl blocks, it’s classified as either a true god object (complex code needing splitting), a builder pattern (intentional fluent API), or a boilerplate pattern (low complexity needing macro-ification). This prevents false positives where repetitive low-complexity code is misclassified as god objects.

Source: Integration with god object detection in src/organization/god_object/classification_types.rs:45-50, src/analyzers/file_analyzer.rs:366-372

Detection Criteria

Debtmap identifies boilerplate using trait pattern analysis (src/organization/trait_pattern_analyzer.rs:158-176):

  • Multiple similar trait implementations - 20+ impl blocks with shared structure
  • High method uniformity - 70%+ of implementations share the same methods
  • Low complexity repetitive code - Average cyclomatic complexity < 2.0
  • Low complexity variance - Consistent complexity across implementations
  • Single dominant trait - One trait accounts for 80%+ of implementations

The TraitPatternAnalyzer computes these metrics:

  • impl_block_count - Number of trait implementations in the file
  • unique_traits - Set of distinct traits implemented
  • most_common_trait - Most frequently implemented trait and count
  • method_uniformity - Ratio of most common method appearance to total impls
  • shared_methods - Methods appearing in 50%+ of implementations
  • avg_method_complexity - Average cyclomatic complexity per method
  • complexity_variance - Variance in complexity across methods
  • avg_method_lines - Average lines of code per method

Detection Signals

The boilerplate detector extracts detection signals (src/organization/boilerplate_detector.rs:246-253, 164-190):

  • HighImplCount(usize) - Number of impl blocks exceeds threshold
  • HighMethodUniformity(f64) - Methods are highly uniform across implementations
  • LowAvgComplexity(f64) - Average complexity is below threshold
  • LowComplexityVariance(f64) - Complexity variance is low (consistent complexity)

Note: The HighStructDensity signal is defined as an enum variant but is not currently extracted by the detection algorithm. It is reserved for future enhancement to detect struct-level boilerplate patterns.

Boilerplate Scoring Algorithm

The confidence score is calculated using weighted signals (src/organization/boilerplate_detector.rs:124-161):

  1. High impl count (30% weight) - Files with 20+ impl blocks score higher

    • Normalized: min(impl_count / 100, 1.0) × 30%
  2. Method uniformity (25% weight) - Methods shared across implementations

    • Score: method_uniformity × 25% (if ≥ 0.7 threshold)
  3. Low average complexity (20% weight) - Simple, repetitive code

    • Score: (1 - complexity / 2.0) × 20% (if complexity < 2.0)
  4. Low complexity variance (15% weight) - Consistent complexity

    • Score: (1 - min(variance / 10.0, 1.0)) × 15% (if variance < 2.0)
  5. Single dominant trait (10% weight) - One trait dominates

    • Score: trait_ratio × 10% (if trait_ratio > 0.8)

Threshold: Patterns with confidence ≥ 0.7 (70%) are reported as boilerplate.

Pattern Types

Trait Implementation Boilerplate

Detected when a file has many similar trait implementations with low complexity.

Example (from tests/boilerplate_integration_test.rs:14-48):

#![allow(unused)]
fn main() {
// 26 From<Format> implementations with identical structure
pub enum Format { A, B, C, /* ... */ Z }
pub struct Target { name: String }

impl From<Format> for Target {
    fn from(f: Format) -> Self {
        match f {
            Format::A => Target { name: "a".to_string() },
            Format::B => Target { name: "b".to_string() },
            // ... 24 more identical patterns
        }
    }
}

// Detected: 26 impl blocks, 1.0 method uniformity, complexity ~2.0
}

Recommendation: Use declarative macro to reduce ~250 lines to ~30 lines.

Builder Pattern

Detected when a file has repetitive setter methods returning Self.

Example (from book/src/boilerplate-detection.md:46-61):

#![allow(unused)]
fn main() {
impl ConfigBuilder {
    pub fn host(mut self, host: String) -> Self {
        self.host = host;
        self
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = port;
        self
    }
    // ... more identical setter methods
}
}

Recommendation: Use derive_builder crate or custom derive macro.

Test Boilerplate

Detected when test functions have shared structure and repetitive assertions (src/organization/boilerplate_detector.rs:238-243).

Example:

#![allow(unused)]
fn main() {
#[test]
fn test_case_a() {
    let input = create_input_a();
    let result = process(input);
    assert_eq!(result.status, Status::Success);
}

#[test]
fn test_case_b() {
    let input = create_input_b();
    let result = process(input);
    assert_eq!(result.status, Status::Success);
}
// ... 20 more similar test functions
}

Recommendation: Use parameterized tests with rstest or table-driven tests.

Planned Pattern Types

The following pattern types are defined in the feature specification but not yet fully implemented:

  • State machine patterns - Repetitive state transition implementations
  • Registry patterns - Similar registration logic across modules
  • Delegation patterns - Wrapper types with passthrough implementations

These are tracked for future enhancement. Currently, the implementation focuses on trait implementation boilerplate detection with partial support for builder and test patterns.

Configuration

Boilerplate detection is controlled via configuration file (src/organization/boilerplate_detector.rs:256-322):

[boilerplate_detection]
# Enable boilerplate detection (default: true)
enabled = true

# Minimum impl blocks to consider (default: 20)
min_impl_blocks = 20

# Method uniformity threshold 0.0-1.0 (default: 0.7)
method_uniformity_threshold = 0.7

# Maximum average complexity for boilerplate (default: 2.0)
max_avg_complexity = 2.0

# Minimum confidence to report 0.0-1.0 (default: 0.7)
confidence_threshold = 0.7

# Enable trait implementation detection (default: true)
detect_trait_impls = true

# Enable builder pattern detection (default: true)
detect_builders = true

# Enable test boilerplate detection (default: true)
detect_test_boilerplate = true

Implementation Status: The detect_trait_impls option is fully implemented. The detect_builders and detect_test_boilerplate options are configuration placeholders with partial implementation - the current detect() method primarily focuses on trait implementation detection (src/organization/boilerplate_detector.rs:75-121).

Field reference (src/organization/boilerplate_detector.rs:48-57, 310-322):

  • All fields have serde defaults
  • Configuration can be provided via TOML or JSON
  • Missing fields use default values

Usage

Boilerplate detection runs automatically when enabled in configuration:

# Run analysis with default configuration
debtmap analyze .

# Use custom config file
debtmap analyze . --config custom-config.toml

# Show where configuration values came from
debtmap analyze . --show-config-sources

Note: There are no dedicated CLI flags like --detect-boilerplate or --show-macro-suggestions. Boilerplate detection is integrated into the god object analysis pipeline and controlled via configuration file only (verified in src/cli.rs - no boilerplate-specific flags exist).

Macro Recommendations

The MacroRecommendationEngine generates specific refactoring guidance (src/organization/macro_recommendations.rs:13-150):

For Trait Implementations

Detected boilerplate: 25 implementations of From trait
Estimated line reduction: 220 lines → 35 lines (84% reduction)

Recommendation:
- Use declarative macro (macro_rules!) for simple conversions
- Use procedural derive macro for complex transformations
- Consider code generation in build.rs for large enums

For Builder Patterns

The MacroRecommendationEngine suggests multiple builder crates (src/organization/macro_recommendations.rs:119-131):

BUILDER PATTERN BOILERPLATE DETECTED: 5 builder structs

Consider using existing builder libraries:
- `bon` crate for declarative builders
- `typed-builder` for compile-time checked builders
- `derive_builder` for macro-based generation

This reduces boilerplate while maintaining type safety.

For Test Boilerplate

Detected boilerplate: 20 similar test functions
Estimated line reduction: 120 lines → 25 lines (79% reduction)

Recommendation:
- Use rstest with #[rstest] and #[case(...)] for parameterized tests
- Extract common test setup into fixture functions
- Use table-driven tests with Vec<TestCase> for data-driven testing

Integration with God Object Detection

Boilerplate detection prevents false positives in god object analysis:

  1. File with many impl blocks detected → Analyze trait patterns
  2. High complexity + many impls → Classified as GodObject (needs module splitting)
  3. Low complexity + many impls → Classified as BoilerplatePattern (needs macro-ification)
  4. Builder pattern detected → Classified as BuilderPattern (intentional design)

This distinction ensures appropriate recommendations for different code patterns.

Source: src/organization/god_object/classification_types.rs:45-50

See Also