第07章:ミニ題材を決める(学習用の小さな世界)🧪🍀
7.1 なんで「ミニ題材」が必要なの?🤔✨
Outbox(トランザクショナル・アウトボックス)は、いきなり本番っぽい題材でやると… 「要件が多すぎて」「どこが大事か分からなくて」「実装が迷子」になりがちです😵💫🌀
だからこの章では、**Outboxの核心(=事故るポイント)だけが入った“小さな世界”**を先に決めます🧊💡 小さいほど、理解が速いし、あとで拡張もしやすいよ〜🪜🌱
7.2 ミニ題材に入れておくべき“必須条件”✅📦
ミニ題材は「Outboxが必要になる状況」をわざと作るのがコツです😈✨ 次のチェックを満たす題材を選べばOK!
- ✅ 業務データの更新がある(例:注文ステータスが変わる)🛒
- ✅ 外へ通知したいことがある(例:通知サービスへイベント)📩
- ✅ 通知は失敗しうる(ネットワーク・一時障害)🌧️
- ✅ 再送が起こりうる(リトライで二重送信の可能性)🔁
- ✅ 「更新」と「送信」を同時に扱うと事故る(これがOutboxの出番)💥
この“二重書き問題(DB更新と通知送信の両方が絡む)”を、Transactional Outbox が解決する、という位置づけだよ🛡️📦 (AWS ドキュメント)
7.3 今回のミニ題材(採用)🛒📩「注文確定 → OrderConfirmed を送る」
この教材では、ミニ題材をこれに固定します🎯✨
✅ ユースケース(やりたいこと)
- ユーザーが「注文確定」ボタンを押す🖱️
- 注文の状態が Confirmed になる✅
- その事実を、外部(通知サービス)へ OrderConfirmed として知らせたい📩
😱 でも現実は…
- DB更新は成功✅
- 送信は失敗❌(通信エラー) → 「確定したのに通知が飛んでない!」📭 みたいな事故が起きる
だから、“送る予定”をDBに残す Outbox が必要になる、という流れです📦🧾 Outbox は「業務DBと同じ場所にメッセージ(イベント)を保存して、あとでリレーが送る」という登場人物構成で語られることが多いよ👥📤 (microservices.io)
7-2. 作るもの:超シンプル「注文確定」シナリオ🛒➡️📦
複雑な業務ロジックは捨てて、「DB更新と同時にイベント予約する」 部分だけに集中します🔍
ここで欲張ると、Outbox以外で燃えます🔥
✅ 今回「やる」こと(スコープIN)🟢
- 注文を Confirmed に更新する
- Outbox に OrderConfirmed を1件保存する
- (後の章で)Outbox を拾って送る係が送信する📤
❌ 今回「やらない」こと(スコープOUT)🔴
- 決済・在庫・配送などの本格業務💳🚚
- 本物のメール送信✉️(最初はダミーでOK)
- メッセージブローカー(Kafka等)導入🧠(後でやれる)
- 分散トレーシングの完全実装🔍(後で育てる)
“動く最小”を最速で作るのがゴールだよ🏃♀️💨🎯
7.5 1枚で書ける「ミニ仕様」テンプレ📝✨
この章の成果物はこれ!👇 (このテンプレを埋めれば、次章以降が超ラクになります🪄)
🧾 ミニ仕様:注文確定
-
入力:orderId(注文ID)🆔
-
前提:注文は存在する(見つからなければエラー)⚠️
-
ルール:status が Draft のときだけ Confirmed にできる✅
-
DB更新:orders.status = Confirmed、confirmedAt を入れる🕒
-
Outbox追加:eventType = "OrderConfirmed"、payload を保存📦
-
期待結果:
- DB更新とOutbox追加が どっちも成功したときだけ完了✅
- 送信は後でやる(失敗しても業務を巻き込まない)✂️
7.6 イベント(OrderConfirmed)の設計をミニで決める📨🧩
イベントは「受け手が困らない最小」を目指すよ🎁✨
✅ 推奨フィールド(最小)
- eventId:一意なID🆔
- eventType:"OrderConfirmed"🏷️
- occurredAt:発生時刻🕒
- payload:本体(注文の情報)📄
- schemaVersion:1(将来のため)🧬
✅ payload に入れる最小(例)
- orderId🆔
- userId👤
- totalAmount💰
- currency("JPY"など)💴
「Outboxに入れるメッセージは、あとでリレー(送信係)が外へ出す」ので、後で見返して意味が分かる形にするのが大事だよ👀📦 (microservices.io)
7.7 TypeScriptで“型”として固定しておく(迷いを消す)🧠✨
ここでは実装をガッツリ進めなくてOK🙆♀️ でも、型だけは先に決めると「仕様のブレ」が激減します📌
// まずはイベント種別を固定(タイポ防止✨)
export type EventType = "OrderConfirmed";
// payload(通知したい中身)
export type OrderConfirmedPayload = {
orderId: string;
userId: string;
totalAmount: number;
currency: "JPY";
};
// Outboxに入れる1レコード(最小)
export type OutboxMessage = {
id: string; // eventId と同じでOK(最初は)
eventType: EventType;
payloadJson: string; // JSON文字列で保存する想定
status: "pending" | "sent"; // まずは2状態でOK
createdAt: string; // ISO文字列
schemaVersion: 1;
};
🍀ポイント:まずは status を2つだけにする(pending / sent) “processing” や “failed” や retryCount は、あとで段階的に増やす🪜✨
7.8 AI(コーディング支援)で「題材の完成度」を上げる🤖💖
ミニ題材づくりは、AIに手伝わせると速いよ⚡ 例えば GitHub の Copilot や、OpenAI の Codex系ツールにこう聞くと便利🧠✨ (※“答えを丸写し”じゃなくて、“仕様の穴を見つける”使い方がおすすめ!👀)
💬 そのまま使えるプロンプト例
- 「注文確定イベントの payload に最低限必要な項目を、受け手視点で提案して」🎁
- 「Draft→Confirmed の状態遷移で、初心者がやりがちなバグを3つ教えて」🐛
- 「このミニ題材、YAGNI的に“やりすぎ”な要素があったら削って」🧊
- 「Outboxレコードの最小カラム案を、学習用に2段階(初級→実運用寄り)で出して」🪜
🔍 追加ヒント
Copilot は VS Code で提案&チャットが使える形で説明されているよ🧰💬 (Visual Studio Code)
7.9 章末チェックリスト(ここまでできた?)✅🌸
- ミニ題材が「注文確定→イベント通知」になっている🛒📩
- スコープIN / OUT が言える(やらないことを守れる)🧊
- ミニ仕様が1枚で書けた📝
- OrderConfirmed の payload 最小が決まった🎁
- TypeScriptの型で固定できた🧠
7.10 ミニ演習(5分)⏱️🎀
次のどれか1つ、同じテンプレで「ミニ題材化」してみよう👇(注文確定の次にやると理解が深まるよ🪄)
- A:会員登録完了 → UserRegistered 🧑💻✨
- B:投稿公開 → PostPublished 📝📣
- C:パスワード変更 → PasswordChanged 🔐⚠️
「DB更新」と「外へ知らせたいこと」がセットになってれば、Outbox向きだよ📦✅
まとめ 🎯📦
この章でやったのは、**Outboxを学ぶための“最小の舞台づくり”**です🧪✨ 次章からは、このミニ題材を使って「実装の最短ルート」を進みます🏃♀️💨