rust-course's rustlings-zh entry points carry the highest structural debt — 2 functions to address first

Two functions in assets/rustlings-zh/src/main.rs — watch (CC 22) and main (CC 23) — account for both critical-band hotspots in sunface/rust-course, untouched for 1,158 days and overdue for structural decomposition.

Stephen Collins ·
oss rust refactoring code-health
Activity Risk14.91Low
Hottest Functionwatch

Antipatterns Detected

exit_heavy3complex_branching1deeply_nested1long_function1stale_complex1

Key Points

What is an exit-heavy function and why does it matter in rust-course?

An exit-heavy function is one with multiple distinct return or early-exit points scattered throughout its body — each exit represents a separate execution path that must be covered by tests to verify correct behavior. The problem is compounded when those exits are embedded inside deeply nested control structures, because a reviewer must mentally trace every combination of conditions to understand which exit fires under which circumstances. In rust-course, 3 of the top hotspot functions are flagged as exit-heavy, both concentrated in `assets/rustlings-zh/src/main.rs`. Without explicit test coverage for each exit path, any future change to `watch` or `main` risks silently breaking one of those paths — and with cyclomatic complexity scores of 22 and 23, there are a lot of paths to break.

How do I reduce cyclomatic complexity in Rust?

The most effective technique is extract-method refactoring: identify cohesive clusters of branches — for example, all logic related to argument parsing or all logic related to a single subcommand — and move them into their own named functions. A cyclomatic complexity above 15 warrants splitting; above 20, as with both `watch` (CC 22) and `main` (CC 23) in rust-course, splitting should happen before the next modification to avoid regression risk. A concrete first step today is to run `cargo clippy -- -W clippy::cognitive_complexity` to get compiler-assisted identification of the most complex blocks inside these functions, then extract the largest self-contained block into a helper. That single extraction typically cuts CC by 30–50% and immediately reduces the number of paths that must be tested together.

Is rust-course actively maintained?

The broader rust-course repository shows ongoing commit activity at the repo level, but the two highest-risk functions — `watch` and `main` in `assets/rustlings-zh/src/main.rs` — have each recorded zero touches in the last 30 days and have not been modified in 1,158 days. All 14 debt-quadrant functions share this pattern of zero recent activity, and no functions currently occupy the fire quadrant. This means the course content is likely being updated regularly while the embedded rustlings-zh tooling has been left largely stable — active maintenance of a project and the presence of structural debt in a dormant subsystem are not mutually exclusive, and the debt here is real regardless of overall repo health.

How do I reproduce this analysis?

The analysis was produced by the hotspots CLI, available at https://github.com/hotspots-dev/hotspots, against commit `b89a0a4` of sunface/rust-course. After running `git checkout b89a0a4` in a local clone, execute `hotspots analyze . --mode snapshot --explain-patterns --force` to reproduce the exact results. The same command works on any local git repository without additional configuration.

What does activity-weighted risk mean?

Activity-weighted risk multiplies structural complexity — derived from cyclomatic complexity, nesting depth, and fan-out — by a recent commit frequency score, so that functions which are both hard to understand and actively changing score the highest. A function with cyclomatic complexity 80 that has not been touched in two years scores much lower than one with CC 20 that is touched every week, because the dormant function has low near-term regression risk regardless of its internal complexity. In rust-course, the top two functions score highest despite zero recent touches because their structural complexity alone is high enough to create significant blast-radius risk the moment development resumes. This prioritization helps teams focus refactoring effort where it will most reduce the probability of introducing bugs — not just where the code appears complicated in the abstract.

The dominant risk in sunface/rust-course is structural debt, not active churn: the two highest-risk functions — watch and main in assets/rustlings-zh/src/main.rs — have sat untouched for 1,158 days while carrying cyclomatic complexity scores of 22 and 23 respectively. rust-course is a comprehensive Rust learning resource with 167 analyzed functions, of which 3 score in the top risk band and all 14 structurally complex functions have zero recent activity. No functions are both highly complex and actively changing right now, which means the immediate concern is not live regression risk but the blast radius that awaits the next developer who needs to modify these entry points.

The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).

Top 5 Hotspots

FunctionFileRiskCCNDFO
watchassets/rustlings-zh/src/main.rs14.922510
mainassets/rustlings-zh/src/main.rs10.32329
qassets/bigPicture.js9.41237
stateassets/rustlings-zh/src/exercise.rs8.4515
all_exercises_require_confirmationassets/rustlings-zh/tests/integration_tests.rs7.8413

Codemod / Tooling Files in Results

Both top-ranked functions — watch and main — are located under assets/rustlings-zh/src/main.rs, which is a vendored or bundled copy of the rustlings exercise runner adapted for Chinese learners rather than first-party application logic. Because this is embedded tooling rather than the course content itself, teams may reasonably choose to exclude it from routine hotspot tracking. To suppress these results, add the following to .hotspotsrc.json: { "exclude": ["assets/rustlings-zh/"] }. That said, if the project maintains and ships this tooling, the structural debt findings remain valid and actionable.

Hotspot Analysis

watch — assets/rustlings-zh/src/main.rs

Based on its name and location in the rustlings-zh exercise runner, watch almost certainly implements the file-watching event loop that monitors exercise files for changes and re-runs verifications — the kind of function that branches on file events, exercise states, and user input simultaneously. Its cyclomatic complexity of 22 means there are 22 independent execution paths through it, each a required test case; a max nesting depth of 5 confirms that some of those paths involve deeply nested conditionals that are hard to reason about in isolation. With a fan-out of 10 and three exit-heavy paths, this function carries significant structural debt and hasn’t been touched in 1,158 days — high blast radius when next changed.

Recommendation: Add characterization tests that cover the observable exit behaviors before touching this function, then extract the distinct responsibilities (event detection, state transitions, user feedback) into smaller focused functions to bring CC below 10.

main — assets/rustlings-zh/src/main.rs

As the top-level entry point for the rustlings-zh CLI, main likely handles argument parsing, subcommand dispatch, and initialization — a classic long-function accumulation point. Its cyclomatic complexity of 23 is the highest in the dataset, meaning there are at least 23 paths through the startup logic alone; the long_function and stale_complex patterns both flagged here suggest this function has grown to absorb responsibilities over time and has not been refactored in 1,158 days. Fan-out of 9 means changes here reach broadly into the codebase, compounding the blast radius.

Recommendation: Apply extract-method refactoring to separate argument parsing, subcommand routing, and initialization into distinct functions; the goal is to reduce CC to under 10 per extracted unit, making each independently testable.

Patterns Found

Antipatterns detected across the top functions in this snapshot:

PatternOccurrences
exit_heavy3
complex_branching1
deeply_nested1
long_function1
stale_complex1

These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.

Key Takeaways

  • Both critical-band functions live in assets/rustlings-zh/src/main.rs and have been untouched for 1,158 days — before any new development push on this tooling, add characterization tests to document current behavior and reduce blast-radius risk.
  • The main function’s cyclomatic complexity of 23 combined with the long_function and stale_complex patterns is a strong signal to apply extract-method refactoring: break subcommand dispatch, argument parsing, and initialization into separate functions each with CC under 10.
  • The watch function’s three exit-heavy paths and nesting depth of 5 mean test coverage is the critical gap — enumerate and test each exit condition explicitly before any structural changes to avoid silent regressions.

Reproduce This Analysis

git clone https://github.com/sunface/rust-course
cd rust-course
git checkout b89a0a41a70be13df49cc94cd739b97084af3f00
hotspots analyze . --mode snapshot --explain-patterns --force

To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.

Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →

Run this on your own codebase

Hotspots runs locally in under a minute — no account, no data leaves your machine.

macOS
$ brew install Stephen-Collins-tech/tap/hotspots
Linux / cargo
$ cargo install hotspots-cli
Run in any repo
$ hotspots analyze .
★ Star on GitHub

Related Analyses