<< All versions
Skill v1.0.1
currentAutomated scan100/100actionbook/rust-skills/m09-domain
3 files
──Details
PublishedMay 14, 2026 at 09:08 PM
Content Hashsha256:a05f32b475b01d63...
Git SHA37e050f490a7
Bump Typepatch
──Files
Files (1 file, 4.2 KB)
SKILL.md4.2 KBactive
SKILL.md · 176 lines · 4.2 KB
version: "1.0.1" name: m09-domain description: "CRITICAL: Use for domain modeling. Triggers: domain model, DDD, domain-driven design, entity, value object, aggregate, repository pattern, business rules, validation, invariant, 领域模型, 领域驱动设计, 业务规则" user-invocable: false
Domain Modeling
Layer 2: Design Choices
Core Question
What is this concept's role in the domain?
Before modeling in code, understand:
- Is it an Entity (identity matters) or Value Object (interchangeable)?
- What invariants must be maintained?
- Where are the aggregate boundaries?
Domain Concept → Rust Pattern
| Domain Concept | Rust Pattern | Ownership Implication | |
|---|---|---|---|
| Entity | struct + Id | Owned, unique identity | |
| Value Object | struct + Clone/Copy | Shareable, immutable | |
| Aggregate Root | struct owns children | Clear ownership tree | |
| Repository | trait | Abstracts persistence | |
| Domain Event | enum | Captures state changes | |
| Service | impl block / free fn | Stateless operations |
Thinking Prompt
Before creating a domain type:
- What's the concept's identity?
- Needs unique identity → Entity (Id field)
- Interchangeable by value → Value Object (Clone/Copy)
- What invariants must hold?
- Always valid → private fields + validated constructor
- Transition rules → type state pattern
- Who owns this data?
- Single owner (parent) → owned field
- Shared reference → Arc/Rc
- Weak reference → Weak
Trace Up ↑
To domain constraints (Layer 3):
"How should I model a Transaction?"↑ Ask: What domain rules govern transactions?↑ Check: domain-fintech (audit, precision requirements)↑ Check: Business stakeholders (what invariants?)
| Design Question | Trace To | Ask | |
|---|---|---|---|
| Entity vs Value Object | domain-* | What makes two instances "the same"? | |
| Aggregate boundaries | domain-* | What must be consistent together? | |
| Validation rules | domain-* | What business rules apply? |
Trace Down ↓
To implementation (Layer 1):
"Model as Entity"↓ m01-ownership: Owned, unique↓ m05-type-driven: Newtype for Id"Model as Value Object"↓ m01-ownership: Clone/Copy OK↓ m05-type-driven: Validate at construction"Model as Aggregate"↓ m01-ownership: Parent owns children↓ m02-resource: Consider Rc for shared within aggregate
Quick Reference
| DDD Concept | Rust Pattern | Example | |
|---|---|---|---|
| Value Object | Newtype | struct Email(String); | |
| Entity | Struct + ID | struct User { id: UserId, ... } | |
| Aggregate | Module boundary | mod order { ... } | |
| Repository | Trait | trait UserRepo { fn find(...) } | |
| Domain Event | Enum | enum OrderEvent { Created, ... } |
Pattern Templates
Value Object
rust
struct Email(String);impl Email {pub fn new(s: &str) -> Result<Self, ValidationError> {validate_email(s)?;Ok(Self(s.to_string()))}}
Entity
rust
struct UserId(Uuid);struct User {id: UserId,email: Email,// ... other fields}impl PartialEq for User {fn eq(&self, other: &Self) -> bool {self.id == other.id // Identity equality}}
Aggregate
rust
mod order {pub struct Order {id: OrderId,items: Vec<OrderItem>, // Owned children// ...}impl Order {pub fn add_item(&mut self, item: OrderItem) {// Enforce aggregate invariants}}}
Common Mistakes
| Mistake | Why Wrong | Better | |
|---|---|---|---|
| Primitive obsession | No type safety | Newtype wrappers | |
| Public fields with invariants | Invariants violated | Private + accessor | |
| Leaked aggregate internals | Broken encapsulation | Methods on root | |
| String for semantic types | No validation | Validated newtype |
Related Skills
| When | See | |
|---|---|---|
| Type-driven implementation | m05-type-driven | |
| Ownership for aggregates | m01-ownership | |
| Domain error handling | m13-domain-error | |
| Specific domain rules | domain-* |