🤖 AI 駆動開発でイベントソーシングが効く理由
状態のスナップショットしか残さない通常の DB では、 「いつ・なぜ・誰が」その状態になったかが曖昧 。バグの再現、仕様の復元、What-if 分析のたびに監査ログを掘り返し、AI に渡すコンテキストが散らかる。
イベントソーシングは、 状態ではなくイベント列(状態変化の事実)を真実として永続化する 。現在の状態はイベントを畳み込んで導出する。AI 駆動開発での効用は 4 つ。
| AI 駆動開発での効用 | イベントソーシングがもたらす状態 |
|---|---|
| バグを即座に再現できる | イベント列を再生するだけで当時の状態が復元 |
| 新機能の追加が安全 | 既存イベントは不変、新イベントを追加するだけ |
| What-if 分析を AI に任せられる | 「もしこの操作を巻き戻したら」を再生で試算 |
| 監査証跡が自動で揃う | 誰が何をしたか欠落なく残る |
本記事は開発手法ガイド:概要のシリーズ 8 本目。イベントソーシングの本質、イベント DB の選び方、AI 駆動開発での活かし方を整理します。
📜 状態保存 vs イベント追記
通常の永続化との違い
通常の DB は「現在の在庫数: 12」を保存する。イベントソーシングは「入荷+10」「出荷-3」「入荷+5」というイベント列を保存し、必要なときに畳み込んで「12」を導出する。
| 観点 | 状態保存(CRUD) | イベントソーシング |
|---|---|---|
| 保存する真実 | 現在の状態 | 状態変化のイベント列 |
| 過去の参照 | 別途監査ログが必要 | イベント列がそのまま履歴 |
| 状態の再構築 | 不要 | イベントを畳み込む |
| 書き込みモデル | UPDATE 中心 | APPEND-ONLY |
| 「もし◯◯だったら」の分析 | 困難 | イベントを再生して試算可能 |
「追記のみ」が核心
イベントソーシングの核心は 過去の事実を上書きせず追記のみで扱う こと。これが AI 駆動開発と相性が良い理由でもある。
- 既存イベントは 不変 — AI が過去のデータを破壊する余地がない
- 新機能追加は 新イベント型の追加 で済む — 既存ロジックは触らない
- バグ修正後も 過去のイベントは残る — いつから壊れていたか追跡可能
🎨 イベント設計の原則
動詞は過去形
イベントは「起きた事実」。過去形で命名する。
良い: OrderPlaced / ItemShipped / PaymentFailed / CampaignApplied
悪い: PlaceOrder(Command と混同)
悪い: ShipItem(動作の指示になっている)
イベントは不変
一度発行されたイベントは書き換えない。誤ったイベントを訂正するなら、 補償イベント を追加発行する。
誤発行:
OrderPlaced { id: 1, amount: 10000 } (金額を間違えた)
補償:
OrderAmountCorrected { id: 1, oldAmount: 10000, newAmount: 5000 }
イベントは業務語彙で
「UPDATE users SET status=‘active’」のような DB 操作の言葉ではなく、 業務で起きた事実 の言葉で書く。
悪い: UserUpdated
良い: UserActivated / UserInvitationAccepted
AI に「このコンテキストでイベントを設計して」と指示するときも、業務語彙で命名するよう明示する。
💾 イベント DB(Event Store)の選び方
イベント列を格納するストレージを Event Store(イベント DB) と呼ぶ。専用 DB か、汎用 DB の上に構築するかで選択肢が分かれる。
主要な選択肢
| 分類 | 代表例 | 特徴 |
|---|---|---|
| 専用 Event Store | EventStoreDB(現 Kurrent) | ストリーム・サブスクリプション・Projection を一級機能として提供 |
| RDBMS 上のライブラリ | Marten(PostgreSQL / .NET)、Axon Server(Java)、Eventuate | 既存の PostgreSQL / SQL 資産を活かせる。運用の学習コスト低 |
| ドキュメント DB | MongoDB + 自作追記テーブル | 柔軟だが Projection・楽観ロックを自力で作り込む |
| メッセージングログ | Apache Kafka、Apache Pulsar | ログ無期限保持で Event Store として使える。分散前提の大規模系 |
| クラウドマネージド | AWS DynamoDB + Streams + Kinesis、Azure Cosmos DB(Change Feed) | マネージドでスケールアウト容易。ベンダーロックインに注意 |
選定観点
| 観点 | チェックポイント |
|---|---|
| 書き込み原子性 | 1 集約 = 1 ストリームで楽観ロックが効くか |
| 読み取り(再生)性能 | 長いストリームでスナップショット・Projection を作れるか |
| スキーマ進化 | アップキャスト・バージョン付与のサポート |
| Subscription / Projection | イベントを購読して Read Model を自動更新できるか |
| マルチテナント | テナントごとにストリーム・パーティションを分けられるか |
| 既存運用との親和性 | RDBMS 運用の知見をそのまま使えるか |
| 言語・ランタイム | .NET / Java / Node.js での実装サポート |
よくある誤選定
- 「Event Store = Kafka」と短絡: Kafka はメッセージングのログで、細粒度の楽観ロックや任意ストリーム再生には向かない。集約 1 件を再生するのに全体を走査する設計になりがち
- 「RDBMS で自作する」: 単純な append は簡単だが、スナップショット・Projection・並行制御・再生ツールなど運用周りで疲弊する。ライブラリ採用を先に検討
- 「ベンダーロックインを嫌って自作」: 運用コストの方が高くつくことが多い。既存 OSS(Marten, EventStoreDB 等)を先に評価
🔁 スナップショットとスキーマ進化
スナップショット
長いストリームを毎回全再生すると遅い。 一定件数ごとにスナップショット を取り、そこから新しいイベントだけを畳み込む。
イベント 1,000 件保存済み
├─ スナップショット(イベント 900 までの状態)
└─ 新イベント 100 件を再生
→ 全再生の 1/10 のコスト
スキーマ進化(アップキャスト)
イベント型は不変なので、スキーマを変更するときは 新バージョンを追加し、旧バージョンから新バージョンへのアップキャスト を実装する。
OrderPlaced v1 { id, amount }
OrderPlaced v2 { id, amount, currency } ← currency を追加
アップキャスト:
v1 を読み取ったら currency = "JPY" として v2 に変換
スキーマ進化の戦略は、イベントソーシング採用時に 最初から設計 することが重要。後から追加すると既存イベントの扱いに困る。
🎯 AI 駆動開発でのイベントソーシング活用
バグ再現を AI に任せる
指示例:
本番で報告されたバグ「注文 #12345 の在庫が -3 になった」を
再現したい。当該注文のイベント列を取得し、ローカル環境で
再生して、どの時点で在庫が負になったか特定してほしい。
イベント列があれば、AI はバグの再現を 読み込んで畳み込むだけ で実現できる。ログから状態を推測する必要がない。
What-if 分析を AI に任せる
指示例:
「もし 2026-03-15 のキャンペーンを適用しなかったら」の
売上を試算したい。当該期間のイベント列から CampaignApplied
を除外して再生し、結果を比較してほしい。
イベントソーシングは 過去の意思決定を巻き戻して試算 できる。AI が分析を組み立てるのが楽になる。
新機能の追加
指示例:
Order 集約に「キャンセル」機能を追加したい。
新イベント型 OrderCancelled を定義し、既存の OrderPlaced /
ItemShipped と整合するよう、Read Model の Projection を更新してほしい。
既存イベントは 触らない というルールが AI への制約として機能する。影響範囲が明確で、レビュー帯域の節約になる。
🔒 GDPR「忘れられる権利」との折り合い
イベントソーシングの「追記のみ」原則は、 個人情報の削除要求 と衝突する。
crypto-shredding(暗号キー破棄)
個人情報を含むフィールドを 暗号化して保存 し、削除要求時に暗号キーを破棄する。イベント自体は残るが、個人情報を復元できなくなる。
通常:
CustomerRegistered { name: "山田太郎", email: "..." }
crypto-shredding:
CustomerRegistered { name: ENC(key_123), email: ENC(key_123) }
key_123 を破棄すると復号不能
削除可能なイベント
法的要件で「物理削除が必要」な場合、そのフィールドだけ物理削除する運用も選択肢。ただしイベントのハッシュチェーン等を使っている場合は影響を慎重に検証。
⚠️ イベントソーシング採用時のアンチパターン
1. 全てをイベントソーシングにする
単純 CRUD な領域にまで適用し、運用が破綻する。
是正: Bounded Context 単位で判断 。業務価値が高い領域(注文・在庫・監査対象)にだけ適用。
2. イベント粒度の失敗
細かすぎる(FieldXUpdated を数十種類)、または粗すぎる(OrderEdited だけで何を変えたか分からない)。
是正: 業務上の出来事の粒度 で設計。「このイベントを見て何が起きたか説明できるか」で判定。
3. Read Model を作らず直接再生する
画面表示のたびに全イベントを再生し、パフォーマンスが破綻。
是正: CQRSで Read Model を作る。イベント → Projection → Read Model の流れを最初から設計。
4. スキーマ進化を軽視
初期設計で「後で変えればいい」と進めると、数カ月後にイベント型を変えたくなったときに詰まる。
是正: 最初からバージョン番号を持たせる 。アップキャスト機構をライブラリ採用時に確認。
📚 まとめ
- イベントソーシングは 状態ではなく状態変化のイベント列を真実として永続化する 設計パターン
- AI 駆動開発では バグ再現・What-if 分析・新機能追加 が構造的に楽になる
- イベント DB は 専用 Event Store / RDBMS + ライブラリ / メッセージングログ / クラウドマネージド から選ぶ。選定観点は書き込み原子性・再生性能・スキーマ進化
- スキーマ進化(アップキャスト)は 最初から設計 することが重要
- 全てに適用せず、 業務価値が高い領域だけに適用 する
- CQRSと組み合わせて Read Model を作るのが定番
🔗 関連記事
- 開発手法ガイド:概要 — シリーズ全体の位置づけ
- 開発手法ガイド:DDD 編 — イベントソーシングの前提となるドメイン設計
- 開発手法ガイド:CQRS 編 — イベントソーシングと組み合わせる読み書き分離
- 開発手法ガイド:CES アプローチ編 — CQRS + ES + Saga の統合