実践ドメイン駆動設計を読んだ
業務でいわゆる軽量DDDを採用しているシステムを扱っており、そのアーキテクチャの理解を深めるために「実践ドメイン駆動設計」を読んでみました。
戦略的DDDと戦術的DDD
本書を読む前から、DDDには戦略的DDDと言われるものと、戦術的(軽量)DDDと言われるものがあることはなんとなく知っていました。
戦略的DDDとはざっくり以下のようなことを意識してシステム開発をすることで、
- ドメインエキスパートとエンジニアが協力してユビキタス言語やドメインモデルを作り上げる
- ドメインモデルは、全部入りの一つの大きなモデルを作るのではなく、ドメインをサブドメイン(コアドメイン、支援サブドメイン、汎用サブドメイン) に分割するように考える
- ドメインモデルをシステムへ落とし込む際は、境界づけられたコンテキストという概念を用いて、システム間の分割・統合を考える
戦術的DDDとは、EntityやValueObject、Repositoryなどの設計パターンを取り入れたシステム開発のことです。
うすうす気づいていたことですが、私が業務で実践しているのはあくまで戦術的DDDであり、戦略的DDDまでは実践できていないんだなーと改めて思いました。 現在のプロジェクトでは、戦略的DDDが実践できて着ないからと言って問題が起きたりはしていませんが、胸を張って「DDDをやってます」とは言えないですね。。
戦略的DDDについては、もともとふわっとした知識しかなかったので、本書を読むことでとても勉強になりました。 特に、境界付けられたコンテキストは、マイクロサービスアーキテクチャのサービス境界の考える際にもよくでてきる概念だったりするので、それを学べたのは良かったと思います。
また、戦術的DDDに関しては、業務で扱っていることもありそこそこ理解しているつもりでしたが、私の認識が不十分であった箇所があったり、業務と本書で解釈(実装)が異なる部分があったりと色々と収穫がありました。 そして一番の収穫は、業務で実装方針に悩んでいた箇所がピンポイントで解説されていたことです。 これは「複数の集約にまたがる参照系処理をどう実装したらいいか」ということなのですが、これについて少し書いていきます。
複数の集約にまたがる参照系処理
DDDでは、基本的にResopitoryを使って集約単位でオブジェクトを(DBに格納されている値から)復元します。 そのため、複数の集約にまたがるような参照系処理では、複数のRepositoryから集約を復元し*1、それらを合成する処理をすることになります。 コードの保守性という観点では、この実装にすることで他の処理(更新系の処理など)との一貫性を保つことができます。 しかし、パフォーマンスと言う観点では、DBアクセスの回数や不要な値(カラム)も取得してしまうという点が問題になります。 これについてどう実装するのがいいのかもやもやしていたのですが、この問題への言及が本書にありました。
必要なデータをすべてリポジトリから取得してユーザーに表示するのが、難しいこともある。 たとえば、いくつもの集約型とそのインスタンスをまたがったデータ取得が必要になる場合などが、特にそうだ。 ドメインを洗練させればさせるほど、こういった状況は起こりやすくなる。
リポジトリだけを使ってこれを解決することもできるが、あまりやりたくはない。
クライアント側で複数のリポジトリにアクセスさせ、必要な集約のインスタンスをすべて取得させてから、必要なデータを組み合わせてデータ変換オブジェクト(DTO)に格納するという手がそのひとつだ。
あるいは、リポジトリ上に特別なファインダーを用意して、一回の問い合わせで各地のデータを取りまとめるようにするという手もある。
そのどちらも使えないような状況なら、ユーザーエクスペリエンスの設計に何らかの妥協が必要だ。 モデルが用意する集約の境界に沿って、ビューを設計することになる。 その結果できあがるのは、人にやさしくない質素で機械的なインターフェイスだ。
もっと違う方法で、ドメインのデータをビューにマッピングできないだろうか? その答えが、CQRSという奇妙な名前のアーキテクチャパターンだ。
本書では、私がもやもやしていた点について以下の3つの解決策を示してくれていました。
- リポジトリ上に特別なファインダーを用意して、一回の問い合わせで各地のデータを取りまとめる
- ユーザーエクスペリエンスの設計に何らかの妥協をする
- CQRSというアーキテクチャパターンを採用する
ただ、これらのどの選択肢もメリットもあればデメリットもあり、それらのトレードオフを考えながら選択する必要があります。 特にCQRSに関しては以下のような注意書きがありました。
あらゆるパターンに共通することだが、CQRSを採用することによって失われてしまうものもある。 十分な検証の元で、賢く使うべきだ。 ユーザーインターフェイスがさほど複雑ではなく、単一のビューに複数の集約が絡むこともあまりないのであれば、下手にCQRSを導入しても、必要以上に複雑性を増す結果になってしまうだろう。
どの選択肢にもトレードオフがあり、普遍的に正しい選択しがないのはアーキテクチャあるあるですね。。
終わりに
本書を通して戦略的DDDから詳細な戦術的DDDの実装まで、DDDについて幅広く学ぶことができました。 DDDの知識もある程度深まったので、次は難しいと噂の「エリック・エヴァンスのドメイン駆動設計」に挑戦してみようと思います。
*1:Repositoryは集約と1対1で紐付く