m15-anti-pattern
SKILL.md
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 |
Weekly Installs
35
Repository
zhanghandong/rust-skillsInstalled on
opencode27
claude-code26
gemini-cli24
codex22
antigravity18
github-copilot16