まえがき
ドメイン駆動設計(DDD)を勉強中の大学生です。
これまでDDDはふんわり理解したつもりでいたのですが,ふとDomain Modelの意味範囲の広さには2通りあるのでは? と感じました。
すなわち,オニオンアーキテクチャの文脈におけるDomain Modelと,より一般的なDDDの文脈におけるDomain Modelでは,それぞれの指す意味領域の広さが少し違うのでは?と感じたので,ドメイン駆動設計の理解を整理しながら,その疑問について考察していきます。
DDDとは何者なのか,特にDomain ModelとDomain Serviceの違いについて整理しているので,「なんとなくDDDが理解しきれない…」という方にとっても参考になるかもしれません!
この記事はきちんとした調査に基づいたものではなく,雑に調べて個人の頭の中で整理したことが書かれています。そのため情報が不正確である可能性がありますので,あくまで参考程度にとどめておいてください。有識者の方は,ぜひアドバイス・指摘等お願いします!
また,Domain Modelのような英語表記と「ロジック」のようなカタカナ表記が混在していますが,前者のような英語表記は,DDDなどの文脈における細かなニュアンスを含んだ意味で,後者のようなカタカナ表記は,日常語における意味合いで使っています。
ドメイン駆動設計 (DDD) とは
まずDDDについて前提を確認します。
私は,DDDとはオブジェクト指向らしいアプリケーション設計をするための方法論と解釈しています。
すなわち,「登場人物」や「専門家のもつ知識」,「業務ロジック」などのDomain Modelをアプリケーションの中心部で表現し,実際の業務フロー=処理の流れは,Use CaseやApplication Service等のレイヤーでDomain Modelを操作することで表現します。
Domain Modelとは
では,Domain Modelとは何でしょうか?
Domain Modelとは,DDDにおいてまさしく「登場人物」や「専門家のもつ知識」,「業務ロジック」などを表現し,カプセル化したモノです。多くの場合クラスで表現します。
しかし,どうやらこのDomain Modelという言葉の意味の範囲が,文脈によって少し変わってくるような気がしたのです。
Domain Modelの意味範囲の考察
一般的(と思われる)意味領域については以下の後者で説明しますが,まずは私が「ちょっと意味領域違うかも?」と引っかかった,オニオンアーキテクチャにおけるDomain Modelについて説明します。
オニオンアーキテクチャにおけるDomain Modelの意味範囲
オニオンアーキテクチャでは,外側から順に
UI(Presentation), Infrastructure, Tests > Application Service > Domain Service > Domain Model
というレイヤー分けが提案されています。
アプリケーションのコア領域をDomainと呼んでいながら,そこにはDomain ModelとDomain Serviceという異なるレイヤーが存在しており,混乱しそうです。。。
Domain ModelとDomain Serviceの違い
そこでいろいろと調べた結果,なんとなく感じ取れたことがあります。それは,どうやらオニオンアーキテクチャの文脈では,ふつうよりDomain Modelの意味領域が狭いっぽい,ということです。
すなわち,オニオンアーキテクチャの文脈でDomain Modelが指すのは,EntityやValue Object,あとはそれらのAggregate(集約)など,要するに登場人物の実体のことであるように感じられます。
このときDomain Modelは,登場人物と,その登場人物ひとりの中にカプセル化「できる」専門知識やロジックをメソッドとして表現したものであるといえそうです。
いま,カプセル化「できる」と強調したことに気づかれましたか?これらDomain Modelはアプリケーションの中核となる「知識」や「ロジック」を表現しますが,一方でそれら全てを表現し尽くすことは「できない」のです。
というのも,複数の登場人物の関係性の中で初めて表現できる知識やロジックもあるはずだからです。
ひと声で「これやって」と言われたら,登場人物たちをまとめて,いい感じに業務フローをまわすのもまた,専門知識やロジックであり,これらをカプセル化するのがDomain Serviceです1。
たとえば「会社全体を運営する」業務フローを考える時,「経理部での仕事内容」は十分に中核にあり専門的です。
一方でこの「経理部での仕事内容」ももっと細かな粒度に分割できるはずで,「請求・支払いをする人」や「給与計算をする人」「書類作成をする人」などの個々の登場人物が関わり合うことではじめて「経理部での仕事内容」が実現されます。
でももちろん,「会社全体を運営する」経営層の立場から,直接個々の登場人物をつなげて「経理部の仕事内容」を実現するのは大変です。できれば会社の経営層が「経理部さん,この仕事やってください」と仕事を投げたら,いい感じに内部で連携してやってくれる,そんな業務フローの単位があればいいですよね。それがDomain Serviceです(だとおもっています)。
一般的なDDDの文脈におけるDomain Modelの意味範囲
ここまでオニオンアーキテクチャの一癖ある語彙について触れてきましたが,基本的にはDomain Modelと言われたら,これまで書いてきたような「登場人物」や「専門家のもつ知識」,「業務ロジック」等をまとめて指す,と考えてよさそうです。
このときDomain Modelは,Domain領域を具体的にモデリングした結果(要するに,指し示す領域はDomainと同じ)である,といえるでしょう。
そしてDomain Model≒Domainを内部にあるモノを大まかに分類すると,以下のようになるでしょう。
-
Entity,Value Object: 登場人物の実体を表現し,ひとりで実現できる業務ロジックやルールをカプセル化する -
Aggregate: 集約。「登場人物」の一単位であり,属性をValue ObjectやEntityで表現する -
Service: 複数のEntityやValue Objectが関わり合って実現できる業務ロジックをカプセル化する -
Repository: データの永続化や取得をインターフェース等を用いて抽象化する。2
Domain Serviceと呼ぶのは大げさな,ちょっとしたロジックの,私なりの取り扱いを紹介します。
EntityやValue Objectとは少し性質が異なるようにみえるが,一方でそれらの関係性をとりもつService的役割を果たすわけでもない,というような微妙な立ち位置のロジック,すなわち日常語の意味での「ロジック」に近いモノを,そのままlogicと名付けます。ディレクトリ構成でいえば/domain/logicみたいな感じで配置します。serviceほど大きな粒度で登場人物を扱うわけではないが,実体がイメージしづらい「ロジック」や「ルール」をここで実装します。
まとめ
DDDにおける様々な用語の雰囲気・気持ちを改めて整理することで,「オニオンアーキテクチャにおけるDomain Model」と「DDDのDomain Model」の違いを考察してみました。
オニオンアーキテクチャにおいては,Domain Modelは登場人物に絞った意味で,Domain Serviceはそれら登場人物を利用して実現できる,専門的な業務ロジックを表現したものである。
一方,より一般的なDDDの文脈では,Domain Modelは登場人物と業務ロジック全般,さらにリポジトリ等を包含する総合的な呼び名である。より細かい意味合いで分けるならEntityやAggregate,Serviceなどがある。
こうした解釈を行えば,DDDのクリーンアーキテクチャやオニオンアーキテクチャにおけるパッケージ構成やディレクトリ構成も考えやすくなるかもしれません。3
ここまでお読みいただきありがとうございました!
-
Domain Model内部には,「ひとりで完結する仕事」がカプセル化されます。一方で,Domain Serviceの責務は,「Domain Modelの関係を取り持って業務フローを実現する」といえます。 ↩ -
Domain層にRepositoryのインターフェースを置いてもよいか,という点はしばしば議論になります。厳密なDDDの理論ではDomain層は値の永続化(要するにDBへの読み書き)に関心をもたない,とされるからです。ですが,データストアへの問い合わせをしなければ実現できないドメインロジックも存在するので,この辺りは妥協しても怒られないでしょう,と私は考えています。 ↩ -
たとえばディレクトリ構成に"src/domain/models"と"src/domain/services"とあれば,前者が「登場人物」 ,後者が「登場人物が関わり合って実現できるロジック」を格納しているのであろう,と推測します。
一方で"src/domain/entities"や"src/domain/valueObjects","src/domain/services"のような構成であれば,厳密に「登場人物」を分類しながら,単一の登場人物に収まりきらないロジックを切り分けているのだろう,と推測できます。
また,"src/domain"というディレクトリの配下に,ある程度大きな粒度でディレクトリが作られていたとしたら(このパターンが一番多そう),「登場人物」と「ロジック(サービス)」が一点にまとめられているのであろう,と推測できます。このとき,当然「登場人物」同士ではお互いに関心を持ちませんが,「ロジック(サービス)」は別領域の「登場人物」や「ロジック」に関心をもつ=依存する可能性があります。 ↩