Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DDD x CQRS - 更新系と参照系で異なるORMを併用して上手くいった話

DDD x CQRS - 更新系と参照系で異なるORMを併用して上手くいった話

参考資料:http://little-hands.hatenablog.com/entry/jjug2017fall

社内新規プロダクトでDDD, CQRSの思想をベースとしたアーキテクチャを構築し、コマンド(更新系処理)ではSpring Data JPA(Hibernate)を、クエリ(参照系処理)ではjOOQを採用しました。
結果としてそれぞれのORMの良いところを生かした組み合わせのアーキテクチャが構築できたので、その経緯と得られた知見についてお話ししたいと思います。
以下のようなトピックを考えています。

・CQRSの定義とメリットデメリット
・DDD,CQRSを検討するにあたってのORMの選定ポイント
・構築したアーキテクチャ

CQRSはDDDと切り分けて単独でも適用することができるので、DDDについてご存知ない方もご覧いただけます。日本語の文献は意外と少ないので、この辺りの分野に興味がある人の参考になれば幸いです。

Koichiro Matsuoka

November 18, 2017
Tweet

More Decks by Koichiro Matsuoka

Other Decks in Technology

Transcript

  1. DDDとは • Domain Driven Design(ドメイン駆動設計)の略称 • ドメインとは ◦ 「アプリケーションの中心となる業務領域」のこと •

    原則 ◦ ドメインとドメインロジックを中心に設計する ( ≠ データモデル中心) ◦ 複雑なロジックをドメインモデルに寄せる (オブジェクト志向に則る) ◦ ドメインエキスパート(業務の専門家)と継続的にコミュニケーションし、モデルを改善し続ける • メリット ◦ ステークホルダー間のコミュニケーションが容易になる ◦ ソースの可読性、変更容易性、メンテナンス性が高まる • EricEvansによる定義
  2. DDDとは • Domain Driven Design(ドメイン駆動設計)の略称 • ドメインとは ◦ 「アプリケーションの中心となる業務領域」のこと •

    原則 ◦ ドメインとドメインロジックを中心に設計する ( ≠ データモデル中心) ◦ 複雑なロジックをドメインモデルに寄せる (オブジェクト志向に則る) ◦ ドメインエキスパート(業務の専門家)と継続的にコミュニケーションし、モデルを改善し続ける • メリット ◦ ステークホルダー間のコミュニケーションが容易になる ◦ ソースの可読性、変更容易性、メンテナンス性が高まる • EricEvansによる定義 略
  3. CQRSの提唱者 • Greg Young ◦ DDD + CQRS + イベントソーシングを推している

    そのため、CQRSとイベントソーシングがセットで語られがち → 本質的には別のもの
  4. • システムが大きくなるほど、 ◦ 書き込み:制御は複雑になっていく ◦ 読み込み:複数テーブルの情報をまとめて加工する必要性が高まっていく → 一つのモデルに関する処理がどんどん複雑になっていく CQRSが必要な背景 •

    そもそも、書き込み・読み込みで要件が大きく異なる ◦ 整合性か、速度か ◦ オブジェクトの形か、結合や集計した形か(モデル表現の違い) ◦ トラフィック数は圧倒的に読み込み処理が多い ◦ パフォーマンス要件は異なることが多い   → どこかにしわ寄せ、妥協が発生する
  5. CQRSのステップ • 段階的CQRS a. 書き込み / 読み込みモデルを分離する b. 書き込み /

    読み込みデータストアを分離する c. イベントソーシングと統合する  → 要件を見極めてどうするか判断すればよい
  6. CQRS - 1.単一物理データストアモデル • 書き込みと読み込みのモデルを別物として用意する • 書き込みモデル: テーブル毎に対応したエンティティ等 • 読み込みモデル:

    テーブルをJoinした結果、SQL viewの取得結果1行などを1モデルとする  → それぞれ適したモデルを扱えるので、処理効率が良い書き方ができる   コードがシンプルになる DB Data Model User Interface Application IF IF DB User Interface IF IF Write Model Read Model
  7. CQRS - 2.複数物理データストアモデル • 書き込みと読み込みのデータストアを物理的に分離する DB User Interface IF IF

    Write Model Read Model Write Data Store Read Data Store User Interface IF IF Write Model Read Model
  8. CQRS - 2.複数物理データストアモデル • 書き込みと読み込みのデータストアを物理的に分離する • Read Data Store ◦

    シンプルなのはread-onlyのレプリカ ◦ 全く別の機構を選択することも可能 (Readをelastic searchにするなど)  → 参照/更新のストア分離により、それぞれの負荷に合わせたスケーリングが可能   異なるアーキテクチャのデータストアを利用可能 DB User Interface IF IF Write Model Read Model Write Data Store Read Data Store User Interface IF IF Write Model Read Model
  9. 分離のメリット・デメリット メリット デメリット 1.モデル分離 処理効率が良い書き方ができる コードがシンプルになる readモデルにwriteモデルの制約を 効かせられなくなる 2.データソース 分離

    Read / Writeを分離してスケールさせること ができる 設計の幅が広がる データ同期の仕組構築 /メンテコストが必要 3.イベント ソーシング データ追跡しやすい ミューテーション排除によるバグ抑止 インピーダンスミスマッチとの決別 導入難易度がが一気に上がる 導入・教育コストが高い
  10. 分離のメリット・デメリット メリット デメリット 1.モデル分離 処理効率が良い書き方ができる コードがシンプルになる readモデルにwriteモデルの制約を 効かせられなくなる 2.データソース 分離

    Read / Writeを分離してスケールさせること ができる 設計の幅が広がる データ同期の仕組構築 /メンテコストが必要 3.イベント ソーシング データ追跡しやすい ミューテーション排除によるバグ抑止 インピーダンスミスマッチとの決別 導入難易度がが一気に上がる 導入・教育コストが高い → ORMも適正に合わせて使い分ければ、このメリットをより大きくできるのではないか?
  11. CQRSのオプション 各オプションは要件に応じて好きに組み合わせて良い 単一物理ストア 複数物理ストア データストア Read / Write 異なるモデル Read

    / Write 同じモデル モデル × しない する イベント ソーシング × → メリット/デメリット、コストを考慮し、今回はこのような構成を選択 単一ORM 複数ORM ORM ×
  12. Write/Read ORMの要件 • Write Model ORM ◦ オブジェクト志向でモデルに振る舞いをもたせたい ・DDDの思想を反映 ◦

    テーブルに対応したオブジェクト • Read Model ORM ◦ 複数テーブルをjoinしたり、集計したりしたい ◦ 効率の良いクエリが書きたい ◦ 実行されるクエリを制御したい
  13. Write/Read ORMの要件 • Write Model ORM ◦ オブジェクト志向でモデルに振る舞いをもたせたい ・DDDの思想を反映 ◦

    テーブルに対応したオブジェクト • Read Model ORM ◦ 複数テーブルをjoinしたり、集計したりしたい ◦ 効率の良いクエリが書きたい ◦ 実行されるクエリを制御したい  → この要件に合うようにORMを選定する
  14. ORMのパターン 中心 SQLロジックの組み込み方法 代表的プロダクト オブジェクト 中心 オブジェクトリレーショナルマッピングを通じ てJavaに組み込む Hibernate、(ActiveRecord) SQL中心

    Java外 - XMLなどの設定ファイル MyBatis、SQL view、 ベンダー特有のストアドプロシージャ Java内 - String文字列 JDBC、JPAネイティブクエリ Java内 - 独自DSL jOOQ、JPQL
  15. ORMのパターン 中心 SQLロジックの組み込み方法 代表的プロダクト オブジェクト 中心 オブジェクトリレーショナルマッピングを通じ てJavaに組み込む Hibernate、(ActiveRecord) SQL中心

    Java外 - XMLなどの設定ファイル MyBatis、SQL view、 ベンダー特有のストアドプロシージャ Java内 - String文字列 JDBC、JPAネイティブクエリ Java内 - 独自DSL jOOQ、JPQL  → 先述の要件を踏まえ、3つのORMでメリット/デメリット検討
  16. メリット デメリット Hibernate (Spring Data JPA) モデルに振る舞いを持たせやすい SpringDataJPAがDDDを想定した仕様 仕様の理解しにくさ、キャッシュなどのトラブ ル、想定外の挙動 etc..

    MyBatis SQLを直接かけるのでシンプル、安心 SQLがテキスト記述、 XMLに設定を書くのは今時結構辛い jOOQ タイプセーフなDSLで書きやすい、 読みやすい オブジェクトリレーションの表現に 制限あり ORM選定
  17. メリット デメリット Hibernate (Spring Data JPA) モデルに振る舞いを持たせやすい SpringDataJPAがDDDを想定した仕様 仕様の理解しにくさ、キャッシュなどのトラブ ル、想定外の挙動 etc..

    MyBatis SQLを直接かけるのでシンプル、安心 SQLがテキスト記述、 XMLに設定を書くのは今時結構辛い jOOQ タイプセーフなDSLで書きやすい、 読みやすい オブジェクトリレーションの表現に 制限あり ORM選定 →Writer Model ORMにHibernate、Read Model ORMにjOOQを採用
  18. • 業務ロジックをドメイン層に凝集する • アプリケーションサービス層はドメイン層が許可した操作を必要に応じて呼ぶ • この辺りはDDDの思想に基づいた設計 アーキテクチャ Business Logic Data

    User Interface Infrastructure Application Service Domain Model User Interface Infrastructure (@little_hand_s から参考資料たどれます 「ドメイン駆動 + オニオンアーキテクチャ概略」 )
  19. interface アーキテクチャ Application Service Domain Model User Interface Infrastructure Application

    Service Domain Model User Interface Infrastructure 実装クラス • ドメイン層をPOJOにするために依存関係を逆転する • ドメイン層が公開したIFに対してインフラ層が実装する設計
  20. • ドメイン層をWrite Model (ドメインモデル)とRead Modelに分割する • インフラ層の実装クラスをWriteとReadで異なるORMで実装する アーキテクチャ Application Service

    Domain Model Query Model User Interface Infrastructure Application Service Domain Model User Interface Infrastructure interface 実装クラス
  21. アーキテクチャ Application Service Domain Model Query Model User Interface Infrastructure

    <<interface>> Repository Entity Repository Impl <<interface>> Query Serivce DTO Query Serivce Impl
  22. Spring Data JPA アーキテクチャ Application Service Domain Model Query Model

    User Interface Infrastructure <<interface>> Repository Entity Repository Impl <<interface>> Query Serivce DTO Query Serivce Impl Hibernate Hibernate(アノテーションだけ)
  23. Spring Data JPA アーキテクチャ Application Service Domain Model Query Model

    User Interface Infrastructure <<interface>> Repository Entity Repository Impl <<interface>> Query Serivce DTO Query Serivce Impl jOOQ Hibernate Hibernate(アノテーションだけ)
  24. サンプルコード Task タスクID タスク名 ステータス User ユーザーID ユーザー名 作成者 担当者

    • シンプルなタスク管理アプリケーションを想定 • タスクの制約 ◦ 作成時の制約 ▪ 「作成者」と「担当者」として実在のユーザーを持つ ▪ 常に「未完了」状態で作成 ◦ 変更時の制約 ▪ 名前は変更できない ▪ 完了/未完了の制御だけできる
  25. アーキテクチャ Application Service Domain Model Query Model User Interface Infrastructure

    <<interface>> Repository Entity Repository Impl <<interface>> Query Serivce DTO Query Serivce Impl Hibernate(アノテーションだけ)
  26. アーキテクチャ Application Service Domain Model Query Model User Interface Infrastructure

    <<interface>> Repository Entity Repository Impl <<interface>> Query Serivce DTO Query Serivce Impl
  27. アーキテクチャ Application Service Domain Model Query Model User Interface Infrastructure

    <<interface>> Repository Entity Repository Impl <<interface>> Query Serivce DTO Query Serivce Impl jOOQ
  28. Spring Data JPA アーキテクチャ Application Service Domain Model Query Model

    User Interface Infrastructure <<interface>> Repository Entity Repository Impl <<interface>> Query Serivce DTO Query Serivce Impl jOOQ Hibernate Hibernate(アノテーションだけ)
  29. • 実際どうだった? →かなり使い勝手が良いです!! • Read Model ◦ Hibernateの得意な部分は活かしつつ、 参照系ではまりがちなHibernateの使い方に悩む時間を一切カット (クエリを書いた通りに動く)

    ◦ 検索条件の拡張も快適 • Write Model ◦ DDDとSpring Data JPAの相性は抜群  RepositoryのIFだけ書けば実装クラスを作ってくれるのはとても楽 ◦ writeモデルに振る舞いを凝縮している安心感、読みやすさ◎ 導入結果
  30. Q&A

  31. Q&A • テストはアプリケーション層のメソッドに対して書く (ちなみにspock) • メリット: ◦ 費用対効果が良い ◦ 内部のリファクタがしやすい

    ◦ アプリケーションサービス層で担保すれば、 呼び出し元がAPIだろうが画面だろうが watcherだろう が安心感がある • デメリット: ◦ テストでのDB実行環境構築が必要 Application Service Domain Model Query Model User Interface Infrastructure • テストはどうしている?