CTS-KB

開発手法ガイド:イベントソーシング編 — AI にバグ再現と What-if を任せる

⏱ 約 8 分で読めます
#開発手法 #イベントソーシング #Event Sourcing #AI駆動開発 #Event Store #イベントDB

🤖 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 StoreEventStoreDB(現 Kurrent)ストリーム・サブスクリプション・Projection を一級機能として提供
RDBMS 上のライブラリMarten(PostgreSQL / .NET)、Axon Server(Java)、Eventuate既存の PostgreSQL / SQL 資産を活かせる。運用の学習コスト低
ドキュメント DBMongoDB + 自作追記テーブル柔軟だが 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 を作るのが定番

🔗 関連記事

📖 関連用語