🤖 AI 駆動開発で CES が必要な理由
「注文 → 在庫引当 → 決済 → 配送手配」のように、 複数サービス・複数集約にまたがる長期トランザクション は、AI に任せると失敗する典型領域。AI は目の前の処理は書けても、 「どこで失敗したら、どう巻き戻すか」 の全体像を自力で組み立てにくい。
CES アプローチ(Command-Event-Saga)は、 CQRS + イベントソーシング + Saga を組み合わせ、長期トランザクションを明示的にモデリングする設計スタイル 。AI 駆動開発での効用は 3 つ。
| AI 駆動開発での効用 | CES がもたらす状態 |
|---|---|
| 成功/失敗シナリオを AI に明示できる | Saga の状態遷移が図として書ける |
| 部分失敗を AI が安全に扱える | 補償トランザクションが業務イベントとして定義済み |
| トラブル時の調査を AI に任せられる | イベント列+ Saga 状態で全経路が追跡可能 |
本記事は開発手法ガイド:概要のシリーズ 9 本目。CES の本質、Saga の設計、AI 駆動開発での適用を整理します。
📜 なぜ CES が必要か
2PC の限界
サービス境界(あるいは集約境界)を跨ぐ業務では、 2 フェーズコミット(2PC) は現実的でない。可用性が落ち、どこか 1 サービスが応答しないだけで全体がブロックされる。
マイクロサービス・外部 API 連携が前提の現代では、 結果整合性 + 補償 の仕組みが必要。それが Saga。
CES の構成要素
CES は 3 要素 を組み合わせる。
| 要素 | 役割 | 代表例 |
|---|---|---|
| Command | 「◯◯せよ」という意図。受け付けて妥当性を検証 | PlaceOrderCommand |
| Event | 「◯◯が起きた」という事実。追記のみで不変 | OrderPlacedEvent |
| Saga | 複数 Event を協調させる長期プロセス。失敗時の補償を持つ | 注文 → 在庫 → 決済 → 配送の連鎖 |
🎭 Saga の 2 つのスタイル
Choreography(振付)
各サービスがイベントを購読して 自律的に次の動作を決める 。中央制御なし。
Sales Service Inventory Service Payment Service
OrderPlaced ──────→ StockReserved ────→ PaymentCharged
を発行 を発行 を発行
| 向いている場面 | 向かない場面 |
|---|---|
| 関係サービスが少ない | 5 以上のサービスが絡む |
| 疎結合を最優先 | フロー全体を俯瞰したい |
| 各サービスが自律的 | 失敗時の巻き戻し順序が複雑 |
Orchestration(指揮)
中央の Saga マネージャが 順序・リトライ・補償を制御 。フローが明示的。
Saga Orchestrator
├─ Step 1: Inventory.Reserve
├─ Step 2: Payment.Charge
├─ Step 3: Shipping.Schedule
└─ 失敗時: 逆順に補償を発行
| 向いている場面 | 向かない場面 |
|---|---|
| フローが複雑・補償が多い | サービス間を疎結合に保ちたい |
| 進捗監視が必要 | 小さい Saga の乱立 |
| 長時間実行(数分〜数時間) | 1 リクエスト内で完結 |
AI 駆動開発での選択基準
- 3 サービス以内 + シンプル → Choreography
- 4 サービス以上 or 補償が複雑 or 監視が必要 → Orchestration
AI に Saga を設計させるときは、この判断を先に人間がする。 「どちらのスタイルで作るか」を決めてから AI に指示する。
🔁 補償トランザクションが核心
Saga の核心は 失敗時の巻き戻しを業務イベントで表現する こと。DB のロールバックではなく、「在庫引当キャンセル」「決済返金」「注文取消」といった業務上のアクションを補償として発行する。
| 順方向イベント | 補償イベント |
|---|---|
| 在庫引当 | 在庫引当キャンセル |
| 決済承認 | 決済返金 |
| 注文確定 | 注文取消 |
| 配送予約 | 配送予約キャンセル |
| メール送信 | お詫びメール送信(物理的に取り消せない) |
「取り消せないアクション」への対応
メール送信・物流連携など、 物理的に取り消せない アクションは、補償ではなく 後続の謝罪・通知フロー で対処する設計が現実解。
AI に指示するとき、 「このアクションは取り消せない。後続フローで対応する」 と明示しておくと、AI が無理にロールバックを書こうとしない。
🎯 AI 駆動開発での CES 実装
ステップ 1: Saga の状態遷移を先に書く
AI に実装を依頼する前に、 状態遷移図 を用意する。
[Started]
↓ OrderPlaced
[OrderAccepted]
↓ InventoryReserved
[StockReady]
↓ PaymentCharged
[Paid]
↓ ShippingScheduled
[Completed]
失敗時:
[Paid] → 配送失敗 → [Refunding] → [Cancelled]
[StockReady] → 決済失敗 → [ReleasingStock] → [Cancelled]
この図を CLAUDE.md や設計ドキュメントに書いておくと、AI への指示が一気に明確になる。
ステップ 2: 各ステップを個別に実装してもらう
指示例:
OrderSaga の Step 2「InventoryReserved イベントを受けて
Payment.Charge Command を発行する」ハンドラを実装してください。
- Orchestration スタイル(中央 Saga マネージャ)
- 失敗時は InventoryReleased 補償イベントを発行
- Idempotency を保証(同じ ID で再実行しても結果が同じ)
ステップごとに実装すれば、AI が全体を一発で書こうとして破綻するのを防げる。
ステップ 3: 補償経路を別指示で実装する
順方向と補償は分けて指示 するのが鉄則。AI が順方向だけ書いて「補償は後で」となると、運用時に詰まる。
レビュー観点
- Saga の状態遷移がドキュメントと一致しているか
- 補償イベントが順方向と対応しているか
- Idempotency(冪等性)を保証しているか
- タイムアウトが設定されているか(無限待機していないか)
- 部分失敗(ネットワーク切断、タイムアウト)に対して挙動が定義されているか
- 「取り消せないアクション」が補償で無理に取り消されていないか
🧟 ゾンビ Saga と向き合う
Saga の運用で必ず出会うのが ゾンビ Saga 。
| 症状 | 原因 |
|---|---|
| 中間状態のまま停止 | 外部サービスで失敗したが、自側に通知が届かず |
| タイムアウト超過 | 待機時間を設定せず無限待ち |
| 手動介入した履歴が残らない | 業務担当者が DB 直接更新でお茶を濁す |
対策
| 対策 | 内容 |
|---|---|
| タイムアウト設定 | 全 Step にタイムアウトを設け、超過したら補償か TimedOut 状態へ |
| 手動復旧 API | ゾンビ化した Saga を安全に再開・キャンセルする API を用意 |
| 全イベントをログに | 手動介入も Saga のイベントとして記録 |
| 監視ダッシュボード | 長時間 Running な Saga を可視化 |
AI に運用を任せるには、 「ゾンビ Saga はどう扱う?」 の回答を最初から設計に組み込む。
⚡ CES が効く場面 / 過剰な場面
効く場面
- マイクロサービス間で長期トランザクションが必要
- 業務上「失敗」が日常的に起こる(在庫切れ・決済失敗・配送不可)
- 監査要件が厳しく、すべての出来事を追跡可能にしたい
- 複数チャネル(モール・店頭・倉庫)で在庫やステータスを同期する
過剰な場面
- 単一 DB で完結する CRUD 主体の業務
- 結果整合性を業務側が許容できない領域(金融トレード当日決済など)
- チームに DDD・イベントソーシング・分散トランザクションの運用知見が薄い段階
- プロトタイプ・小規模 MVP
CES は 投資対効果の閾値が高い 設計スタイル。AI 駆動開発で速く作れるからといって、小規模案件に持ち込むと運用で疲弊する。
⚠️ CES 採用時のアンチパターン
1. Choreography で 10 サービス連携
イベントの因果関係が追えなくなり、トラブル時の調査が不可能に。
是正: 4 サービス以上なら Orchestration に倒す。または Bounded Context を切り直して Saga を小さく保つ。
2. 補償を後回しに設計
「まず順方向を完成させて、補償は後で」で本番投入。失敗が日常発生して人手で巻き戻す羽目に。
是正: 順方向と補償は セットで設計 。AI に補償だけ別指示で必ず実装させる。
3. Saga に同期 RPC を多用
結局 2PC と同じ可用性問題が発生。
是正: Saga 内は イベント駆動 。同期 RPC が必要ならその部分だけ切り出し、Saga の中には置かない。
4. Idempotency の欠落
同じイベントが 2 回届くと状態が壊れる。
是正: 各 Step で Idempotency Key を持たせ、重複検出を標準装備。AI に「Idempotency を保証して」と明示。
📚 まとめ
- CES は Command + Event + Saga を組み合わせ、長期トランザクションを明示的にモデリングする 設計スタイル
- AI 駆動開発では 「成功と失敗の両シナリオを自動で認識できる」 のが最大の効用
- Saga のスタイルは Choreography(疎結合) vs Orchestration(集中制御) 。4 サービス以上は Orchestration 推奨
- 補償トランザクションは 業務イベントで表現 。取り消せないアクションは後続フローで対応
- ゾンビ Saga 対策(タイムアウト・手動復旧 API・監視)を 最初から設計 に組み込む
- 投資対効果の閾値が高い。単純 CRUD には過剰
🔗 関連記事
- 開発手法ガイド:概要 — シリーズ全体の位置づけ
- 開発手法ガイド:DDD 編 — CES の前提となるドメイン設計
- 開発手法ガイド:CQRS 編 — CES を構成する読み書き分離
- 開発手法ガイド:イベントソーシング編 — Saga の駆動軸となるイベント永続化