m09-domain について
m09-domainは、Rust開発者向けのドメインモデリングスキルです。DDDの概念をRustの型やパターンに対応させ、不変条件、所有権、集約境界を踏まえた設計を支援します。
主な機能
- 01エンティティと値オブジェクトの区別
- 02DDD概念をRustパターンに対応
- 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)
-
どのような不変条件を満たす必要がありますか?
- 常に有効 → private フィールド + 検証済みコンストラクター
- 遷移ルール → 型状態パターン
-
このデータを所有するのは誰ですか?
- 単一の所有者(親) → 所有されるフィールド
- 共有参照 → 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-* | 2 つのインスタンスを「同じ」と見なす条件は何ですか? |
| 集約の境界 | 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); |
| エンティティ | Struct + ID | struct User { id: UserId, ... } |
| 集約 | モジュール境界 | mod order { ... } |
| リポジトリ | Trait | trait UserRepo { fn find(...) } |
| ドメインイベント | Enum | 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 対応