ドメインとかモデルとかよく分かってない
MVC とか DDD とかの中で、「ドメイン」とか「モデル」とか「サービス」とか「ロジック」とかいう言葉が何となく出てきて、ちゃんと区別出来てない感じがしたので整理する。
目次
MVC の整理
まず、一般的な MVC の定義を再度整理する。
- View = ユーザインターフェース層
- ユーザに情報を表示したり、入力を解釈したりするところ
- Controller = アプリケーション層
- View からのリクエストを受け取り、「モデル」が持つ処理や、「サービス」に切り出した処理を呼び出すことで、問題を解決に導き、View (ユーザインタフェース層) にレスポンスする
- Model = ドメイン層
- ビジネスロジックを持つところ
ココで、「Model とはドメイン層のこと」という言葉が出てくることで、理解がややこしくなる。
DDD の文脈
MVC の構成要素とは別に、オブジェクト指向や DDD の文脈で、「ドメイン」とか「ドメインモデル」とかいう言葉が使われる。無理に MVC の「M」に当てはめようとせず、一旦分離して考えた方が良い。
- ドメイン
- 元は「領域」を示す語
- システムで根幹となる概念
- モデル
- 同義語 : オブジェクト指向モデル、ドメインモデル、ドメインオブジェクト
- ある概念をプログラムするために抽象化したモノ
- いくつかのプロパティと、自身で行う「処理 (メソッド)」からなるクラスの形であることが多い
- 例 : 「ブログシステム」であれば、「記事」や「コメント」、「管理者」といったモノが「モデル」として作られる
- 例 : 「クルマ Class」は
speed
プロパティを持ち、加速する・クラクションを鳴らすといったメソッドを用意している
「モデル」を表現するパターンとして、以下の3つのパターンがある。
- エンティティ
- O/R マッピングの単位として扱われるモデルクラス
- DDD においては、O/R マッパーの話は出てこなくて、一意に特定・識別できるモデルを示す
- 値オブジェクト (VO・Value Object)
- 同義語 : DTO (Data Transfer Object)
- 値を持つだけのモデルクラス。POJO (Plain Old Java Object) といえばコードの雰囲気は分かりやすいか。プロパティ (と Getter・Setter だけ) な感じ
- O/R マッパーやフレームワークに依存しないのが特徴
- DDD においては、イミュータブルに保たれるのが特徴
- サービス
- 同義語 : ドメインサービス
- 単一の「モデル」に責任を押し込むと不自然なタスクや、複数のモデル間のやり取りを担う処理を実装するモノ
- 「モデル」を引数にとる関数の形であることが多い
- Rails は ActiveRecord との連携により、Model クラスが大量のロジックを持ってしまい、Fat Model が生まれやすいが、うまく Service クラスを作って切り出せると緩和できる
(ドメインイベントは無視。DB アクセスを担う DAO も無視)
ディレクトリ構成でいうとどうなるの
普通に MVC 構成で分けようと思うと、
my-app/
├ views/
├ controllers/
└ models/
となって、models
にあらゆるビジネスロジックが集約することになる。model
という単語が「ドメイン層」と同義な印象である。
Rails のディレクトリ構成を超簡素に抽出するとこんな感じか。
my-app/
├ views/
├ controllers/
├ models/
├ entities/
├ services/
└ value-objects/
Rails の場合は ActiveRecord パターンがあるためか、models
が entities
を担っていてあんま区別されてない感じ。Rails 以外の言語・FW で、例えば Web API を構築する際は、DDD の文脈ではなく「O/R マッパーとしての entities
」と models
とを分けて管理すると良さそうだ。
「ドメイン層」を表現するディレクトリ階層がないものの、models
・entities
・services
・value-objects
の4つをまとめて「ドメイン層」と表現することになるワケだ。無理やり階層で表現するとしたらこうなるか。
my-app/
├ views/
├ controllers/
└ domains/
├ models/
├ entities/
├ services/
└ value-objects/
自分は Node.js 系 SPA だとこんな感じで作るかしら
フロントエンド (SPA) の場合、上述までの views/
の中を細分化するワケだが、自分は Angular の構成が気に入っているので、Angular が推奨する構成をベースに考えがち。
frontend/
├ core/ … (アプリ全体にまたがるモノ)
│ └ services/
├ shared/ … (アプリ全体で共用するモノ)
│ ├ classes/ … (共通のクラス)
│ ├ components/ … (共通コンポーネント置き場)
│ └ services/ … (共通サービス置き場)
└ pages/ … (いわゆる「Views」)
├ hoge-page/
└ fuga-pages/
├ classes/ … (1画面内で使うクラス)
├ components/ … (1画面内で使う子コンポーネント置き場)
└ services/ … (1画面内で使うサービス置き場)
フロントエンドにおけるビジネスロジックは、ほとんど Service として表現する。Service で扱う「モデルクラス」、Value Object などは、明確に分離しなくても良いレベルなので classes/
ディレクトリでまるっと管理してしまうことが多いか。別けたければココらへんは Angular の設計思想に沿って別けたらよかろう。
Components → Services という呼び出し順は一定しているので、見通しは悪くないと思う。
バックエンドは、Angular に似た設計思想で作られている NestJS を参考にすると良いだろう。以前は Rails の構成を参考に、Express.js で同等の構成を作っていたこともあった。
backend/
├ routes/ … (ルーティング・URL 定義)
├ controllers/ … (リクエストを受け取りレスポンスするだけ)
├ services/ … (ドメインサービス。基本的にコントローラからサービスを呼び出してあれこれ処理させる作りにしがち)
├ models/ … (ドメインモデル。FW や ORM に依存せず、プロパティとメソッドを持つクラス)
└ entities/ … (TypeORM などの ORM と連携するためのエンティティ。「ドメインモデル」とほぼ同じだけど ORM 用のクラスが出来がち)
NestJS だと、機能ごとに modules/
みたいなディレクトリの配下に切り出してるかな。
Routes → Controllers → Services という動線は常に一定させておいて、Services 内で適宜 Entities を使って処理して、Models に結果をまとめて返す、みたいなことをしがち。models/
が微妙な感じで、classes/
でも良いような、Value Object じみた使い方をしてることが多い。
分かったような分かんないような
自分はそもそも DDD やクリーンアーキテクチャといった手法が好きじゃないので、ドメインとかモデルとかいう単語が別の文脈の似て非なる用語と混ざっていながら、どうでもええわと思って無視してきた。
並のプログラマのスキルじゃ、Service クラスを適宜作って分かるレベルまでしか理解できんって。なんでもかんでも小さな Value Object や細かい Model を作っても、やたら見通し悪いなーと思うだけで、ついていけんって。
だから自分は、Components or Controllers → Services という動線で基本的に終わらせて、DB アクセスが必要なら適宜 (ORM としての) Entity を作ったり、データをまとめる単位としてテキトーに POJO 的な Class (「モデル」クラス) を作ればええやん、という感じでいる。
そして、一つのアプリが担う「ドメイン」を小さく保ち、マイクロサービス構成で組み合わせていけば、大きな「ドメイン」も表現できるし、チーム開発する時はそういう感じになるんじゃね?なんて思っている。DDD とかクリーンアーキテクチャって、ちょっとモノリシックな匂いがするのもあって嫌いなのよね。やたらに膨らまそう膨らまそうとしてるでしょ?俺たちそんな賢くないから、小さく保とうや。
参考文献
- 【DDD】ドメインモデルとドメインサービスについて調べたがまだよくわかっていない - See the Elephant
- ドメインモデル、ドメインロジックとは何かをコードを交えて考えてみる - Qiita
- 混乱しがちなサービスという概念について - かとじゅんの技術日誌
- DDDにおけるアプリケーションサービスとドメインサービスの違い - Qiita
- 中規模Web開発のためのMVC分割とレイヤアーキテクチャ - Qiita
- お前らがModelと呼ぶアレをなんと呼ぶべきか。近辺の用語(EntityとかVOとかDTOとか)について整理しつつ考える - Qiita
- ドメイン駆動設計のエンティティとクリーンアーキテクチャのエンティティ │ nrslib
- DDD基礎解説 : Entity、ValueObjectってなんなんだ - little hands' lab
- MVC の Model 肥大化への対処 - Qiita
- 違いについても解説!JavaのDAOクラスとDTOクラスとは | TechAcademyマガジン