CQRSは「目的」、イベントソーシングは「手段」
多くの場合、まずCQRSの考え方を導入し、その書き込みモデルを実装する手段としてイベントソーシングを選択するのが、最も自然でリスクの低い流れです。
この2つは、「目的」と「手段」 の関係として捉えると分かりやすいです。
CQRS (コマンド・クエリ責務分離) 📜
これは、「書き込み(コマンド)のモデル」と「読み取り(クエリ)のモデル」を分離するという アーキテクチャパターン(目的・思想) です。
導入の主な動機は、
書き込みと読み取りの要求が異なり、単一のモデルでは両方を効率的に満たせない
という問題を解決することです。
書き込み(コマンド):整合性が重要。正規化されたデータモデルが適している。
読み取り(クエリ):性能が重要。検索や集計に最適化された、非正規化なデータモデルが適している。
この根本的な要求の違いから、
「書き込みモデルと読み取りモデルを分離しよう」というアーキテクチャ上の目的(戦略決定)
が生まれます。これがCQRSです。
イベントソーシング ✍️
対して、こっちは、データの状態を「イベントの連なり」として記録する、 永続化のパターン(手段・実装方法) です。
「分離した書き込みモデルを、具体的にどう実装しようか?」と考えた時に手段として登場するのが、イベントソーシングです。
CQRSの **書き込み側(コマンドサイド)**を実装するための、極めて強力な選択肢の一つです。
・イベントソーシング:変更を「イベントの完璧な履歴」として全て記録する。
・従来のRDB:「現在の状態」をRDBに保存し、変更があったらアウトボックスパターンでイベントを通知する。
イベントソーシングは、その出力(イベントストリーム)が、多様な読み取りモデルを構築するための完璧な材料となるため、CQRSとは非常に相性が良い、強力な手段です。
しかし、CQRSで必須ではありません。
よりシンプルな従来のRDBでも、CQRSの「目的」自体は一応達成できます。
なぜCQRSを先に考えるべきか
イベントソーシングを導入すると、必然的にCQRSが必要になります。
なぜなら、
イベントソーシングは「イベントの完璧な履歴」を保存するだけで、
「現在の最新の状態」を直接は保持しない
そのため、効率的なデータ参照のためには、イベントストリームから別途「現在の状態」を射影した読み取り専用のモデル(リードモデル)を構築する必要があるからです。
このリードモデルを構築する行為そのものが、CQRSの実践に他なりません。
ここまでのまとめ
このように、
CQRSはアーキテクチャの
「WHY(なぜ分離するか)」と「WHAT(何を分離するか)」を定義
イベントソーシングはその「HOW(どう書き込み側を実装するか)」の1つの解
という関係性です。
「結果」の記録 vs. 「過程」の記録
RDB + アウトボックスパターン
このパターンが記録するのは、
ローカルトランザクションが完了した後の 「最終的な結果」
です。
例えば、1つのトランザクション内で
「商品をカートに追加」→「クーポンを適用」→「注文を確定」 という一連の操作が行われたとします。
アウトボックスから発行されるイベントは、多くの場合、OrderConfirmedという最終結果だけです。
イベントソーシング
対して、こちらが記録するのは、
最終結果に至るまでの**「全ての出来事(過程)」**
です。
同じシナリオでも、イベントストアには、
1. ItemAddedToCart
2. CouponApplied
3. OrderConfirmed
といった、集約内部の状態がどのように変化していったかの全履歴が、イベントの連なりとして記録されます。
なぜ「過程」の記録が重要なのか
RDBとアウトボックスパターンだけでは、この 「過程」 を細かく追跡できません。
そして、この「過程」の記録こそが、イベントソーシングがもたらす独自の価値の源泉となります。
詳細な監査
なぜ最終的にその状態になったのか、完全な証跡を追うことができます。
ビジネス分析
「どのクーポンが、どの商品の追加後に適用されやすいか」といった、ユーザーの行動に関するより深い分析が可能になります。
デバッグの容易さ
複雑なバグがサービス内部で発生した際に、状態変化の全ステップを再現し、どこでロジックが間違ったのかを正確に特定できます。
ここまでの結論
結論として、単に「サービス間で確実にイベントを通知する」だけであれば、RDBとアウトボックスパターンで十分です。
しかし、
「集約内部で『何が起きたか』という物語そのものがビジネス上の資産である」
と判断した時に初めて、その物語を完全に記録するための手段として、イベントソーシングが選択されるのです。
推奨される段階的な導入ステップ
したがって、最もリスクが低く、現実的な導入ステップは以下の通りです。
1. 課題特定
まず、「読み取り処理が複雑化・低速化し、書き込み処理の足を引っ張っている」といった課題を特定します。
2. 意思決定
その課題を解決するために、CQRSパターンの導入を決定します。
3. 最初の実装
コマンド側
まずはチームが慣れ親しんだ、従来のRDB(状態を直接更新するモデル)で実装します。
連携
書き込みDBが更新されたら、トランザクショナル・アウトボックスパターンを使って、変更内容をイベントとして確実に発行します。
クエリ側
そのイベントを購読し、参照に最適化されたリードモデル(別のDBや検索エンジン)を構築します。
4. 進化
その後、監査証跡や過去の時点への復元といった、より高度な要求が出てきた段階で、初めてコマンドモデルをイベントソーシングへとリファクタリングすることを検討します。
この手順を踏むことで、CQRSとイベントソーシングという2つの強力なパターンを、それぞれのメリットを理解しながら、適切なタイミングで段階的に導入することができます。