天下一バリューオブジェクト牛丼談義
どうやらバリューオブジェクト(値オブジェクト)がホットな話題らしい。
今も熱い牛丼談義が続いている。僕も自転車置場で牛丼はつゆだくがうまいとか、卵は半熟か生かどうかとか話すのは大好きだ。僕は最近、大盛りを食べるのはちょっときつくなってきた。それはともかく、せっかくだから僕もバリューオブジェクトの天下一牛丼談義に参戦しよう。
天下一牛丼談義への参戦のきっかけは、かとじゅんさんがバリューオブジェクトはドメイン固有型の一種であるという解釈を記事で紹介していて、それは違うんじゃないかと思ってtweetをしたことだ。これにはかとじゅんさんから回答をもらうことができた。しかし、まだいくつかの疑問が残っているので、ドメイン固有型とドメインオブジェクトとはなにかという議論を通じて、バリューオブジェクトと不変条件、そしてバリューオブジェクトとは結局は何であるのかというのを、ここで整理していきたい。
バリューオブジェクトはドメイン固有の型なのか?
ドメイン固有型(値オブジェクト含む)を再考するという記事の中で、かとじゅんさんは次のようにバリューオブジェクトについての言及している。
ここでドメイン固有型は、記事内でも参照されている97 Thingsのプリミティブ型よりドメイン固有の型というエッセイのドメイン固有の型(Domain-Specific Types)のことのようなので、DateやPointのようなバリューオブジェクトについても、ドメイン固有の型とするのは矛盾していると思ったのでtweetをした。
これには次のように回答をもらえた。
それでもDateやPointをドメイン固有の型と言うのは難しいと思ったので、さらに次のような質問をして、回答ももらえた。回答によると97 Thingsのドメイン固有の型の一種はなく、DDDのドメインオブジェクトの一種という解釈のようだ。
まずは、バリューオブジェクトは97 Thingsのドメイン固有の型ではないという理解で良いだろう。
ドメインオブジェクトとはなにか?
ドメインオブジェクトが自分が関わらない他人のドメインのオブジェクトを含むかどうかについては、他人のドメインについて言及するのは混乱を招くので避けるべきだし、用語を作る側を想定すると、そのような定義はしないのでは思うので、かとじゅんさんと僕の認識は異なる。
しかし、そもそもDDDのドメインオブジェクトとはなんだろう?実はよくわからない。なぜならEric Evans氏による明確な定義がどこを探しても見つからないのだ。
DDDの原典であるエリック・エヴァンスのドメイン駆動設計(DDD本)の第4章では次のような記述が見つける。
正直イマイチよくわからないが、ドメインオブジェクトはドメインモデルを表現する責務を負うらしい。結局、DDD本ではドメインオブジェクトという用語は何度も書籍内で使われているが、「ドメインオブジェクトとはXである」というような明確に定義だとわかる記述はDDD本では見当たらない。
DDD本が難解なせいか、Eric Evans氏による別冊のリファレンスが出版されていて、PDFが無料で配布されている。このPDFを開くと表示されるタイトルが Microsoft Word - pdf version of final doc - Mar 2015.docx なのも、なかなかに味わい深い。しかし、やはりドメインオブジェクトの定義は見つからない。ドメインの定義はあるので代わりに参照しよう。
ソフトウェアのユーザーがプログラムを利用するときに対象とする領域をドメインと呼ぶようだ。DDDのドメインオブジェクトは、おそらく、ドメイン、あるいは、ドメインモデルを構成するオブジェクトのことを指す明確な定義がない緩い用語なのだろう。DDDのコンテキストで用語が何を意味するかという疑問に対して、定義ではなくそれぞれの解釈が返ってくるのは、どうやらDDD本の記述に理由がありそうだ。
ちなみに、Eric Evans氏の意味するところのドメインオブジェクトと完全に一致するかは分からないが、wiki.c2.com では次のように説明されている。
とりあえず、ドメインオブジェクトはドメインモデルを構成するオブジェクトという理解で問題なさそうだが、どうなのだろうか。
他人のドメインのオブジェクトはドメインオブジェクトなのか?
用語の実用性の観点から、そんなことはないんじゃないかと思うけれど、かとじゅんさんの言うように、言語の標準ライブラリや外部のライブラリが提供する、汎用的なDateやPointのようなオブジェクトも、他人のドメインのドメインオブジェクトだから、ドメインオブジェクトと呼ぶのだろうか?
DateやPointは汎用的なドメインに属するので、ドメインオブジェクトと呼べるというのがかとじゅんさんの論のようだ。では、汎用的なドメインとは何を指すのか? どうやら、汎用サブドメイン(Generic Subdomains) のことらしい。
DateやPointが汎用サブドメインに属する事があるから、それらをドメインオブジェクトと呼ぶことに不自然ではないことを判断するには、汎用サブドメインとは何かかが分かれば良さそうだ。では、DDD本の汎用サブドメインの説明を参照してみよう。
やはりDDD本は難解だが、プロジェクトの主たる動機とならないサブドメインから、さらに汎用的なモデルを括りだして集めたものが汎用サブドメインのようだ。つまり、ソフトウェアがプロジェクトの動機するドメインの更に中心的な存在であるコアドメインにたいして、それ以外のサブドメインに属するオブジェクトもドメインオブジェクトと呼ぶのであれば、汎用サブドメインに属するオブジェクトもドメインオブジェクトと呼ぶことができる。また、DDD本では金銭や通貨が汎用サブドメインのオブジェクトとして扱われている。これらのオブジェクトがあるドメインに属するドメインオブジェクトと説明されるのは十分に理解できる。ここから、次のような説明が成り立つのではないだろうか。
ドメインモデルを構成するすべてのオブジェクトはドメインオブジェクトである
この説明であれば他人のドメインに言及する必要はない。もちろん明確な定義が無いものに対して、これが真のドメインオブジェクトの解釈だと言い張る気はない。しかし、自分のスコープ外の他人のドメインに属するオブジェクトも、ドメインオブジェクトと呼ぶのであれば、オブジェクトとドメインオブジェクトの境界は無くなり、あるオブジェクトをドメインオブジェクトと呼ぶ意味は消失してしまう。
ドメインオブジェクトという用語の意味が消失しない説明をするためには、私のドメインオブジェクトだけが、ドメインオブジェクトでなければならない。他人のドメインに属するからDateやPointもドメインオブジェクトという説明にはやはり難があるのではないだろうか。一方で、ドメインモデルを構成するすべてのオブジェクトはドメインオブジェクトであるとするならば、DateやPointのような汎用的なオブジェクトも、ドメインによっては(私の)ドメインオブジェクトとすることができる。
バリューオブジェクトはドメインの不変条件への責任をもつのか?
不変条件(invariant)はドメインオブジェクトと違い、DDD本なかでも用語解説の中できちんと次のように説明されている。
それでも定義としてはなんともふわりとしている。あるいはこれがDDDの味わいなのだろうか?この霞のようでゆるくふわりとした味わいがわかるようになれば、DDDマスターになれるのかもしれない。
それはともかく、DDDがPofEAAからバリューオブジェクトなどの用語を借用しているように、不変条件もおそらくはBertrand Meyer氏の契約プログラミングからの借用だろう。DDD本では不変条件の他にも、契約プログラミングの用語の事前条件や事後条件なども登場している。Bertrand Meyer氏の著作のオブジェクト指向入門 第2版 原則・コンセプトでは不変条件の定義を確認してみると不変条件ではなく、クラス不変表明(class invariant)として、第11章 契約による設計:信頼性の高いソフトウェアを構築する の 11.8 クラス不変表明 の冒頭で次のように説明されている。
また、巻末のオブジェクト技術用語集では次のように説明されている。
ついでにDDD本の説明にも登場しているので、表明という用語の解説も引いておこう。
なんだか難しいが、Wikipediaにもあるように、クラス不変表明とはクラスのインスタンスのコンストラクタやパブリックなメソッドが呼び出された後に、常に満たしてなければいけない状態に対する条件のことだ。
オブジェクト指向入門のEiffelや、DDD本の文脈で登場するJavaのような、クラスとオブジェクトを基礎概念として、クラスのインスタンスとしてオブジェクトを生成するオブジェクト指向言語では、バリューオブジェクトはクラスのインスタンスとして扱われるので、かとじゅんさんの解釈の中で登場する不変条件(invariant)も、このクラス不変表明(class invariant)のことだと仮定してもよいだろう。
DDD本ではパフォーマンスなどの制約がある場合を除いて、バリューオブジェクトを不変にしなければならないと記述されている。不変条件はクラスのインスタンスの状態への制約なので、不変なオブジェクトであれば、そのオブジェクトの振る舞いは、状態に対する条件を常に守ることになる。つまり、バリューオブジェクトはその構築以外ではプログラマがクラス不変表明を気にかける必要はない。
インスタンスの構築でクラス不変表明への責任を負うのは、必ずしもコンストラクタではない。Factoryパターンのようにファクトリが不変表明への責任を負う場合がある。不変表明をどこで保証すべきかについてはDDD本の 第6章 ドメインオブジェクトのライフサイクル ファクトリ(FACTORIES) でも言及されている。
少なくとも、DDD本においてもバリューオブジェクトの不変表明を負うのが常にコンストラクタであるとは限らないのがわかる。したがって、バリューオブジェクトが常にドメインに対するクラス不変表明への責任を負うと言うのは難しいだろう。
バリューオブジェクトとDTOに包含関係はあるのか?
PofEAAのバリューオブジェクトがDTO(Data Transfer Object)を含むかどうかについて、過去にコミュニティで議論があったとかとじゅんさんの記事にはあるが、これはPofEAAでも言及されている。
15.2 データ変換オブジェクトの冒頭では次のように
15.2.3 参考文献では次のように記されている
Martin Fowler氏が、DTOのことを私のバリューオブジェクトはまったく異なるパターンと言っているので、DTOとバリューオブジェクトの間に包含関係を考える必要はなさそうだ。
DDDのバリューオブジェクトとは何であるのか?
バリューオブジェクトはドメインオブジェクトの一種かどうかは、それらは直交する概念なので、包含関係は存在しない。Martin Fowler氏のwikiにもあるように、たしかにドメインオブジェクトはエンティティ(参照オブジェクト)や、バリューオブジェクトや、サービスなどに分類できるが、それはバリューオブジェクトがドメインオブジェクトの一種であることを必ずしも意味しない。牛丼も並盛・大盛・特盛に分類はできるが、並盛は牛丼の一種だとはならない。豚丼や親子丼にだって並盛がある。
DDD本も見てみると、バリューオブジェクトは次のように説明されている。
いまいちよく分からない部分もあるが、PofEAAの中で説明されているバリューオブジェクトと同じように、同一性を持たないオブジェクトをバリューオブジェクトと呼んでいることはわかる。一方で、ドメインにおける記述的な側面を表現するとは何を意味するのか苦慮するところだ。僕にはよくわからなかったので教えてもらえるとうれしい。
また、バリューオブジェクトの不変性については次のように説明している。
DDD本を読んでもいまいち分からないこともあるが、同一性を持たないオブジェクトを可能ならば不変にするというDDD本の説明は概ねPofEAAの説明と一致する。
やはりバリューオブジェクトはPofEAAからの借用語なようなので、少なくともPofEAAの説明を満たすものがDDDにおけるバリューオブジェクトといっても差し支えはないだろう。このことは、あるバリューオブジェクトがドメインオブジェクトであることと矛盾しない。そして、バリューオブジェクトが、必ずしも(私の)ドメインオブジェクトだとは限らない。
まとめ
DDD本は20年も前の本だ。出版当時のソフトウェア開発の問題を解決して、その当時のコミュニティに受け入れられたかもしれないが、今となってはその内容に古臭さがあるのは仕方がないのだろう。この本がもっと用語の定義がしっかりしていればとも思うけれど、それではバリューオブジェクトの牛丼談義はなかっただろう。
まあ幸い牛丼談義は楽しい。用語の曖昧さもDDDの味わいだと思うのが良いだろう。そして、珠玉のアンサーソングを期待している。
ヘッダ画像はWikimedia CommonsからCC0 1.0に基づいて利用しています。
この記事が気に入ったらサポートをしてみませんか?