m15-anti-pattern
actionbook/rust-skills
Identify and refactor Rust code anti-patterns during review.
What is m15-anti-pattern?
This skill helps you spot common Rust anti-patterns—like excessive cloning, unwrap in production, and fighting the borrow checker—and understand why they're problematic. Use it when reviewing code to diagnose design issues and suggest idiomatic alternatives.
- Recognize 8+ common anti-patterns (clone everywhere, unwrap in production, Rc misuse, unsafe for convenience, OOP via Deref, giant match arms, String overuse, ignored #[must_use])
- Distinguish between symptom and root cause (e.g., cloning indicates ownership design issues)
- Map anti-patterns to upstream design skills (m09-domain, m01-ownership) and downstream implementation skills (m06-error-handling, m02-resource)
- Provide quick refactoring guidance for each anti-pattern with concrete alternatives
- Identify code smells and suggest structural improvements (extract methods, clarify data flow, add encapsulation)
How to install m15-anti-pattern
npx skills add https://github.com/actionbook/rust-skills --skill m15-anti-patternHow to use m15-anti-pattern
- 1.When reviewing code, check the Quick Review Checklist for common issues
- 2.If you spot suspicious code, ask: Is this solving the symptom or the cause?
- 3.Use the Anti-Pattern → Better Pattern table to identify the issue and find the idiomatic alternative
- 4.Trace up to design skills (m09-domain, m01-ownership) if the root cause is architectural
- 5.Trace down to implementation skills (m06-error-handling, m02-resource) for concrete fixes
Use cases
- Review a colleague's code and spot why they're cloning everywhere, then trace back to ownership design
- Encounter unwrap() in production code and recommend proper error handling with ? or expect()
- See index-based loops and suggest iterator-based alternatives
- Identify String used where &str or Cow<str> would be more efficient
- Spot fighting-the-borrow-checker patterns and suggest data structure restructuring
- Rust code reviewers
- Developers learning idiomatic Rust patterns
- Team leads establishing code quality standards
- Developers refactoring legacy Rust code
m15-anti-pattern FAQ
Ask: Is this solving the symptom or the cause? If you're cloning to avoid borrow-checker errors, that's a symptom of unclear ownership (anti-pattern). If you're cloning a large struct once for performance reasons, that may be justified.
m01-ownership teaches reference patterns and ownership rules. This skill identifies when code violates those patterns and suggests fixes. Use m01 to learn, use this to review.
In library code, yes—propagate errors with ?. In binaries, unwrap is acceptable for truly unreachable cases, but prefer expect() with a message explaining why it can't fail.
It usually means your data structure doesn't match your ownership model. Restructure to own data outright, use references consistently, or consider Rc/Arc if shared ownership is needed.
When the cost is justified (e.g., cloning a small struct once) or when ownership semantics require it. If you're cloning to escape borrow-checker errors, restructure instead.
Full instructions (SKILL.md)
Source of truth, from actionbook/rust-skills.
name: m15-anti-pattern description: "Use when reviewing code for anti-patterns. Keywords: anti-pattern, common mistake, pitfall, code smell, bad practice, code review, is this an anti-pattern, better way to do this, common mistake to avoid, why is this bad, idiomatic way, beginner mistake, fighting borrow checker, clone everywhere, unwrap in production, should I refactor, 反模式, 常见错误, 代码异味, 最佳实践, 地道写法" user-invocable: false
Anti-Patterns
Layer 2: Design Choices
Core Question
Is this pattern hiding a design problem?
When reviewing code:
- Is this solving the symptom or the cause?
- Is there a more idiomatic approach?
- Does this fight or flow with Rust?
Anti-Pattern → Better Pattern
| Anti-Pattern | Why Bad | Better |
|---|---|---|
.clone() everywhere | Hides ownership issues | Proper references or ownership |
.unwrap() in production | Runtime panics | ?, expect, or handling |
Rc when single owner | Unnecessary overhead | Simple ownership |
unsafe for convenience | UB risk | Find safe pattern |
OOP via Deref | Misleading API | Composition, traits |
| Giant match arms | Unmaintainable | Extract to methods |
String everywhere | Allocation waste | &str, Cow<str> |
Ignoring #[must_use] | Lost errors | Handle or let _ = |
Thinking Prompt
When seeing suspicious code:
-
Is this symptom or cause?
- Clone to avoid borrow? → Ownership design issue
- Unwrap "because it won't fail"? → Unhandled case
-
What would idiomatic code look like?
- References instead of clones
- Iterators instead of index loops
- Pattern matching instead of flags
-
Does this fight Rust?
- Fighting borrow checker → restructure
- Excessive unsafe → find safe pattern
Trace Up ↑
To design understanding:
"Why does my code have so many clones?"
↑ Ask: Is the ownership model correct?
↑ Check: m09-domain (data flow design)
↑ Check: m01-ownership (reference patterns)
| Anti-Pattern | Trace To | Question |
|---|---|---|
| Clone everywhere | m01-ownership | Who should own this data? |
| Unwrap everywhere | m06-error-handling | What's the error strategy? |
| Rc everywhere | m09-domain | Is ownership clear? |
| Fighting lifetimes | m09-domain | Should data structure change? |
Trace Down ↓
To implementation (Layer 1):
"Replace clone with proper ownership"
↓ m01-ownership: Reference patterns
↓ m02-resource: Smart pointer if needed
"Replace unwrap with proper handling"
↓ m06-error-handling: ? operator
↓ m06-error-handling: expect with message
Top 5 Beginner Mistakes
| Rank | Mistake | Fix |
|---|---|---|
| 1 | Clone to escape borrow checker | Use references |
| 2 | Unwrap in production | Propagate with ? |
| 3 | String for everything | Use &str |
| 4 | Index loops | Use iterators |
| 5 | Fighting lifetimes | Restructure to own data |
Code Smell → Refactoring
| Smell | Indicates | Refactoring |
|---|---|---|
Many .clone() | Ownership unclear | Clarify data flow |
Many .unwrap() | Error handling missing | Add proper handling |
Many pub fields | Encapsulation broken | Private + accessors |
| Deep nesting | Complex logic | Extract methods |
| Long functions | Multiple responsibilities | Split |
| Giant enums | Missing abstraction | Trait + types |
Common Error Patterns
| Error | Anti-Pattern Cause | Fix |
|---|---|---|
| E0382 use after move | Cloning vs ownership | Proper references |
| Panic in production | Unwrap everywhere | ?, matching |
| Slow performance | String for all text | &str, Cow |
| Borrow checker fights | Wrong structure | Restructure |
| Memory bloat | Rc/Arc everywhere | Simple ownership |
Deprecated → Better
| Deprecated | Better |
|---|---|
| Index-based loops | .iter(), .enumerate() |
collect::<Vec<_>>() then iterate | Chain iterators |
| Manual unsafe cell | Cell, RefCell |
mem::transmute for casts | as or TryFrom |
| Custom linked list | Vec, VecDeque |
lazy_static! | std::sync::OnceLock |
Quick Review Checklist
- No
.clone()without justification - No
.unwrap()in library code - No
pubfields with invariants - No index loops when iterator works
- No
Stringwhere&strsuffices - No ignored
#[must_use]warnings - No
unsafewithout SAFETY comment - No giant functions (>50 lines)
Related Skills
| When | See |
|---|---|
| Ownership patterns | m01-ownership |
| Error handling | m06-error-handling |
| Mental models | m14-mental-model |
| Performance | m10-performance |
Related skills
More from actionbook/rust-skills and the wider catalog.

meta-cognition-parallel
Three-layer parallel meta-cognition analysis for Rust questions—language mechanics, design choices, and domain constraints.

rust-call-graph
Visualize Rust function call graphs and trace caller/callee relationships using LSP.

rust-code-navigator
Navigate Rust code with LSP: go to definition, find references, and explore symbols efficiently.

rust-daily
Fetch Rust community news and updates filtered by time range (daily, weekly, or monthly).

rust-deps-visualizer
Visualize Rust project dependencies as ASCII art trees with optional feature flags.

rust-learner
Fetch Rust versions, crate info, and API documentation from official sources.