イベントソーシング + CQRS を理解する

ステートソーシング

従来からあるステートソーシングは一般的で分かりやすい。出荷状態を管理するモデルを例に取ると、status カラムが「準備中→出荷→到着→完了」のように遷移していく。

  • ポイント
    • データの「状態」を記録する
  • 流れ
    • データの状態を DB から読み出す
    • データの状態を変更する
    • 変更データを DB に書き込む
  • 特徴
    • モデルに対する CRUD で実現できる
    • レコードが常に状態と一致する

出荷を CRUD したければ単一のモデルに対してアクセスすれば実現できる。

flowchart LR
subgraph State[ざっくり概念図]
        direction LR
        Client((クライアント))
        Model[モデル]
        DB[(データベース)]

        Client -->|CRUD操作| Model
        Model -->|読み取り/書き込み| DB
        DB -->|現在の状態| Model
        Model -->|結果| Client

        style DB fill:#bbf,stroke:#333
end

イベントソーシング

レコードが常に最新の状態を持っているステートソーシングに対し、イベントソーシングは「状態が変わる出来事」に着目する。出荷状態が変わるできごと ー 例えば、梱包が完了した、トラックが出発した、受取が完了した ー を記録していく。

  • ポイント
    • データの「状態遷移」を記録する
  • 流れ
    • 状態を読み出すにはイベントから状態を再生する
    • 新しいイベントを追加する
  • 特徴
    • 基本的に SELECT と INSERT のみ
    • 参照と更新でアプローチが異なる
flowchart LR
subgraph State[ざっくり概念図]
    direction LR
    Client((クライアント))
    Model[モデル]
    Projection[プロジェクション]
    ES[(イベントストア)]

    Client -->|参照/更新| Model
    Model -->|書き込み| ES
    ES -->|読み出し| Projection
    Model -->|状態の再生| Projection
    Model -->|結果| Client

    style ES fill:#f9f,stroke:#333
end

コマンドクエリ責任分離 (CQRS)

データの読み取りと書き込みを分離する設計パターン。データの参照を担う Query とデータの書き込みを担う Command に分けられる。CQRS とイベントソーシングはセットで語られるが、相性がいいというだけで概念は別物である。そのためイベントソーシングするが CQRS を実装しないこともあり得る。(ただ、イベントソーシングする時点で書き込みと読み込みの処理は全く別物になるため自ずと分離を迫られる。)

イベントソーシングの概念図に CQRS を当てはめると次のようになる。

flowchart LR
subgraph State[ざっくり概念図]
    direction LR
    Client((クライアント))
    ReadModel[Query モデル]
    WriteModel[Command モデル]
    Projection[プロジェクション]
    ES[(イベントストア)]

    Client -->|更新| WriteModel
    Client -->|参照| ReadModel
    WriteModel -->|書き込み| ES
    ES -->|読み出し| Projection
    ReadModel-->|状態の再生| Projection
    ReadModel -->|結果| Client

    style ES fill:#f9f,stroke:#333
end

参考