DDD / Value Objects


VALUE OBJECTS (P97)

要約

VALUE OBJECTS

[文脈の説明]

多くのオブジェクトには概念的なアイデンティティはない。そのようなオブジェクトはモノのなんらかの特性を表している。

***

[問題についての説明]

子供たちが絵を描くとき、色や先端が尖っているかとかは気にするけど、同じ色や形のモノがあったとしたら気にしません。そして使い切ったときに別のセットから同じモノを取り出して、何も気にせずに作業を再開するでしょう。

冷蔵庫がかかれた絵があったとしたら、ある子供は自分の姉妹の絵は即座に見分けられるでしょう。姉妹の間には共通のアイデンティティがあって、それを絵にみることができるからです。しかしそれを見分けるために、書いたマーカーまで気にしないと行けなくなったら複雑になって絵を描くことが難しくなってしまいます。

モデルとして重要視されているオブジェクトはたいてい ENTITY で、その ENTITY のアイデンティティーを追いかけることは重要なので、全てのドメインオブジェクトにアイデンティティーを割り当てようとするのは自然なことで、実際いくつかのフレームワークではありとあらゆるオブジェクトに固有のIDを割り当てます。

システムは全てのオブジェクトを追跡可能にしようとしますが、それはパフォーマンスの最適化を犠牲にします。重要なアイデンティティーを見つけて、分散システムはデータベースの向こうにあるオブジェクトを安全に追跡できるように分析する必要があります。併せて、不自然なアイデンティティーはミスリーディングを招きます。全てのオブジェクトを同じ型にはめようとすると、それらのモデルは混乱します。

問題サマリ

ENTITY のアイデンティティーを追跡するのは不可欠ですが、他のオブジェクトのアイデンティティーを付与しようとするとパフォーマンスに悪影響を及ぼします。そして、分析作業によって全てのオブジェクトが同じようにみえるように同じ型にはめようとします。

ソフトウェア設計は複雑さとの戦いの連続です。私たちはどこに対して特別な対処が必要かを見極めないといけません。

しかし、アイデンティティーの欠如したオブジェクトを考えた場合、ツールボックスやボキャブラリを付与してはいけません。それらはそれ自身の特性とそれぞれ自身の意味をモデルに対して持ってます。これらは説明するためのオブジェクトです。

[問題の解決方法についての説明]

概念的なアイデンティティを持たないドメインの記述的なアスペクトを表現するオブジェクトを VALUE OBJECT と呼びます。VALUE OBJECT は我々がそれが誰(who)であるかやそれがどちら(which)であるかを気にするのではなく、それが何(what)であるかを気にした設計要素を表すために使用されます。

"色"は現在多くのベースライブラリで提供される VALUE OBJECT の例です。それらは文字列や数値として表されます。

色を混ぜ合わせるプログラムの場合、色同士を組み合わせられるように拡張されたカラーオブジェクトをもつリッチなモデルがあるかもしれません。これらには新しく作られる VALUE OBJECT を引き出すために複雑なアルゴリズムを持つことが出来ます。

VALUE OBJECT は他のオブジェクトの集まりかもしれません。家のプラン設計をするソフトウェアの場合、"窓のスタイル"のためのオブジェクトを作ることが出来るでしょう。属性を変えたり組み合わせるためのルールと同様に、"窓のスタイル"は"窓"オブジェクトと組み合わせれるでしょう。これらの"窓"は他の VALUE OBJECT で作られた VALUE OBJECT です。それらは次は"壁"オブジェクトに・・・というように順番に大きな要素に組み入れられるでしょう。

VALUE OBJECT は ENTITY を参照することが出来ます。例えば、私がサンフランシスコからロサンゼルスまでの景色を楽しみながらドライブするために地図サービスを使った場合、それらは Pacific Coast Highway 経由の Route オブジェクトを導き出すかもしれません。Route オブジェクトは VALUE であり、それらを参照している3つのオブジェクト(2つの都市と高速道路)は全て ENTITY です。

VALUE OBJECT はしばしばオブジェクト間のメッセージパラーメータとして渡されます。それらはいつも一時的で、操作のたびに作成されては破棄されます。 VLAUE OBJECT は ENTITY(そして他のVALUE)の属性として使用されます。"人"はアイデンティティーをもつ ENTITY としてモデル化するかもしれませんが、その人の"名前"は VALUE です。

解決方法サマリ

モデルの要素の属性だけを気にする場合は VALUE OBJECT として分類しましょう。それが伝える属性の意味を表して、関連する機能をそれに与えましょう。VALUE OBJECT は不変なモノとして扱いましょう。アイデンティティーは少しも与えてはいけません。そして、ENTITY を維持するのに必要な設計上の複雑さも排除してください。

VALUE OBJECT を形成する属性は概念的なもので形成されるべきです。例えば、通り/都市/郵便番号は"人"オブジェクトの別々の属性であるべきではなく、"住所"として単一で一貫性のある VALUE OBJECT に切り出します。そうすることによって"人"オブジェクトはシンプルになります。

***

VALUE OBJECTS の設計

私たちはどのインスタンスが VALUE OBJECT を持っているかということを気にしません。このことによって、設計をシンプルにしたり、パフォーマンスを最適にしたりしやすくなってます。これにはコピーや共有、不変性に関する選択を伴います。

二人の人が同じ名前だった場合、彼らは同じ人ではないし、交換可能でもありません。しかし、名前を表すオブジェクトの場合、名前のスペルだけが重要なので、交換可能です。"人"オブジェクト同士では"名前"オブジェクトはコピー可能です。

2つの"人"オブジェクトに対して、それぞれに"名前"インスタンスは必要ないかもしれません。同じ"名前"オブジェクトはそれらが振る舞いやアイデンティティーを変更しない間は共有出来ますが、変更されてしまったらそれらは共有できなくなります。安全に共有されるためには、完全に差し替える以外の方法では変更されない、つまり不変でなければなりません。

同じ問題はオブジェクトが他のオブジェクトから引数は返却値として受け取る際に発生します。何でも操作可能なオブジェクトが出来てしまうと、不変のルールを破って VALUE を変更できてしまいます。この問題は渡されたオブジェクトを不変にするか、コピーすることによって避けることが出来ます。

VALUE OBJECT は数が多くなる傾向があるので、パフォーマンスチューニングのための追加のオプションを作ることが重要になることがあります。家の設計ソフトウェアの例はこのヒントになっています。電機部品がそれぞれ別の VALUE OBJECT だった場合、使用される箇所の分だけそれが必要になります。しかし、全ての部品が交換可能であれば、同じ部品のカタログを指せばよくなります(FLYWEIGHT[Gamma 1995])。規模が大きいシステムではこの効果は絶大で、このような最適化は冗長なオブジェクトを作成することを防ぎます。これは ENTITY には適用できない最適化テクニックの1つの例です。

共有に対するコピーのコストは実装環境に依存します。コピーはオブジェクトの数が増えるのでシステムを邪魔しますが、共有はシステムの分散を減速させます。2つのマシンの間でコピーを渡す場合はメッセージをおくって受け取った側でも別に存在します。しかし、共有される場合は、参照だけが渡され、実体がある方に必要に応じてメッセージを送る必要が出てきます。

共有が効果的でかつ問題が発生しないようにいくつか制約をかけるのが良いでしょう。

  • データベースの領域もしくはオブジェクトの数を制約することが重要な場合
  • (集約されたサーバなどの)やりとりのオーバーヘッドが低い場合
  • 共有されたオブジェクトが厳密に不変である必要がある場合

属性やオブジェクトの不変性は言語や環境によっては実現できない場合があります。それらの特徴は設計の決定事項を伝えるのには役に立ちますが、不可欠なモノではありません。私たちがモデルに行っている区別は、現在多くのツールやプログラミング言語の実装では明らかには出来ません。自動的にアイデンティティーの操作を行うような ENTITY を宣言することはできません。しかし、そのようなことが直接サポートされてないことが区別することが役に立たないことを表しているわけではありません。もしこのルールを維持するためにそれらを制御しないといけないならば、実装に含まれることになるでしょう。それらは命名規則やドキュメント、多くの議論で補強できるでしょう。

VALUE OBJECT が不変である限り、完全な差し替える以外は変化はないので、変化の管理は簡単です。電機部品の例のように自由に不変のオブジェクトを共有できます。GCが信頼できるならば、削除はそのオブジェクトへの参照を削除するだけで可能です。VALUE OBJECT が設計上不変となる場合は、開発者はコピーを自由に行えて、共有することが出来ます。

VALUE OBJECT を定義して、それを不変とするのは一般的なルールに従うケースです。モデルに対する不要な規則がなければパフォーマンスチューニングを自由に行うことが出来ます。ルールを定義することによって、重要な振る舞いを変更しない間は、開発者は設計を微調整することが出来ます。このような設計の微調整は特定のプロジェクトで使用されている技術にしばしばとても特化します。

Example - VALUE OBJECTを使ったデータベースのチューニング

データベースは、最も低いレイヤー、つまりディスク上の物理的な位置にデータをおかれる必要があって、物理的に動き回らないと行けないのでデータを読むには時間がかかります。精巧なデータベースでは1つの物理的な操作でディスクから関連するデータを取ってこれるようになっていて、物理的にクラスタリングするように試みます。

オブジェクトが他のオブジェクトから参照されると、それらは物理的に近くには存在しないでしょう。なので、追加の物理的な操作が必要になります。同じインスタンスで参照を共有するよりも、むしろコピーすることによって、それを使用する ENTITY と同じページに多くの ENTITY の属性として使用する VALUE OBJECT を保存することができます。アクセスタイムがストレージの容量やメンテナンスのしやすさよりも重要である場合は、同じデータを複数コピーして保存する非正規化(denormalization)と呼ばれるこのテクニックはしばしば使用されます。

RDBでは、テーブルをわけてそれらに関連をつくるよりは、むしろそれを所有している ENTITY のテーブルに特定の VALUE を入れたいだけかもしれません。分散システムでは、他のサーバに VALUE OBJECT の参照を保持するとメッセージに対する反応が遅くなるでしょう。その代わり、全てのオブジェクトのコピーをもう片方のサーバに渡されるべきです。私は VALUE OBJECT で対処できるので、自由にコピーを作ることが出来ます。

VALUE OBJECT に関わる関連を設計する

初期の関連に関する議論の多くは ENTITY と VALUE OBJECT にも同じように適用されます。モデルの関連がより少なくて、より簡単であればあるほどよくなります。

しかし、ENTITY 間の関連が双方向で強固な間は、2つの VALUE OBJECT 間の双方向の関連には意味がありません。アイデンティティーがなければ、VALUE OBJECT が指しているモノと同じモノを指しているオブジェクトは無意味です。そのオブジェクトがあなたが表現したいモノのほとんどを示していたとしても、違ったモノが出てきます。そしてそれが役に立つ例は考えにくいです。VALUE OBJECT 間の双方向の関連は完全に排除するように努めてください。そのような関連が必要だと感じたならば、最初に VALUE OBJECT であるべきかを考え直してください。たぶんそれにはまだ認識していないアイデンティティーが存在します。

ENTITY と VALUE OBJECT は従来のオブジェクトモデルでは主な要素でしたが、実用主義の設計者は他の要素を使用するようになってきました。例えば SERVICE のような・・・(次の SERVICE に続く)


担当者のつぶやき

  • PofEAAのValue ObjectとJ2EEのValue Object(Transfer Object)が混じってる?

みんなの突っ込み


まとめ (議事録)