关于 m09-domain
m09-domain 是面向 Rust 开发者的领域建模技能,帮助将 DDD 概念映射为 Rust 类型与模式,并结合不变量、所有权和聚合边界作出设计选择。
主要功能
- 01区分实体与值对象
- 02用 Rust 模式表达 DDD 概念
- 03围绕不变量设计类型
- 04明确聚合与所有权边界
- 05提供模式模板和常见错误参考
适用场景
- 01为业务概念选择实体或值对象
- 02设计聚合根及其子对象
- 03为领域类型添加验证规则
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ actionbook/ rust-skills --skill m09-domain安装后在 Claude Code 中输入/m09-domain确认已加载。
详细介绍
领域建模
第 2 层:设计选择
核心问题
这个概念在领域中扮演什么角色?
在代码中建模之前,请先了解:
- 它是实体(身份很重要)还是值对象(可互换)?
- 必须维护哪些不变量?
- 聚合边界在哪里?
领域概念 → Rust 模式
| 领域概念 | Rust 模式 | 所有权影响 |
|---|---|---|
| 实体 | struct + Id | 独立拥有,身份唯一 |
| 值对象 | struct + Clone/Copy | 可共享,不可变 |
| 聚合根 | struct 拥有子对象 | 所有权树清晰 |
| 仓储 | trait | 抽象持久化 |
| 领域事件 | enum | 捕获状态变化 |
| 服务 | impl 块 / 自由函数 | 无状态操作 |
思考提示
创建领域类型之前:
-
这个概念的身份是什么?
- 需要唯一身份 → 实体(Id 字段)
- 按值可互换 → 值对象(Clone/Copy)
-
必须满足哪些不变量?
- 始终有效 → 私有字段 + 经过验证的构造函数
- 状态转换规则 → 类型状态模式
-
谁拥有这些数据?
- 单一所有者(父对象) → 自有字段
- 共享引用 → Arc/Rc
- 弱引用 → Weak
向上追溯 ↑
至领域约束(第 3 层):
"How should I model a Transaction?"
↑ Ask: What domain rules govern transactions?
↑ Check: domain-fintech (audit, precision requirements)
↑ Check: Business stakeholders (what invariants?)
| 设计问题 | 追溯至 | 提问 |
|---|---|---|
| 实体还是值对象 | domain-* | 什么使两个实例“相同”? |
| 聚合边界 | domain-* | 哪些内容必须保持一致? |
| 验证规则 | domain-* | 适用哪些业务规则? |
向下追溯 ↓
至实现(第 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
快速参考
| DDD 概念 | Rust 模式 | 示例 |
|---|---|---|
| 值对象 | Newtype | struct Email(String); |
| 实体 | 结构体 + ID | struct User { id: UserId, ... } |
| 聚合 | 模块边界 | mod order { ... } |
| 仓储 | Trait | trait UserRepo { fn find(...) } |
| 领域事件 | 枚举 | enum OrderEvent { Created, ... } |
模式模板
值对象
struct Email(String);
impl Email {
pub fn new(s: &str) -> Result<Self, ValidationError> {
validate_email(s)?;
Ok(Self(s.to_string()))
}
}
实体
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
}
}
聚合
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
}
}
}
常见错误
| 错误 | 错误原因 | 更好的做法 |
|---|---|---|
| 过度依赖基本类型 | 缺乏类型安全 | 使用 Newtype 包装类型 |
| 含有不变量的公开字段 | 不变量可能被破坏 | 使用私有字段 + 访问器 |
| 泄露聚合内部细节 | 封装被破坏 | 在根上定义方法 |
| 用 String 表示语义类型 | 无法验证 | 使用经过验证的 Newtype |
相关技能
| 适用情形 | 参阅 |
|---|---|
| 类型驱动实现 | m05-type-driven |
| 聚合的所有权 | m01-ownership |
| 领域错误处理 | m13-domain-error |
| 特定领域规则 | domain-* |
评论
支持 Markdown