Rust’s ownership model and compiler strictness are supposed to guide developers toward better code. Yet when I analyzed 27 open-source Rust repositories, I found long functions in every single one. The language’s type system catches memory bugs, but it doesn’t stop a function from growing to 500 lines or accumulating a cyclomatic complexity score that makes testing impractical.
Methodology
I computed activity risk for functions across all 27 repositories by combining structural complexity (cyclomatic complexity × nesting depth × fan-out) with recent commit frequency. Functions that are both complex and actively changing score highest—these represent the most urgent refactoring candidates. The analysis window covered recent git history to weight actively-maintained code over legacy modules.
The Most Common Antipatterns
Long functions appeared in 27 of 27 repositories—a perfect score that should concern no one familiar with real-world codebases. Rust’s pattern matching and explicit error handling often encourage developers to keep related logic together rather than split it across helper functions. This isn’t inherently wrong, but it creates maintenance problems when a single function handles multiple responsibilities.
Exit-heavy functions showed up in 26 of 27 repos. This pattern reflects Rust’s idiomatic use of early returns with the ? operator and explicit return statements for error cases. While early returns can improve readability, excessive exit points scatter control flow and make it harder to reason about a function’s invariants. The language encourages this style, so Rust teams need to be more deliberate about function boundaries.
Complex branching appeared in 25 of 27 repositories. Match expressions are powerful, but they also make it easy to accumulate high cyclomatic complexity within a single function. When a match statement handles ten variants, each with its own logic, you’ve created a function that’s difficult to test exhaustively.
The Highest-Risk Repositories
DioxusLabs/dioxus recorded the highest risk score at 41.1—more than double the median. The primary drivers were long functions, god functions, and neighbor risk, suggesting that complex functions are calling other complex functions. This creates a cascade where touching one hotspot forces you to understand its entire call neighborhood.
nushell/nushell followed at 37.1, with complex branching and deep nesting as the main contributors. Shell implementations tend toward intricate parsing and evaluation logic, but a score this high indicates functions that have grown beyond reasonable maintainability.
astral-sh/ruff came in at 26.0, driven by long functions, god functions, and complex branching. Linter implementations are inherently complex—they must handle every syntactic edge case—but the concentration of risk in specific functions suggests opportunities to extract rule-specific logic into smaller units.
juspay/hyperswitch scored 21.2, with patterns centered on complex branching, deep nesting, and exit-heavy functions. Payment processing involves significant conditional logic, but the combination of these three patterns in the same functions creates maintenance friction.
vercel-labs/agent-browser registered 21.7, showing similar patterns to hyperswitch: complex branching, deep nesting, and exit-heavy code. Browser automation logic tends to accumulate conditionals as edge cases are discovered and handled inline.
What This Means for Rust Developers
The 100% prevalence of long functions suggests this is a cultural pattern, not an accident. Rust’s emphasis on explicit control flow—combined with the ergonomic cost of creating new types and traits—pushes developers toward keeping logic in fewer, larger functions. The compiler won’t complain, and the code will run correctly, but you’re accumulating structural debt that makes future changes riskier.
The median top risk score of 18.9 is moderate, but the spread matters. DioxusLabs/dioxus at 41.1 is more than twice the median, indicating that some codebases have significant concentrations of complexity. If your repository has similar patterns, focus refactoring effort on functions that score high on activity risk—they’re complex, they’re changing, and they’re likely to cause problems during your next feature push.
Analyze Your Own Repository
You can run the same analysis on any local Rust repository. Install the CLI:
brew install Stephen-Collins-tech/tap/hotspots
Or on any platform with Cargo:
cargo install hotspots-cli
Then run:
hotspots analyze .
The output will show your highest-risk functions ranked by activity risk, along with the specific antipatterns driving each score.