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