第13章:メッセージの基礎(CommandとEventの違い)📨🎯

この章のゴール🏁✨
- Command(依頼)と Event(事実)をちゃんと分けて話せるようになる😊
- 「これはお願い?それとも起きたこと?」を瞬時に見分けられるようになる👀⚡
- Sagaで出てくるメッセージ名(OrderPaid / ReserveInventory など)を迷わず命名できるようになる🧠📝
まず覚える一言🧩💡
- Command =「これやって!」(お願い・指示)
- Event =「これ起きたよ!」(過去の事実・ニュース)
これを混ぜると、Sagaはすぐ事故るよ〜😵💫💥
Command vs Event イメージ 📨🎯📣
13-1. CommandとEvent、何が違うの?🤔📮
Command(コマンド)=「誰か1人にお願いするメッセージ」🎯
-
目的:行動してもらう(何かを実行してもらう)
-
宛先:基本 1つの担当(ハンドラ) を想定
-
例:
ReserveInventory(在庫を確保して!)ChargePayment(決済して!)CancelOrder(注文をキャンセルして!)
Commandは「お願い」なので、断られることもある(在庫ない、カードNGなど)😢
Event(イベント)=「起きた事実をみんなに知らせるメッセージ」📣🗞️
-
目的:事実の共有(もう起きたこと)
-
宛先:基本 複数の購読者(サブスクライバ) がいてOK
-
例:
InventoryReserved(在庫確保できた!)PaymentCharged(決済完了した!)OrderCanceled(注文キャンセルされた!)
Eventは「ニュース」だから、受け手が止めることはできない(止めたいなら、その前にCommandで止める)🧯
13-2. 一発で見分けるチェックリスト✅🧠
これはCommand?🎯
- 「〜して!」って言える?(命令形っぽい?)
- 失敗・拒否される可能性がある?
- “宛先がだいたい決まってる”感じ?(誰がやるか明確)
→ YES多めなら Command 😊
これはEvent?📣
- 「〜した!」って言える?(過去形っぽい?)
- もう起きたことを報告してる?
- “聞きたい人が勝手に聞く”感じ?(購読者が増えてもOK)
→ YES多めなら Event 😊
13-3. Sagaの流れで見ると超わかる🍱🔁
例:ECで「注文→決済→在庫」🛒💳📦
Command→Event の王道パターン✨
PlaceOrder(注文して!)🎯OrderPlaced(注文できた!)📣ChargePayment(決済して!)🎯PaymentCharged(決済できた!)📣ReserveInventory(在庫確保して!)🎯InventoryReserved(在庫確保できた!)📣
この並びだと、Sagaの「状態機械(第11〜12章)」にも落とし込みやすいよ〜⚙️✨
13-4. 命名ルール(ここが一番効く!)📝💥
Commandの命名:命令形(やって!)🧑✈️
ReserveInventoryChargePaymentCancelOrder
Eventの命名:過去形(起きた!)📣
InventoryReservedPaymentChargedOrderCanceled
「Eventは過去形が自然」みたいな命名ルールは、メッセージング系の実務ドキュメントでも定番だよ📚✨ (docs.particular.net)
13-5. 混ぜるとどう壊れるの?(ありがち事故)😱🕳️
事故①:「お願い」をEventっぽく出す📣❌
たとえば…
InventoryReservationRequested(在庫確保お願いしたいっぽい名前)
これをEventとして配信すると、
- “誰がやるの?”問題が出る(購読者が複数いると二重実行の地獄)🔥
- 「担当は1人」なのに「みんな聞ける」形になる😵💫
事故②:「事実」をCommandっぽく出す🎯❌
たとえば…
PaymentWasChargedPleaseHandleみたいなノリ(やばい命名例🤣)
これをCommand扱いにすると、
- 「事実なのに、受け手が失敗したらどうするの?」となる
- 結果、「事実」が不安定になる(え、起きたの?起きてないの?)🤯
事故③:「同じ言葉」がCommand/Eventで混在する🌀
例:
CancelOrder(Command)CancelOrder(Event)←同名にしちゃう
ログや監視で死ぬ😇🧾 → CommandとEventは“見ただけで違う”名前にするのが安全!
13-6. C#での型設計(超ミニマムでOK)🧑💻✨
ここでは「混ぜない」ために、型で分けちゃうのがコツだよ🧷
// 目印インターフェース(中身は空でOK)
public interface ICommand { }
public interface IEvent { }
// メタ情報(追跡の基本セット)
public sealed record MessageMeta(
Guid MessageId,
string CorrelationId,
string? CausationId,
DateTimeOffset CreatedAtUtc
);
// Command例(お願い)
public sealed record ReserveInventory(
string OrderId,
string Sku,
int Quantity,
MessageMeta Meta
) : ICommand;
// Event例(起きた事実)
public sealed record InventoryReserved(
string OrderId,
string Sku,
int Quantity,
MessageMeta Meta
) : IEvent;
なんで record が便利なの?📌
- **メッセージは基本「作ったら変えない(不変)」**のが安全
- recordは「データのかたまり」として扱いやすい✨ C#のrecordはこういう用途に向いてるよ📘 (Microsoft Learn)
13-7. “封筒(Envelope)”の考え方(ちょい実戦)✉️🔗
実務では、Eventに「共通の外側フォーマット」を付けることがあるよ📦 その代表が CloudEvents(イベント共通スキーマ)✨ 「id / source / type / time / subject / data」みたいな枠を揃えるやつ! (GitHub)
- “イベントを運ぶ箱”を標準化すると、サービス間の相互運用がラクになる🙌
- Azureでも CloudEvents が推奨フォーマットとして扱われてるよ📨 (Microsoft Learn)
※ CommandまでCloudEventsに寄せるかはチーム次第だけど、まずは「Eventの外側標準」くらいの理解でOK😊
13-8. ミニ演習🎲😊(分類クイズ)
問題:Command?Event?どっち?🧠💥
OrderPaidPayOrderReserveInventoryInventoryReservedShipOrderOrderShippedRefundPaymentPaymentRefundedCreateShipmentShipmentCreated
解答✅✨
- Event(支払い終わった)📣
- Command(払って!)🎯
- Command 🎯
- Event 📣
- Command 🎯
- Event 📣
- Command 🎯
- Event 📣
- Command 🎯
- Event 📣
コツは「命令形か?過去形か?」だよ〜📝💡 (docs.particular.net)
13-9. ミニ演習🛠️(命名リライト)
お題:この名前、直してみよ〜😆✍️
InventoryReservationRequested(Eventっぽく流してる)PaymentCompletedCommand(事実なのにCommandっぽい)OrderCancel(Command/Eventどっちか曖昧)
例の答え(1つの案だよ)✨
- Commandにするなら:
ReserveInventory🎯 / Eventにするなら:InventoryReserved📣 - Eventなら:
PaymentChargedまたはPaymentCompleted📣 - Commandなら:
CancelOrder🎯 / Eventなら:OrderCanceled📣
「曖昧な単語(Request / Completed / Process)」を使うと、混ざりやすいから注意だよ⚠️😵💫
13-10. AI活用(Copilot/Codexに投げると強い)🤖✨
① 分類レビューを頼む(混ざり検知)🔍
以下のメッセージ名一覧を、Command / Eventに分類して。
さらに「紛らわしい名前」「混ざって事故りそうな点」を指摘して、
改善案(命名)を各1〜2個ずつ提案して。
- (ここに一覧)
② 命名規則を“チームルール”として文章化📝
CommandとEventの命名ルールを、初心者にも分かる短い文章でまとめて。
例も5個ずつ付けて。過去形・命令形のルールが伝わるように。
③ C# record のひな形を作ってもらう🧑💻
次のドメイン(注文・決済・在庫)に対して、
Command と Event の record 定義案をC#で作って。
MessageMeta(MessageId / CorrelationId / CausationId / CreatedAtUtc)も含めて。
まとめ🎀✨
- Command=お願い(1担当に向ける)🎯
- Event=事実(みんなに通知できる)📣
- 命名は Command:命令形 / Event:過去形 が最強の事故防止🛡️✨ (docs.particular.net)
- C#では 型(ICommand/IEvent)+record で混ぜない仕組みを作ると安定するよ😊📌 (Microsoft Learn)