第07章:用語セット(Command / Event / State / Projection)📮📜🧠🔎
今日のゴール🎯✨
この章を読み終わったら、次の4語を混ぜずに話せる&書けるようになります😊💪
- Command:やって!のお願い(命令)📮
- Event:やった!の記録(出来事)📜
- State:いまどうなってる?の状態🧠
- Projection:見やすい形に整えた表示用データ🔎
まずは“1行ずつ”で覚えよう📌😊
Command(コマンド)📮
- ひとことで:システムに「こうして!」と頼む“お願い”🙋♀️
- 形:命令形(Add / Remove / Change など)
- ポイント:まだ成功してるか分からない(失敗するかも)😵💫
例(買い物カート)🛒
AddItemToCart(カートに商品を追加して!)RemoveItemFromCart(商品を削除して!)
Event(イベント)📜
- ひとことで:起きた事実を“過去形で”記録したもの📖
- 形:過去形(Added / Removed / Changed など)
- ポイント:「起きた」ことなので、基本は後から書き換えない✋
- イベントソーシングのコア:状態の変化をイベントとして残し、イベント列から状態を再現できる考え方🌱 (イベントが“真実の履歴”になるイメージ) (martinfowler.com)
例(買い物カート)🛒
ItemAddedToCart(商品が追加された)ItemRemovedFromCart(商品が削除された)
State(状態)🧠
- ひとことで:「今この瞬間のカートはこう!」という“結果”📸
- 形:合計金額、商品一覧、数量など
- ポイント:イベント列を順に適用(Apply)して作れる🔁
例(買い物カート)🛒
- Items:[(りんご, 2), (みかん, 1)]
- Total:580円
Projection(プロジェクション)🔎
- ひとことで:画面・検索・一覧のために、読みやすい形へ作り直したデータ📋✨
- ポイント:書き込みモデル(厳密)と、読みモデル(見やすい)を分ける発想と相性が良いよ😊 (読みと書きを分けて最適化する考え方はCQRSでもよく語られるよ) (Microsoft Learn)
- 実装イメージ:イベントを受け取って“表示用の表”を更新する💡 (EventStoreDB系の世界だと“Projections”という名前で仕組みが用意されていたりする) (Kurrent Docs)
例(買い物カート)🛒
- 画面用:
CartSummary(商品数、合計、最後に更新した時間…など) - 一覧用:
CartListRow(カートID、合計、アイテム数)
4語の関係を“1枚”で理解🧠🖼️

(ユーザー) (システム)
│ │
│ Command 📮 │ 「やって!」
├──────────────▶ Decide(判断)🧠
│ │ 不変条件チェック✅
│ │
│ │ Event 📜 「やった!」
│ ├───────────▶ Event Store(履歴)📚
│ │
│ │ State 🧠(いまの状態)
│ └── Apply 🔁(イベントを適用)
│
│ Projection 🔎(表示用)
└──────────────▶ 画面/検索/一覧に使う📋✨
覚え方の合言葉💬✨
- Command = お願い📮
- Event = 事実📜
- State = 現在地🧠
- Projection = 見せ方🔎
“混ぜると事故る”あるある集🚑😵💫
事故①:イベントを命令形で作っちゃう📜❌
- ❌
AddItemToCart(命令)をイベントとして保存 - ✅
ItemAddedToCart(事実)をイベントとして保存 👉 イベントは「起きたこと」なので過去形が超大事⏳✨
事故②:コマンドに“結果”を書いちゃう📮❌
- ❌
AddItemSucceeded(もう成功してる前提になってる) - ✅
AddItemToCart(お願い) → 成功したらItemAddedToCart(事実) 👉 成功したかどうかは判断のあとに決まるよ🧠✅
事故③:Projectionを“真実”として編集しはじめる🔎❌
- ❌ 画面用テーブルを直接更新して「これが正!」にする
- ✅ **イベント(履歴)**が正で、Projectionは“派生物”🌿 👉 Projectionは壊れても作り直せる思想が強いよ🔁🧹
事故④:Stateを保存して「イベントソーシングです!」って言っちゃう🧠❌
- 状態保存は全然悪くないけど、イベントソーシングは「状態変化をイベントで残す」が核🌱 (martinfowler.com) 👉 “履歴”が残る設計が欲しい時に効いてくる💪📚
事故⑤:イベントにUI都合の項目を入れすぎる📜🍱❌
- ❌
ButtonColor = "Red"みたいな“画面都合”が混ざる - ✅ 「事実」として意味がある情報だけ(誰が/何を/いくつ/いつ など)🧾✅ 👉 UIはProjection側で好きに整えよう🔎✨
ミニ演習:要件を4分類してみよう🗂️😊
お題:カートの要件(例)🛒
次の文章を、Command / Event / State / Projection に分類してね✍️✨
- 「商品をカートに追加したい」
- 「商品が追加された履歴を残したい」
- 「今の合計金額を表示したい」
- 「カート一覧画面で “アイテム数” をすぐ見たい」
- 「商品を削除したい」
- 「今カートに入ってる商品一覧がほしい」
- 「“いつ誰が追加したか” が追えるようにしたい」
- 「検索で“合計金額が1000円以上のカート”を出したい」
ヒント💡
- 「〜したい」→ Command候補📮
- 「〜された」→ Event候補📜
- 「今どうなってる」→ State候補🧠
- 「画面で早く見たい / 検索したい」→ Projection候補🔎
ちいさなC#例:型を分けるだけで事故が減る🧩😊
ここでは“用語を混ぜない”ために、名前と型の置き場所を分ける練習をするよ✍️✨
// Command 📮(お願い): 命令形
public sealed record AddItemToCart(Guid CartId, string Sku, int Quantity);
// Event 📜(事実): 過去形
public sealed record ItemAddedToCart(Guid CartId, string Sku, int Quantity, DateTimeOffset OccurredAt);
// State 🧠(現在の状態): Event列をApplyして作る
public sealed class CartState
{
private readonly Dictionary<string, int> _items = new();
public IReadOnlyDictionary<string, int> Items => _items;
public void Apply(ItemAddedToCart e)
{
_items.TryGetValue(e.Sku, out var current);
_items[e.Sku] = current + e.Quantity;
}
}
// Projection 🔎(表示用): 画面のための形
public sealed class CartSummaryProjection
{
public Guid CartId { get; private set; }
public int TotalItems { get; private set; }
public DateTimeOffset LastUpdatedAt { get; private set; }
public void When(ItemAddedToCart e)
{
CartId = e.CartId;
TotalItems += e.Quantity;
LastUpdatedAt = e.OccurredAt;
}
}
このコードで大事なこと🌟
- Commandは“お願い”だから、成功・失敗どっちもありえる📮😵💫
- Eventは“起きた事実”だから、過去形で確定📜✅
- Stateはイベントを適用して作る🧠🔁
- Projectionは表示最適(あとで壊して作り直してもOK)🔎🧹
チェッククイズ(サクッと)🧠✅
- 「RemoveItemFromCart」はどれ?(Command / Event)
- 「ItemRemovedFromCart」はどれ?(Command / Event)
- 「カート合計金額」はどれ?(State / Projection)
- 「一覧画面の行データ(CartId, Total, Count)」はどれ?(State / Projection)
- イベント名が過去形なのはなぜ?(一言で)
- Projectionを直接更新して“真実”にしてはいけない理由は?(一言で)
答え合わせの目安📌
-
- Command 📮 / 2) Event 📜 / 3) StateかProjection(用途で分かれる!)/ 4) Projection 🔎
-
- “起きた事実”だから / 6) 真実はイベントで、Projectionは派生物だから🌿
AI活用:4分類を一瞬で“仮”に作るプロンプト例🤖✨
① 要件を4分類して、理由も書かせる🗂️💬
次の要件リストを Command / Event / State / Projection に分類して。
各項目について「なぜその分類か」を1行で説明して。
要件:
- (ここに箇条書きで貼る)
② コマンド→イベント候補を出させる📮➡️📜
次のCommand案それぞれについて、
成功した場合に発生しうる Event 名(過去形)を3案ずつ出して。
Command:
- AddItemToCart
- RemoveItemFromCart
出力は「Command → Event候補(3つ)」の形で。
③ “混ぜ事故”を検出するレビュー🤖👀
この設計のCommand/Event/State/Projectionの分け方で、
混ざっている箇所や危ない命名があれば指摘して、修正案も出して。
(コード or 箇条書きを貼る)
コラム:2026年の.NETの動き(超短く)🪟⚡
- .NET 10 は 2025年11月に公開され、LTS(長期サポート)として案内されているよ📌 (Microsoft for Developers)
- 2026年1月時点でも更新が出ている(例:10.0.2 のリリース日表示)🧩 (Microsoft)
まとめ:この章で覚えた4つの“置き場所”📦😊
- Command📮:お願い(命令形)
- Event📜:事実(過去形)+履歴が大事 (martinfowler.com)
- State🧠:イベントをApplyしてできる現在地
- Projection🔎:画面/検索のための読みやすい形(読みと書きを分ける発想と相性◎) (Microsoft Learn)