みなさんは、Modelと言われたときに何をイメージしますか?
こんなアレを思い浮かべた方も多いかと思います。
マサカらせてください。やはりお前らのModelは間違っている。
アレをModelと呼ぶと何が不味いのか
すみません、早速言い過ぎました。半分は正しいです。MVCの発明者、Trygve Reenskaug氏による1979年の説明によると、
Models represent knowledge. A model could be a single object (rather uninteresting), or it could be some structure of objects. 1
このように「Modelは単体のオブジェクトであってもいい」と言っています。つまり__アレ__もModelっちゃModelなのです。
でも、お前らはいつもModelと言ったら__アレ__だけを指していて、 some structure of objects
をModelと呼ぼうとはしない。結果、ビジネスロジックがモデル層から染み出して、プレゼンテーション層に if (user.age > 35) { ... }
とか書いたりするんです。そりゃ UserModel
って言われたら、外から user
を取り扱うロジックは Model
ではないんだなって思っちゃいますよ。
2009年のReenskaug博士によれば、オブジェクト指向プログラミングの目的は、ユーザーの、あるいはプログラマのメンタルモデルと一致させるコード上のモデリングをすることです。
the goal of object-oriented programming pioneers was to capture end user mental models in the code. 2
Modelとは、ビジネスロジックの置き場です。ビジネスロジックとはつまり、OSやプラットフォームが変化しても変わらない部分。
UIやデータベースの都合に左右されない、本質的なロジックをすべて含むのがModelというレイヤです。
__お前らがModelと呼ぶアレ__は、Modelの中のほんの一部分に過ぎません。
MVCのモデルの誤解を解くためにフレームワークを例に挙げようとしたら誤解してもしゃーないなって思った - Qiita を読むと、誤解が広まったのはたぶん各種フレームワークの説明が悪かったんだろうと思います。
でもなんにせよ、曖昧な名前は責務を不明瞭にし、ロジックの置き場所を見失わせます。
そういうミスを防ぐためには、まず__アレ__をModelと呼ぶのをやめて、もっと具体的に呼ぶべきなのです。
○○Managerや○○Utilって名前を避けようって話はよく聞きますが、だったら○○Modelも避けて、もっと具体的な名前をつけましょうよ。
周辺の用語について
POJO? POSO? Domain? Entity? Value Object? DAO? DTO?
色々な用語があって混乱すると思います。現に、混乱して色々調べたものの、やっぱりすっきりできていないエントリはQiita内外に散見されます。混乱の原因は、それぞれの用語の出自が整理できていないから。ものによっては文脈によって全然別物のことを指していることもあり、そこの切り分けができないと全容を理解することは不可能です。
そこで、この記事では、各用語を文脈ごとに整理して解説しつつ、 __アレ__をどう呼ぶべきかを模索してみます。
フレームワーク周り(Java寄り)の文脈
Entity
Java Persistence API, ADO.NET等々、各種フレームワークでだいたい「O/Rマッピングの単位」として使われているワード。
Entityとは「永続化可能なJavaオブジェクト」をさします。具体的にはRDBにある表に相当するオブジェクトだと思ってください。データベースの表(テーブル)に列(カラム)があるように、Entityには変数(フィールド)があります。またそれらのフィールドを操作するためのアクセッサー・メソッド(getter/setter)があります。Entityをインスタンス化するということは、データベースの行に相当するレコードをEntityのフィールドに関連付けることです。 3
フレームワークの力を借りて、データベースの実装を意識せずにデータ構造を取得できます。すごいぞ強いぞ!
Plain Old Java Object(POJO)
ちょっと待った、と水を掛けるのがPOJOです。
Entityのような特定のフレームワークに依存した機能を必要とせず、言語由来の「普通のオブジェクト」を使った方がよい場面で、そのことを強調したいときに使う、Martin Fowlerらが作ったワードです。
「システムに普通のオブジェクトを使うことに強い抵抗を持つ人が多いのはなぜかと考えたとき、それは単純なオブジェクトに良い名前がついていないのが原因だという結論に達した。そこで我々が名前をつけたら、それがとても流行りだした。」 4
※Entityの対義語というわけではありません。特定のフレームワークに非依存であればすべてPOJO。一般的な名称です。
__アレ__周りの単語を調べる系のQiita記事は他にもありますが、そのきっかけになってそうな「POSO」も、Swiftの国際的カンファレンスであるtry! Swift2017にて、同種の文脈で出てきたワードです。Swiftに限らず、最近のモダンな言語では、その言語なりのPOXOで賄えるなら賄ったほうがよい、というのが定番パターンになっていそうですね。
Data Transfer Object(DTO)
ビジネスロジックが含まれないデータの入れ物であり、メソッドを持たない。
もともとDTOパターンが編み出されたきっかけは、リモートのプレゼンテーション層でDTOのインスタンスを扱いたいという要求だった。DTOをビジネス層で組み立ててシリアライズし、それをネットワーク越しに送信して、プレゼンテーション層でデシリアライズする。 5
ちなみにSunコミュニティではかつて、DTOのことをValue Objectと呼んでいました。このValue Objectは、DDDの文脈のものとは別なので注意。
なお、DTOはネットワークを介さないレイヤ間で使われることもあり、そこではLocal DTOというパターンもありうる。
Domain Payload Object(DPO)
しかしLocal DTOには欠点があります。
大抵の場合はDTOを使うとすべてのデータに対して同じ定義を二度書かなければいけないので大きなコストになるという批判が大きいようです。
プレゼンテーション層がネットワーク的に離れていない場合は、このパターンを使うと、アプリケーションの設計が無駄に複雑化してしまう。いわゆるYAGNI("You Ain't Gonna Need It")だ。 6
そこで生み出されたパターンがDPO。ヴァーノンが「実践ドメイン駆動設計」で解説しているDPOの構造は、「DDDにおける集約(※後述)への参照を保持したオブジェクトに、ビュー用のプロパティが生えている」というもの。
DTOより低コストに作成可能なのがメリット。
Data Access Object(DAO)
DTOを、レイヤ化アーキテクチャでいうData層から取り出してModel層に渡す役割がDAOです。DAO自身はプロパティを持ちません。
ドメイン駆動設計(DDD)の文脈
モデル層(エリック・エヴァンスの「ドメイン駆動設計」では「ドメイン層」と呼んでる)を他からきちっと切り分けて、その中にドメインモデルをきちっと設計していく手法。……と言うと確実に別のマサカリが飛んでくるんだけど(DDDはアーキテクチャではなく、コードに留まらず実装者以外も巻き込むイテレーティブな開発手法なのです)、そこまで説明するとアレなので端折ります。
ドメイン駆動設計について詳しい解説書としては、2003年にエリック・エヴァンスがドメイン駆動設計という本をまとめ、その10年後、ヴァーン・ヴァーノンが実践ドメイン駆動設計(iDDD)という本でより具体的な実装について述べています。
本記事では用語説明にあたり、それら2冊を参照しています。
ドメインモデル
そもそもドメインモデルとは何か。
すべてのソフトウェアプログラムは、それを使用するユーザの何らかの活動や関心と関係がある。ユーザがプログラムを適用するこの対象領域が、ソフトウェアのドメインである。 (...) ドメインモデルとは特定の図ではなく、図が伝えようとしている考え方である。これはドメインエキスパートの頭の中にある単なる知識ではなく、その知識が厳密に構成され、選び抜かれて抽象化されたものなのだ。 7
とのことです。
Entity
はい名前被り、きました。
DDDでいうエンティティは、先述したO/Rマッピングの対象となる(永続化という概念を含む)エンティティとは似て非なる概念です。
DDDにおいては、エンティティは「一意な識別子によって特定される」という特性を持ちます。ライフサイクルを通じた連続性を持ち、その属性から独立して同一性が保たれるのであれば、それはエンティティ。
同じような概念でも「システムが同一性を区別する」必要があるかどうかでエンティティかどうかは変わる。たとえば同じスタジアムの座席でも、指定席は座席番号(識別子)で区別されるからエンティティ。自由席は区別されないからエンティティではない。
Value Object(値オブジェクト・VO)
エンティティではないものはどう表現するかというと、値オブジェクトです。ライフサイクルの追跡が不要で、識別子ではなく構造全体によって同一性を判定するときには値オブジェクトを使います。値オブジェクトは不変(イミュータブル)であることが望ましく、計測値や説明が変わったときには全体を完全に置き換えられて、振る舞いに副作用がないことが求められます。
ドメインイベント
「実践ドメイン駆動設計」に登場します。エヴァンスのDDD本が発刊された後に発見された概念。
ドメイン内で起こった何かの出来事。
「現場で役立つシステム設計の原則」には、業務の関心を「ヒト・モノ・コト」という3分類に分けるテクニックが紹介されていますが、その「コト」というのがこれにあたると思われる。
Aggregate(集約)
DDDには、あまり語られないけれど重要な概念として、集約があります。
エンティティや値オブジェクトをとりまとめた、オブジェクトグラフのことです。
Repository
永続化の手段。
集約のインスタンスを、それに対応したリポジトリ内に置く。そのリポジトリを使ってインスタンスを取得する。リポジトリがあることで、ドメインでは裏側にある永続化のメカニズムを気にする必要がなくなります。
なお、リポジトリは、その実装がたとえデータ層にあったとしても、インタフェースはモデル層に定義されます。
クリーンアーキテクチャの文脈
クリーンアーキテクチャは、Uncle Bobが2012年に提唱したアーキテクチャです。古典的なレイヤ化アーキテクチャの問題(Data LayerとModel Layerの依存方向が逆)を修正し、ヘキサゴナルアーキテクチャ、オニオンアーキテクチャ、DCIなどの概念を統合しました。
https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html
ここにもレイヤに関わる概念が出てくるので、Model層に絞って紹介しておきます。
Entity
Entities encapsulate Enterprise wide business rules. An entity can be an object with methods, or it can be a set of data structures and functions.
ということで、クリーンアーキテクチャ文脈でのエンティティは一意性については特に触れられておらず、DDDにおける値オブジェクトもこの括りに入りそう。
クリーンアーキテクチャはあくまでコンセプトであり、レイヤの分割粒度についての縛りはないので、そこまで真面目に考えなくてもいいかもしれない。
Use Case
アプリケーション固有のビジネスロジックを担うレイヤ。アプリレベルでEntityからの/Entityへのデータフローを制御する。データベースやUI、共有フレームワークの変更からは影響を受けないことを期待。
まとめると、こういう図になります
__お前らがModelと呼ぶアレ__の呼び方の検討
フレームワーク文脈の用語は皆、Data層のやりとりをどう隠蔽するか、に注目しており、Model層には興味ないようです。POJOも別にModel層に限った概念ではないしなあ…。
<追記>
上記取り消し線部分について、Twitterにて反論をいただきました。
実際の現場で Data Source 層の出し入れのためだけに ORM が歪んで使用されるケースが多いことは確かですが、それが Entity の一般的に認められた定義であるかのような記述は不正確だと思います。
— Takuma SHIRAISHI (@ts7i) 2017年12月14日
例えば、JPA でいう Entity は仕様で "An entity is a lightweight persistent domain object." (JPA 2.1 仕様 https://t.co/ViuKXDAyOC p23 参照) と定義されていて、単なる Data Source 層の出し入れのためのオブジェクトではなく、Domain 層のオブジェクトです。
— Takuma SHIRAISHI (@ts7i) 2017年12月14日
つまり少なくともOracleの定義からすれば、Entityは__アレ__と重なりうるもののはずなのです。
ただし、永続化の概念が入ってきてしまうので、やはり__アレ__を表すには、この文脈のエンティティは惜しい感じですね。
追記>
DDD文脈の用語は、エンティティと値オブジェクトが惜しい感じですね。これらを合わせて「ドメイン駆動設計」ではなんと呼んでいるか調べたところ、よくわかりませんでした。「ドメインオブジェクト」という単語はあるのですが、後述の集約などを含め、ドメインモデルを構成するすべてを含めてそう呼んでる感じなんですよね。
ただ、「実践ドメイン駆動設計」のほうでは
ドメインオブジェクト(エンティティや値オブジェクトなど) 8
という記述があり、ひょっとするとエヴァンス本発売の2003年から「実践」発売の2013年までの間に、ニュアンスが変わっているのでしょうかね?
<追記>
……👆と思いましたが、コメントで @ktz_alias さんにいただいた情報によると、2016年発刊のFunctional Reactive Domain Modelingではエヴァンス本に近い意味で「ドメインオブジェクト」が使われているそうです。そのかわり、__アレ__に近い文脈では domain element
というワードが使われているとのことです。
追記>
クリーンアーキテクチャ文脈でのエンティティは、まさに__お前らがModelと呼ぶアレ__に近いですね。
ただ、「エンティティ」というワードはあまりに色々な文脈で被りまくってるし、クリーンアーキテクチャを採用していない場合にそこだけ借用するのもなんだか微妙な感じがします。
結論
一番使ってて誤解が少なく歴史的な妥当性がありそうなのは「ドメインオブジェクト」じゃないかな、という感じで。
DDDは普通のオブジェクト指向の延長線上にある概念なので、一部だけ借用するのも悪くはないはず。
ということで皆、__アレ__のことはもうModelと呼ばず、ドメインオブジェクトと呼ぼう!
あるいはもっといい名前があったら教えてください!
-
http://heim.ifi.uio.no/~trygver/1979/mvc-2/1979-12-MVC.pdf ↩
-
http://public.dhe.ibm.com/software/dw/jp/websphere/was/was61_ejb3fep_ws/ejb3_03java_persistence_api.pdf ↩
-
ヴァーン・ヴァーノン.実践ドメイン駆動設計(Kindleの位置No.11055-11061)..Kindle版. ↩
-
ヴァーン・ヴァーノン.実践ドメイン駆動設計(Kindleの位置No.11055-11061)..Kindle版. ↩
-
Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Kindle の位置No.737-749). . Kindle 版. ↩
-
ヴァーン・ヴァーノン. 実践ドメイン駆動設計 (Kindle の位置No.1543). . Kindle 版. ↩