
Reduce Complexity
- 1 installs
- 1 repo stars
- Updated July 23, 2026
- ahrav/gossip-rs
reduce-complexity is a Claude Code skill that detects code complexity hotspots, classifies them as essential or accidental, and suggests reductions with safety annotations.
About
reduce-complexity analyzes code for complexity hotspots using evidence-based LOC, nesting, and parameter thresholds. It classifies each flagged function as essential (leave alone) or accidental (reducible) and produces reduction suggestions with safety annotations. It does not perform automated refactoring; it detects, explains why code is complex, and suggests fixes. The technique catalog is Rust-focused with a match-nesting discount.
- Detects complexity hotspots by LOC, nesting, and parameter thresholds
- Classifies complexity as essential vs accidental with safety annotations
- Suggests reductions using a 12-technique catalog (Rust emphasis)
Reduce Complexity by the numbers
- 1 all-time installs (skills.sh)
- Ranked #984 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Jul 24, 2026 (Skillselion catalog sync)
reduce-complexity capabilities & compatibility
- Capabilities
- complexity analysis · code review · refactoring triage · maintainability review
- Use cases
- code review · refactoring
- Pricing
- Free
What reduce-complexity says it does
Detect complexity hotspots, classify them as essential or accidental, and suggest specific reduction techniques with safety annotations.
Works on any language with emphasis on Rust-specific patterns. Does NOT perform automated refactoring -- it detects, explains, and suggests.
An exhaustive `match` on an enum with <= 6 variants counts as nesting +0 (no increment).
npx skills add https://github.com/ahrav/gossip-rs --skill reduce-complexityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1 |
| Last updated | July 23, 2026 |
| Repository | ahrav/gossip-rs ↗ |
What it does
Find complexity hotspots in code and get safety-annotated reduction suggestions without auto-refactoring.
Who is it for?
Maintainability reviews and refactor triage, especially in Rust codebases.
Skip if: Automated refactoring, performance optimization, or style/formatting - the docs redirect those to other tools.
When should I use this skill?
You are reviewing a file or module for maintainability, triaging tech debt, or looking for the highest-ROI refactoring targets.
What you get
A ranked list of complexity hotspots with essential/accidental classification and safety-annotated reduction suggestions.
- ranked hotspot list
- essential/accidental classification
- reduction suggestions with confidence levels
By the numbers
- 12 complexity reduction techniques catalog
- flags LOC 51-100 advisory to >400 critical
- caps output at 15 functions per file, 25 per directory
Files
Code Complexity Reduction
Detect complexity hotspots, classify them as essential or accidental, and suggest specific reduction techniques with safety annotations. The core value is not metric computation (Clippy already does that) but explaining WHY code is complex and WHETHER reduction is safe in context.
When to use
- Reviewing a file or module for maintainability
- Before refactoring, to identify the highest-ROI targets
- Triaging tech debt across a codebase or directory
- When a function feels hard to understand and you want to know why
- During code review of large or deeply nested functions
When NOT to use
- For code review (use code-review skills instead)
- For performance optimization (use performance-analyzer)
- For automated refactoring (use refactoring-assistant)
- For style/formatting issues (use cargo fmt / linters)
---
Input
| Form | Example | Behavior |
|---|---|---|
| File path | /reduce-complexity src/cache.rs | Analyze all functions in the file |
| Directory | /reduce-complexity src/ | Scan source files, report top-N hotspots |
| No argument | /reduce-complexity | Scan all non-test source files, report top-10 |
Exclude test files (*_tests.rs, tests/) from default scans unless explicitly passed. Test code has different complexity norms.
---
Analysis Pipeline
Execute these four phases in order. Read the target code before starting.
Phase 1: Detection
Enumerate every function in the target scope. For each, measure:
1. LOC -- lines from opening { to closing }, excluding blanks and comment-only lines 2. Max nesting depth -- with the Rust match discount (see below) 3. Parameter count -- including &self/&mut self 4. Unsafe presence -- whether the function body contains unsafe blocks 5. Clippy annotations -- any #[allow(clippy::...)] on the function or enclosing impl
Flag a function if ANY independent threshold triggers:
| Metric | Advisory | Moderate | High | Critical |
|---|---|---|---|---|
| LOC | 51-100 | 101-200 | 201-400 | >400 |
| Nesting | 4 | 5-6 | 7+ | -- |
| Params | 6-7 | 8+ | -- | -- |
Advisory items appear only in the codebase overview unless another metric also triggers.
Rank flagged functions by: number of thresholds exceeded (descending), then LOC (descending). Cap output at 15 functions per file, 25 per directory.
Why these metrics, not cyclomatic/cognitive complexity
LOC is the most stable defect predictor across all major studies (Menzies, Hatton, Lessmann). Cyclomatic complexity correlates with LOC at r > 0.9 -- it catches nothing LOC misses. Cognitive complexity adds only 5.26% accuracy and the Clippy team placed their implementation in the restriction group as unreliable for Rust. Independent threshold checks are transparent and evidence-based.
Rust match discount
An exhaustive match on an enum with <= 6 variants counts as nesting +0 (no increment). Rust's exhaustive matching is a type-safety mechanism, not decision complexity. A match on Result<T, E> or a 4-variant enum is idiomatic.
A match on a runtime value (integer, string) or an enum with >6 variants counts as normal nesting +1.
Phase 2: Classification
For each flagged function, read it and its surrounding context (enclosing impl, module doc, called functions). Classify as:
- ESSENTIAL -- complexity is inherent to the problem domain; leave alone
- ACCIDENTAL -- complexity is reducible; suggestions follow
- MIXED -- some essential, some accidental; suggestions target only the accidental part
Use these tests to make the judgment:
1. Domain necessity: Would a clean-room reimplementation solving the same problem have similar structure? If yes, the complexity is essential.
2. Error handling: Does each branch handle a semantically distinct error case with distinct recovery (logging, circuit breaker signaling, metrics, cleanup)? If yes, the branching is essential -- not reducible by collapsing.
3. Sequential coupling: Do steps have data or control dependencies preventing reordering? If yes, the sequential length is essential.
4. Accidental indicators: Duplicated logic blocks (same pattern 3+ times), deep nesting flattenable with early returns, boilerplate extractable to a helper, parameters always passed together (struct opportunity), conditions testing implementation state rather than domain state.
Include a 1-2 sentence rationale with each classification.
Phase 3: Suggestions
For ACCIDENTAL and MIXED functions, recommend specific techniques. Read references/techniques.md for the full catalog of 12 techniques with preconditions, contraindications, and presentation templates.
Techniques are classified by confidence:
| Category | Techniques | Confidence |
|---|---|---|
| Fully automatable (5) | Guard clauses, redundant else removal, remove unnecessary Result, pass by reference, type aliases | auto-apply or suggest |
| Judgment-required (4) | Extract function, ? operator, merge match arms, let-else | suggest or flag-for-review |
| Not automatable (3) | Collapse if-chains, polymorphism, decompose state machine | flag-for-review only |
Never suggest more than 3 techniques per function. More than 3 signals the function needs broader redesign, not incremental fixes. Say so explicitly.
Phase 4: Safety Checks
Apply these checks after generating suggestions. They can override or annotate output.
1. Unsafe exclusion zone: If the function contains unsafe, or calls a function in the same module that contains unsafe -- label "MANUAL REVIEW REQUIRED" and suppress all suggestions except guard clauses. Unsafe invariants (like set_len + truncate, #[repr(align)], FFI contracts) often span multiple statements and are invisible to any analysis.
2. Clippy annotation respect: If the function has #[allow(clippy::...)], note the developer made a deliberate decision. Do not suppress suggestions but lower confidence by one level.
3. Over-abstraction brake (for extract-function suggestions):
- Shallow module check: If
param_count + return_type_fields >= body_lines / 3,
warn that the extraction interface is nearly as complex as the body.
- Single call-site + high coupling: If the extracted code would be called from
exactly 1 site AND requires >3 parameters, warn about locality destruction.
- Zero intention gap: If the body is only stdlib/library calls with no domain
logic, warn that a function name adds no information.
4. Async boundary warning: If a suggestion involves extracting code containing .await points, warn about Send bound implications and recommend cargo check.
5. Validation requirement: Any accepted suggestion must pass cargo check + cargo clippy. Characterization tests alone are insufficient -- they miss Send/Sync violations and lifetime constraint breakages.
---
Output Format
Structure the report with these four sections:
Section 1: Hotspot Summary
A ranked table:
## Complexity Hotspots
| # | Function | Location | LOC | Nesting | Params | Flags | Class |
|---|----------|----------|-----|---------|--------|-------|-------|Flags use abbreviated severity: LOC:High, Nest:Mod, Params:Mod. Class is ESSENTIAL, ACCIDENTAL, or MIXED.
Section 2: Per-Function Analysis
One block per flagged function, in rank order:
### #N: `function_name` (file:line) -- CLASSIFICATION
**Metrics:** N LOC | max nesting M | K params
**Flags:** which thresholds triggered
**Why it is complex:** 2-3 sentences explaining the dominant complexity driver.
**Essential vs Accidental:** What is inherent to the domain vs what is structural.
**Suggestions:** (only for ACCIDENTAL/MIXED)
1. TECHNIQUE (confidence): explanation, before/after sketch, impact estimate
- Over-abstraction check result if applicable
- Safety warnings if applicableSection 3: Codebase Health Overview
Aggregate statistics:
## Codebase Health
| Metric | Value | Assessment |
|--------|-------|------------|
| Functions exceeding LOC threshold | N / total (%) | vs Pareto norm (10-20%) |
| Functions exceeding nesting threshold | N / total (%) | |
| Essential complexity ratio | N of M flagged (%) | Higher = more domain-inherent |
| Dominant complexity pattern | e.g. "sequential orchestration" | |
**Highest-ROI targets:** Functions with the most accidental complexity and
simplest extraction boundaries.Section 4: Essential Complexity Warnings
Functions that are complex but should NOT be simplified:
## Essential Complexity -- Leave Alone
| Function | Location | Why Essential |
|----------|----------|---------------|Close with: "Complex code takes 124% longer to resolve issues in (CodeScene, 39 codebases). This is a cognitive load effect -- the cost is developer time, not production failures. Rust's compiler eliminates many defect classes."
---
Supplementary Signals
When git history is available, use it to adjust ranking priority (not detection):
| Signal | Command | Effect |
|---|---|---|
| Change frequency | `git log --oneline -- <file> \ | wc -l` |
| Author count | `git log --format=%aN -- <file> \ | sort -u \ |
| Recency | git log --since=90d -- <file> | Recently changed functions ranked higher |
Process metrics outperform all static code metrics for defect prediction (Moser 2008).
Technique Catalog
12 complexity reduction techniques organized by automation confidence level. For each: preconditions (when to suggest), contraindications (when NOT to suggest), and a presentation template.
---
Fully Automatable (5 techniques)
1. Guard Clauses / Early Return
Confidence: auto-apply
Preconditions:
- Function body is wrapped in
if condition { ... long body ... } - The condition is a precondition check (None, bounds, state)
- The else branch is empty, a simple return, or absent
Contraindications:
- Both arms have substantial logic (this is an if-else, not a guard)
- Function is inside
unsafewhere early return could skip invariant restoration
Template:
SUGGESTION: Convert to guard clause (auto-apply)
The if-block at line N wraps M lines of code. Inverting the condition and
returning early reduces nesting by 1 level:
if <inverted_condition> { return <value>; }
// ... M lines at reduced nesting ...
Impact: -1 nesting level for M lines.---
2. Redundant Else Removal
Confidence: auto-apply
Preconditions:
- An
ifblock ends withreturn,continue,break, or?propagation - An
elseblock follows immediately
Contraindications:
- The else introduces bindings used after the if-else (scope change)
- The if-else symmetry is intentional documentation (parallel case handling)
Template:
SUGGESTION: Remove redundant else (auto-apply)
The if-branch at line N returns/breaks. The else keyword and braces can be
removed, reducing nesting by 1 level for N remaining lines.---
3. Remove Unnecessary Result
Confidence: auto-apply
Preconditions:
- Function returns
Result<T>orResult<T, E> - No code path returns
Err(...) - Not a trait implementation (where the signature is fixed)
Contraindications:
- Trait method implementation (Result required by trait)
- Intentional for future extensibility (check for TODO comments)
- Public API where removing Result is a breaking change
Template:
SUGGESTION: Remove unnecessary Result (auto-apply)
fn X() -> Result<T> never returns Err. The Result wrapper forces callers to
handle an impossible error. Consider returning T directly.
Note: Breaking change for public APIs. Callers using `?` need updating.---
4. Pass by Reference
Confidence: suggest
Preconditions:
- Parameter takes ownership (String, Vec, PathBuf, etc.)
- Parameter is only read inside the function (no move, no return)
Contraindications:
- Parameter is
Clone + 'staticand the function spawns async tasks capturing it - Parameter is moved into a struct or collection
- Trait implementation with fixed signature
Box<dyn Trait>(ownership is idiomatic for trait objects)
Template:
SUGGESTION: Pass by reference (suggest)
Parameter `X: String` at line N is only read. Consider `X: &str` to avoid
unnecessary cloning at call sites.
CAVEAT: If called from async contexts needing 'static bounds, ownership
may be required. Verify with `cargo check`.---
5. Type Alias for Repeated Complex Types
Confidence: auto-apply
Preconditions:
- Same generic type signature appears 3+ times in the file/module
- Not a framework-constrained type (e.g., Pingora trait types)
Contraindications:
- Type appears only in trait bounds (aliasing bounds is non-idiomatic)
- Already an alias
- Only in test code
Template:
SUGGESTION: Introduce type alias (auto-apply)
`Arc<RwLock<HashMap<K, V>>>` appears N times. Consider:
type SharedMap = Arc<RwLock<HashMap<K, V>>>;
Reduces visual noise and creates a single point of change.---
Judgment-Required (4 techniques)
6. Extract Function
Confidence: flag-for-review
Preconditions:
- A contiguous block of 20+ lines with:
- Clear single responsibility (identifiable by a comment or paragraph break)
- Uses <= 3 variables from the enclosing scope
- Produces a single output
Contraindications:
- Block contains
unsafeor sits between unsafe and its invariant-restoring code - Block crosses an
.awaitboundary AND captures non-Send types - Block uses
&'static self(propagation is non-obvious) - Shallow module brake:
param_count + return_fields >= body_lines / 3 - Single call-site + high coupling: only called from 1 place AND >3 params
- Zero intention gap: body is only stdlib calls (name adds nothing)
Template:
SUGGESTION: Extract function (flag-for-review)
Lines N-M (<purpose>) could be extracted:
- Uses K variables from enclosing scope
- Produces: <output description>
- Unsafe: none / PRESENT (manual review required)
- Async boundaries: none / PRESENT (Send bound warning)
Proposed: fn <name>(<params>) -> <return>
OVER-ABSTRACTION CHECK:
Interface: K params + M return fields = J
Body: L lines
Ratio: J/L = X (threshold: 0.33)
Result: PASS / WARN: extraction may increase net complexity
CAUTION: Verify the extraction improves readability for someone unfamiliar
with this module. If the name would be "do_the_next_thing", skip it.---
7. ? Operator Replacement
Confidence: suggest
Preconditions:
- Match on Result/Option where Err/None arm returns early with the error
- Ok/Some arm extracts the value and continues
Contraindications:
- Err arm has side effects (circuit breaker signaling, metrics, logging with context)
- Err arm handles specific error types differently (e.g., ESTALE vs EIO)
- Match is on a domain type where
?would lose error discrimination
Template:
SUGGESTION: Replace match with ? (suggest)
The match at line N extracts Ok(val) and returns on Err with no side effects.
Simplify to: let val = expression?;
NOTE: Verify the Err arm has no side effects. NFS error handling in this
codebase often includes ESTALE detection and circuit breaker signaling
that would be lost with `?`.---
8. Merge Match Arms
Confidence: suggest
Preconditions:
- Two+ match arms with identical bodies
- Patterns combinable with
|
Contraindications:
- Arms are intentionally separate for future divergence (check for TODO comments)
- Arms represent semantically distinct domain concepts even with same current handling
- Match is on an error type where each variant has distinct operational meaning
Template:
SUGGESTION: Merge match arms (suggest)
Arms at lines N and M have identical bodies. Consider:
Pattern1 | Pattern2 => { ... }
NOTE: Only merge if identical handling is intentional and permanent. If
these may diverge, separate arms are better documentation.---
9. let-else Replacement
Confidence: suggest
Preconditions:
if let Some(x) = expr { ... long body ... } else { return/continue; }- Happy path body is > 5 lines
- Else branch is a simple divergence (return, continue, break)
Contraindications:
- Else branch has multi-statement logic (metrics, logging, state transitions)
- Else branch exceeds 3 lines
Template:
SUGGESTION: Replace if-let with let-else (suggest)
Rewrite at line N:
let Some(x) = expr else { return; };
// ... happy path at reduced nesting ...
Reduces nesting by 1 level for N lines.
NOTE: Only appropriate when the else is a simple divergence. Keep if-let
when the else has logging, metrics, or cleanup.---
Not Automatable (3 techniques)
10. Collapse If-Chains
Confidence: flag-for-review
Preconditions:
- Sequential if-checks testing related conditions
- Could theoretically combine with
&&or restructure as match
Contraindications:
- Each if has side effects between checks (logging, metrics, state)
- Chain is a documented pipeline with per-step purpose comments
- Steps have data dependencies where intermediate results are used later
Template:
FLAG: Sequential if-chain (flag-for-review)
Lines N-M contain K sequential if-checks. This may be:
(a) A pipeline with essential sequential coupling -- leave as-is
(b) Redundant checks that could be consolidated
Review purpose of each check. Only consolidate if all checks are pure
preconditions with no intermediate side effects.---
11. Replace Conditional with Polymorphism
Confidence: flag-for-review
Preconditions:
- Large match/if-else dispatching on a type/variant with >20 lines per arm
- Same dispatch pattern appears in multiple functions
Contraindications:
- Dispatch is on runtime data, not type variants
- Framework constrains the trait hierarchy
- Only one function has this pattern (polymorphism for a single dispatch is over-engineering)
Template:
FLAG: Repeated type dispatch (flag-for-review)
The dispatch at line N on <type> with K arms (>20 lines each) appears
in N locations. This MAY suit a trait-based design, but requires evaluating:
1. Whether the dispatch pattern is stable
2. Whether variants share sufficient interface
3. Whether framework constraints allow it
This skill does not make this recommendation automatically.---
12. Decompose State Machine
Confidence: flag-for-review
Preconditions:
- Function > 200 LOC with sequential stages separated by error handling
- Multiple match expressions on intermediate results
- Name or comments indicate multi-step process
Contraindications:
- Stages have essential sequential coupling (each depends on previous output)
- Error handling is distinct and stage-specific
- Function handles NFS/IO where scattering recovery narrative harms incident response
Template:
FLAG: Multi-stage sequential function (flag-for-review)
K identifiable stages over N lines, each with stage-specific error handling.
Sequential state machines (create -> write -> fsync -> rename) intentionally
keep all stages visible in one function so the full error recovery narrative
is readable in one place. Decomposition scatters this across K functions.
Consider decomposition ONLY if:
- Stages are independently testable
- Error handling is uniform across stages
- Function exceeds 400 LOC AND has accidental complexity beyond the
sequential structure itselfRelated skills
FAQ
Does it refactor the code for me?
No. It detects, explains, and suggests reductions with safety annotations but never performs automated refactoring.
Why not cyclomatic or cognitive complexity?
The docs note cyclomatic complexity correlates with LOC at r > 0.9 and cognitive complexity adds only about 5% accuracy, so it uses transparent LOC/nesting thresholds.