かとじゅんの技術日誌

技術の話をするところ

メモ:値オブジェクトの定義と差異について

「値オブジェクト」の定義について不勉強だったので「DDDの値オブジェクト」の定義とDDD以外の「値オブジェクト」との違いについて、改めて関連書籍を読み直し整理してみました。

すごい長いし細かいので他人に読ませるような記事ではなく、自分のために書いたメモです。

もし読むなら興味がある人だけで。


自分向けのメモですが、一応 この記事の前提や意図を書いておきます。

  • 「DDDの値オブジェクト」以外を否定する記事ではありません。
  • 原理主義のように書籍の理想どおり実践するべきだと主張するつもりはありません
    • 「理想に従えばよい」「理想に従うの無意味だ」と決め付けの二項対立的な思考ではなく、理想と現実の絡み合ったグレーゾーンを見極めつつ、現場で手を打つのが優れた実践者ではないでしょうか
  • 下記に紹介する、それぞれの値オブジェクトの優劣について細かく議論し、論破する・されることを目的としていません。
  • 言い訳と聞こえるかもしれませんが、読書に完璧はありません。そしてその感想にはたぶんにバイアスがかかります
    • 読書というのは同じ書籍を十人が読めば十人とも同じ解釈になるとは限らないですし、読書の解釈は「ここの部分の解釈は、これで合っていますか?」と著者に聞くことも難しいのです
    • だからといって、いい加減に読んでもよいとは考えていません。13年以上現場でDDDを実践し*1、DDD本和訳レビューや他のDDD本のレビューも関わり、著者のEvansからも直接講義を受け、他の有識者を含む日本のDDDコミュニティの方々と対話してきた経験からも考えをまとめています
    • いずれにしても、そもそも完璧な読書など存在しないという前提で、この記事を読んでいただけると嬉しいです
  • 僕の見解が唯一正しいなどと考えていませんし、DDDだけが正しい設計方法だと考えていません。ぜひ他の方の意見も参考にしてみてください。当然、私の解釈が間違っている可能性もあります。そのときは何か根拠付きで指摘していただけると有意義だと思います

5/23追記

"ドメインモデル(ドメインオブジェクト)"という表記に問題をあると…。これだけで問題になるのですね。

その記述の上の方に"ドメインモデルの考え方を反映した実装がドメインオブジェクト"と書いてますが…。

こういう重箱の隅をつつかれても不毛ですね…


前置きが長くなりましたが、値オブジェクトはよく話題になるものは、大きくわけて3つあると思うので、それをみていきましょう。

Wikipediaの値オブジェクト

さて、Wikipediaによると、Value Object(値オブジェクト)は以下のように説明されている。この定義を「Wikipediaの値オブジェクト」と呼ぶことにします。

コンピュータサイエンスでは、Value Object(値オブジェクト)は、同等性がアイデンティティに基づいていない単純なエンティティを表す小さなオブジェクトである。つまり、2つの値オブジェクトは、同じ値を持つ場合は等しく、必ずしもそれらが同一のオブジェクトである必要はない。

Value object - Wikipedia

PofEAAの値オブジェクト

Martin Fowler 著エンタープライズアプリケーションアーキテクチャパターン』(PofEAA)によると

https://www.amazon.co.jp/dp/B01B5MX2O2

IDに基づいた等価性を確保していない、MoneyやDateRangeなどのシンプルな小型オブジェクト。

さまざまな種類のオブジェクトシステムを使うとき、参照オブジェクトと値オブジェクトの相違が役立つことに気づいた。これら2つのオブジェクトではバリューオブジェクトの方が小型であり、純粋にオブジェクト指向ではない多くの言語にあるプリミティブな型に類似している。

マーチン・ファウラー. エンタープライズアプリケーションアーキテクチャパターン (Japanese Edition) (Kindle の位置No.12687-12690). Kindle 版.

「IDに基づいた等価性を確保していない小型のオブジェクト」という定義になる。

「PofEAAの値オブジェクト」にDTOは含まれるか

論争になりやすいのはDTOの概念が含まれるかという点。

Data Transfer Object - Wikipedia

DTOとは自身のデータへの格納と取り出し機能しか持たないオブジェクトのことです。JavaではSetter,Getterなどで構成されるオブジェクトで、主にデータ転送の目的で利用されます。例えばJSON形式のリクエストやレスポンスはDTOとして設計することが多いのではないでしょうか。

このWikipediaによると「PofEAAの値オブジェクト」はDTOとは異なるらしい。 理由は書いてないのでよくわかりません。

bliki: ValueObject

しかし、こちらの別の記事によると、過去に、特定のコミュニティ(J2EE?)ではDTOも「値オブジェクト」として用いられていたらしい。

実践DDD本 第6章「値オブジェクト」~振る舞いを持つ不変オブジェクト~

こちらのFowlerのブログでも、過去にJ2EEの文献がDTOをVOに分類していたが、今はみなくなった、と言及があります。

One source of terminological confusion is that around the turn of the century some J2EE literature used "value object" for Data Transfer Object. That usage has mostly disappeared by now, but you might run into it.

用語の混乱の原因の1つは、世紀の変わり目の頃、いくつかのJ2EE文献がData Transfer Objectに対して "value object "を使っていたことです。このような使い方は今ではほとんどなくなりましたが、遭遇することがあるかもしれません。

というわけで、今は「PofEAAの値オブジェクト」にDTOの概念が含まれないと判断するのが妥当でしょう。 (WikipediaのほうはDTOの概念は含まれるだろうか…判断が付かない…)

追記: 5/23

WikipediaのDTOの解説によるとDTOは含まれないそうだ。

https://twitter.com/justinto_nation/status/1528561673061117953

「IDに基づいた等価性を確保していない」以外の特徴はあるのか

上記の定義以外はどう解釈すべきか…。「18.7 マネー」あたりです。パターンではなく実装例の解説なので判断が難しい。

個人的にはこれらの特徴も定義に含めたいが、人によって意見が分かれるところかもしれません。

18.7 マネー

コンピュータはMoney(貨幣)を処理しているが、困ったことに主流のプログラミング言語はどれもMoneyを最重要データ型として扱っていない。通貨を扱う環境にとって、型がないことが問題の原因であることは明らかである。

マーチン・ファウラー. エンタープライズアプリケーションアーキテクチャパターン (Japanese Edition) (Kindle の位置No.12754-12756). Kindle 版.

「PofEAAの値オブジェクト」は対象の問題を解決する型(ドメインモデル)だ、という見方もできそうです。

Moneyの場合、Moneyオブジェクトを数字のように簡単に使えるような、算術演算が必要である。しかし、Moneyの算術演算と数字のMoney演算との間には、重要な相違点がいくつかある。最も明確なのは、異なる貨幣単位の金銭を合算しようとする場合、加算や減算では常に貨幣単位を認識する必要があることである。シンプルでよく使われる対処方法は、異なる貨幣単位の合算をエラーとして処理することである。

マーチン・ファウラー. エンタープライズアプリケーションアーキテクチャパターン (Japanese Edition) (Kindle の位置No.12772-12776). Kindle 版.

異なる貨幣単位を無視して合算できてしまうと、Money型として不変条件(invariant)が維持できない。そうなると値としての存在意義や利用価値を失うので、値オブジェクトのメソッドによって保護するような記述と読める。

これらはそう読めるだけで「PofEAAの値オブジェクト」としてそうするべきなのかわからない。

「PofEAAの値オブジェクト」に「DDDの値オブジェクト」は含まれるか

先ほど紹介したブログによると、Vaughn VernonがDDDの観点から値オブジェクトを解説しているとのこと。

Vaughn Vernon's description is probably the best in-depth discussion of value objects  from a DDD perspective. He covers how to decide between values and entities, implementation tips, and the techniques for persisting value objects.

Vaughn Vernonの記述は、おそらくDDDの観点から見た値オブジェクトの最も深い議論である。彼は、値とエンティティの間の決定方法、実装のヒント、および値オブジェクトを永続化するためのテクニックをカバーしています。

「Vaughn Vernonの記述」とは『実践ドメイン駆動設計』(Vaughn Vernon)で書かれた値オブジェクトの説明のことでしょう。つまり「DDDの値オブジェクト」のことです。「DDD観点からみた値オブジェクト」としていますが、「PofEAAの値オブジェクト」に「DDDの値オブジェクト」が含まれるかはこの文章からははっきりしない。

DDDの値オブジェクト

下のほうで例示している、複数のDDD関連書籍を改めて読み直しました。

【「DDDの値オブジェクト」はドメインオブジェクトである】は、様々なDDDの関連書籍にも明確に書かれているので、これは間違いでしょう。DDDに詳しい人にとっては当たり前のことですが。

WikipediaやPofEAAの立場からみると、ドメイン・非ドメインどちらでも使える値オブジェクトが、なぜドメイン限定になるんだ。なぜ値オブジェクトがドメインモデル(ドメインオブジェクト)だといいきるのだ、という印象を持たれるかもしれません。

まぁそれが差異です。混ぜて考えると、ゴチャゴチャになります。

(この辺りの話はDDDの汎用サブドメインのトピックも関係しますが、また今度にします…)

「DDDの値オブジェクト」の特徴

以下は、DDD関連書籍に記述されている事実から抽出した「DDDの値オブジェクト」の主な特徴です。凝集度を高めるや自己文書化など、他にも挙げだしたらキリがないのでこんなところだと思います。

  1. ドメイン内の何かしらの計測・定量化・説明のいずれかを扱う
  2. 値が等しいかどうかを、他と比較できる(値が等しいかどうかを、他と比較できる)
  3. 状態を不変(immutable)に保つこと(が望ましい)
  4. 計測値や説明が変わったときに、全体を完全に置き換えられる
  5. 関連する属性を不可欠な単位として組み合わせ、概念的な統一体を形成する
  6. 協力関係にあるその他の概念に「副作用のない関数(SIDE-EFFECT-FREE-FUNCTIONS)」を提供する
    • ここでいう関数とは、副作用がない振る舞いやメソッドのこと
    • パターン名としては”副作用のない”は強調されているが、不変(immutable)であれば振る舞いに副作用がないのは自然なこと
    • メソッド名はユビキタス言語で表現されるドメインの概念と対応付く
    • DTOのようなインターフェイスは意図していない
  7. ドメイン上の制約に基づき不変条件(invariant)を表明する(ASSERTIONS)

これらを定義どおり実践するのか。それは時と場合によるとしか言えません。書いてあることは難しい印象がありますが、実際には最近のプログラミング言語に慣れているなら、それほど苦労せず実践できると思います。

特徴の比較

いずれの値オブジェクトも以下が共通する特徴。最初からわかりきってたと思いますが…。

2) 値が等しいかどうかを、他と比較できる (IDではなく値による等価性を確保)
3) 状態を不変(immutable)に保つこと(が望ましい)

「Wikipedia及びPofEAAの値オブジェクト」はドメイン・非ドメインに関係なく使えそうです。

「DDDの値オブジェクト」はDDD特有の事情が含まれています。

明確に差異がある。

差異の解釈

差異を明確にする立場であれば、同じところは2)3)だけで他の項目は違うと言えばいい。確かに用語の定義としてはそうかもしれません。でも、そう簡単な話ではないような気がします。

そもそも、他の項目はDDD固有の考え方なのか、という疑問あるかもしれません。たとえば「必要に応じて振る舞いも作るし不変条件も表明するだろ、わざわざDDD文脈を付けるのは意味不明」という意見もあるかもしれません。WikipediaやPofEAAに明確な定義がなくても、オブジェクトならこういうやりかたをするよね、みたいな常識はあるかもしれません。

少し話しは逸れますが、そのソフトウェアの存在意義に関わる関心のことをドメインと呼ぶ*2ので、その関心とそれ以外を分けて考える、ある意味 概念に境界線を引くために使う方法論がDDDだと理解しています*3

元々ドメインという用語はEvans独自の用語ではありません*4し、DDDのようなある種の形式的な手法*5に頼らずとも、暗黙的にドメインを見出しそれを解決するモデルを作れる人は少ないですがいます*6。そういう人にはDDDの手法が回りくどく感じるかもしれません。そうであればもはやDDDのよう手法に頼る必要もないでしょう。本質的には、目的の結果が得られる、適切な方法論ならいずれでもよいでしょう。

一方で、そのように誰もが問題を解決できるのであれば、DDDはこれほどに注目されないと思います。複雑な問題では概念に境界線を引くのは思った以上に難しいものです。簡単に線引きできるなら、人類はモジュールやマイクロサービスの分割点で悩んだりしません。そういうときに、DDDがツールとして選択肢の一つになります。もちろん、DDDは銀の弾丸ではないので結果がうまく行く保証はありません。それでも我々はよりよい結果のために工夫をしながらツールも使うのではないでしょうか。

というわけで、この両方の視点で考えると「DDDの観点がないから劣っている」とか「DDDは形式的だから過剰」だとか、一概に言えません。そういう意味では、実用上、例に挙げた値オブジェクトに大きな差異があるとも言い切れないのです。

個人的には、チームで機能させられるのはどちらかというとDDDの方だと思いますが、個人の裁量が大きい仕事ではそこまで形式的な方法に頼る必然性もなかったりするので、時と場合によって思考停止せずにどの選択肢がよいか考えたほうがよさそうです。

まとめ

と、ここで終わるのはよくないですね。

少なくとも「目的が違うものを混ぜて語るな。文脈を分けろ」という指摘があるとしたら、ごもっともです。思いのほか「値オブジェクト」は多義的だったので、用語の使い方としては文脈をわきまえるしかなさそうです。

今回はこういった文脈を前置きせずに議論してしまったところがあるので、そこは配慮が足りなかったと思っています。なので、自戒を込めて今後は文脈を共有できない場では「DDDの値オブジェクト」などとプレフィクスを付けて、他と異なる概念として語るとよさそうです。

近年、DDD関連図書が増えたこともあり「DDDの値オブジェクト」の概念はよく耳にしていて半ば常識になりつつあると思いますですが、視野が狭くならないように「値オブジェクト」としては解釈が複数あることを必要に応じて啓蒙していくのがよさそうです。

長々と最後まで読んでいただき、ありがとうございました。


追加資料

DDDの値オブジェクトの定義はどうなっているか、Evans本及びDDD関連書籍から関係しそうな箇所を以下に列挙。細かすぎるので自分用のメモぐらいのつもりで書いています。読まなくてもよいと思います。

『エリック・エヴァンスのドメイン駆動設計』

著 Eric Evans(@ericevans0)

https://www.amazon.co.jp/dp/B00GRKD6XU

私は和訳版のレビューに参加しました。

補足: 大前提であるドメインと境界づけられたコンテキストについて

第1部 ドメインモデルを機能させる

すべてのソフトウェアプログラムは、それを使用するユーザの何らかの活動や関心と関係がある。ユーザがプログラムを適用するこの対象領域が、ソフトウェアのドメインである。ドメインの中には、物理的な世界を含んでいるものもある。例えば、航空会社の予約プログラムのドメインは、実際の航空機に搭乗する現実の人々を含んでいる。一方、実体を含まないドメインもある。会計プログラムのドメインは金銭と財務である。ソフトウェアのドメインは、コンピュータとほとんど関係ないのが普通だが、例外もある。ソースコード管理システムのドメインは、ソフトウェア開発そのものである。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.2). Kindle 版.

補足

ドメインとは何か。ソフトウェアプログラムを使用するユーザ(利用者や利害関係者)の何らかの活動や関心に関係あり、ユーザがプログラムを適用する対象領域がドメインである。コンピュータとほとんど関係ないが、例外もあるとしている。つまり、ソフトウェアと関係するものもある。

ソフトウェアを利用するユーザの活動や関心がドメイン。問題領域もしくは問題ドメインと呼ばれることがある。広義には開発者にとってのドメイン(言語・処理系やSQLやHTTPやWeb F/Wなど)もある、と読める。

たとえば、バージョン管理という問題ドメインに対する、GitのBlob, Tree, Commit, Tagなどは実際は解決ドメイン(後述)のモデルにあたるだろうが、日常的には問題ドメインと解決ドメインを明確に区別しないで語ることが多い。詳しくは以下のツイートを参照

かとじゅん on Twitter: "https://t.co/wMRnW9hQXB杉本さんのこの図とてもわかりやすい。ドメインモデルはソリューションのモデル。その実装はドメインオブジェクト。BC毎に個別に紐付くもの。なので、Gitのコミットモデル、Subversionのコミットモデルになる。 pic.twitter.com/KFBs6NLB3c / Twitter"

第4部 戦略的設計

第14章 モデルの整合性を維持する

境界づけられたコンテキスト(BOUNDED CONTEXT)

モデルが適用されるコンテキストを明示的に定義すること。明示的な境界は、チーム編成、そのアプリケーションに特有の部分が持つ用途、コードベースやデータベーススキーマなどの物理的な表現などの観点から設定すること。その境界内では、モデルを厳密に一貫性のあるものに保つこと。ただし、境界の外部の問題によって注意を逸らされたり、混乱させられたりするのを避けること。境界づけられたコンテキストは、特定のモデルが適用できる範囲を制限する。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.344). Kindle 版.

補足

境界づけられたコンテキストとは何か。ドメイン、ユーザの活動や関心に対応してソフトウェアで解決する領域のことである。解決ドメインと言われることもある。 通常、ソースコード上でドメインモデルやドメインオブジェクトといっているものはこちらに分類される、ソリューションとしてのモデル。


第2部 モデル駆動設計の構成要素

優れたドメインモデルを開発することは芸術である。しかし、モデルの個々の要素を実際に設計し、実装することは、比較的体系立てて行える。ドメインの設計を、ソフトウェアシステムにおけるその他の大量の関心事から分離することで、設計とモデルとのつながりが非常に明確になる。特定の区別に従ってモデル要素を定義することで、モデル要素の意味が鮮明になる。個々の要素に対して実績のあるパターンに従うことで、実際に実装できるモデルを作れるようになる。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (pp.62-63). Kindle 版.

ドメインモデルに関係するコード全部を1つの層に集中させ、ユーザインタフェース、アプリケーション、インフラストラクチャのコードから分離すること。表示や格納、アプリケーションタスク管理などの責務から解放されることで、ドメインオブジェクトはドメインモデルを表現するという責務に専念できる。これによって、モデルは十分豊かで明確になるように進化し、本質的なビジネスの知識をとらえて、それを機能させることができるようになる。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.68). Kindle 版.

第5章 ソフトウェアで表現されたモデル

その要素とは、エンティティ、値オブジェクト、サービスである。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.79). Kindle 版.

値オブジェクト(VALUE OBJECTS)

あるモデル要素について、その属性しか関心の対象とならないのであれば、その要素を値オブジェクトとして分類すること。値オブジェクトに、自分が伝える属性の意味を表現させ、関係した機能を与えること。値オブジェクトを不変なものとして扱うこと。同一性を与えず、エンティティを維持するために必要となる複雑な設計を避けること。

値オブジェクトを構成する属性は、概念的な統一体を形成すべきである

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.97). Kindle 版.

第7章 言語を使用する:応用例

配送仕様は値オブジェクトである。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.168). Kindle 版.

第10章 しなやかな設計

副作用のない関数(SIDE-EFFECT-FREE-FUNCTIONS)

プログラムロジックのうち、できる限り多くの部分を関数に置くこと。関数とは、目に見える副作用なしに結果を戻す操作である。コマンド(目に見える状態を変更することになるメソッド)は厳密に分離して、ドメインについての情報を戻さない、非常に単純な操作にすること。ある概念が、値オブジェクトの担う責務に合致する場合には、複雑なロジックをその値オブジェクトに移すことによって、副作用をさらに制御すること。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.256). Kindle 版.

副作用のない関数、中でも不変の値オブジェクトに置かれたものは、操作を安全に組み合わせることができる。関数が意図の明白なインタフェースによって示されていれば、開発者は実装の詳細を理解していなくても、その関数を使うことができる。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.256). Kindle 版.

表明(ASSERTIONS)

操作の事後条件と、クラスおよび集約の不変条件を宣言すること。プログラミング言語で表明を直接コーディングできない場合は、その代わり、自動化されたユニットテストを書くこと。プロジェクトの開発プロセスのスタイルに合う場合には、表明をドキュメンテーションや図の中に記述すること。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (p.262). Kindle 版.

感想

  • 値オブジェクトに関する記述はいろんな章に分散している…。そもそも読み方が難しい。
  • 「第2部 モデル駆動設計の構成要素」の図に、モデル駆動設計の値オブジェクトが含まれていることがわかる
  • レイヤー化アーキテクチャの部分では、ドメインモデルとドメインオブジェクトを分けて説明している。ドメインモデルの考え方を反映した実装がドメインオブジェクト。
  • ドメインモデルの構成要素は、エンティティ、値オブジェクト、サービスである
  • 値オブジェクトには「関係した機能を与えること」としている。つまり振る舞い(メソッド)を持たせる、と読むのが自然
  • 「値オブジェクトは概念的な統一体である」の、概念とはドメインモデルのことを指すと文脈から読める
  • 「第10章 しなやかな設計」では値オブジェクトが振る舞いを持つ、と示されている
    • DTOのような、単なるデータ保持役ではない、と読める
    • 図10.4は塗料(値オブジェクト)の例があり、振る舞いを提供している
  • 集約およびクラス(=ドメインオブジェクト)は不変条件(invariant)を宣言すること、と読める

『Domain-Driven Design Reference』Definitions and Pattern Summaries

著 Eric Evans

https://www.domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf

DDD本のサマリとなる本。短くてわかりやすい。しかもダウンロードできる。

Value Objects

Therefore:

When you care only about the attributes and logic of an element of the model, classify it as a value object. Make it express the meaning of the attributes it conveys and give it related functionality. Treat the value object as immutable. Make all operations Side-effect-free Functions that don't depend on any mutable state. Don't give a value object any identity and avoid the design complexities necessary to maintain entities.

モデルの要素の属性とロジックにしか興味がない場合は、値オブジェクトとして分類する。それが伝える属性の意味を表現させ、関連する機能を持たせる。値オブジェクトはイミュータブルとする。すべての操作は、変更可能な状態に依存しないSide-Effect-Free Functionsにする。値オブジェクトにアイデンティティを与えず、エンティティの維持に必要な複雑な設計を回避する。

-

Side-Effect-Free Functions

Therefore:

Place as much of the logic of the program as possible into functions, operations that return results with no observable side effects. Strictly segregate commands (methods which result in modifications to observable state) into very simple operations that do not return domain information.Further control side effects by moving complex logic into value objects when a concept fitting the responsibility presents itself.All operations of a value object should be side-effect-free functions.

プログラムのロジックをできるだけ関数に置き、観測可能な副作用を伴わない結果を返す操作とする。コマンド(観測可能な状態を変更するメソッド)は、ドメイン情報を返さない非常に単純な操作に厳密に分離する。 さらに、複雑なロジックを値オブジェクトに移行することで、副作用を抑制します。 値オブジェクトのすべての操作は、副作用のない関数でなければなりません。


『実践ドメイン駆動設計』

著 Vaughn Vernon(@vaughnvernon)

https://www.amazon.co.jp/dp/B00UX9VJGW

数多くEvans本を参照している

6.1 値の特徴

ある概念が値であるかどうかを判断するときには、その概念が以下の特性を持っているかどうかを見極める必要がある。

そのドメイン内の何かを計測したり定量化したり、あるいは説明したりする。

状態を不変に保つことができる。

関連する属性を不可欠な単位として組み合わせることで、概念的な統一体を形成する。

計測値や説明が変わったときには、全体を完全に置き換えられる。

値が等しいかどうかを、他と比較できる。

協力関係にあるその他の概念に、副作用のない振る舞い[Evans]を提供する。

ヴォーン・ヴァーノン. 実践ドメイン駆動設計 (Japanese Edition) (p.211). Kindle 版.

副作用のない振る舞い

オブジェクトの振る舞いは、副作用のない関数[Evans]として設計できる。

ヴォーン・ヴァーノン. 実践ドメイン駆動設計 (Japanese Edition) (p.218). Kindle 版.

感想

  • 値オブジェクトは説明と等価判定と不変(immutable)以外に以下の責務がある
    • 概念的な統一体を形成する
    • 振る舞いも提供する

『セキュア・バイ・デザイン』

著 Dan Bergh Johnsson(@danbjson), Daniel Deogun(@danieldeogun), Daniel Sawan

https://www.amazon.co.jp/dp/B09F697K2V

3.2 モデルをコード上で表現するための構成要素

ドメイン駆動設計において、モデルをコード上で表現する 構成要素の中で、本書が特に注目しているものは、エンティティ、値オブジェクト(value object)、集約(aggregate)になります(図3.9)。

3.2.2 値オブジェクト(value obect)

不変条件(invariant)の定義とその確認

しかしながら、これは適切な年齢の範囲ではないため、適切な制約もしくは不変条件(invariant)を年齢の値オブジェクトに持たせて、その値オブジェクトが表現することを明確にしなくてはなりません。

図3.15 値オブジェクトは不変条件を維持しなければならない。

この種の不変条件は値オブジェクトの中に定義すべきであり、他のドメイン・オブジェクトやユーティリティ・メソッドなどに定義すべきではありません。

また、ここで言う不変条件の確認は一般的に妥当性確認(validation)と呼ばれる種類の確認ではないことに注意してください。

5.1 ドメイン・プリミティブ(domain primitive)と不変条件(invariant)

5.1.1 ドメインモデルにおける最小の構成要素としてのドメイン・プリミティブ

値オブジェクトはドメインモデルにおいて重要な概念を表すものです。

ドメイン・プリミティブはドメイン駆動設計の値オブジェクトと同じようなものです。

感想

  • ドメインモデル(ドメインオブジェクト)の構成要素に、値オブジェクトが含まれる、と示されている
  • また値オブジェクトは不変条件(invariant)を維持しなければならない、とも示されている

『Patterns, Principles, and Practices of Domain-Driven Design』

著 Scott Millett, Nick Tune

Part III: Tactical Paterns: Creating Effective Domain Models

Chapter 14: Introducing the Domain Model Building Blocks

Each building block pattern is designed to have a single responsibility; it could be to represent a concept in the domain like an entity or a value object, or it could be to ensure that the concepts of the domain are kept uncluttered from lifecycle concerns like the factory or repository objects. In a way, you can view the building blocks as a ubiquitous language (UL) for developers to use as a framework for constructing rich and useful domain models.

Millett, Scott; Tune, Nick. Patterns, Principles, and Practices of Domain-Driven Design (p.310). Wiley. Kindle 版.

各ビルディングブロックのパターンは、単一の責任を持つように設計されています。それは、エンティティや値オブジェクトのようなドメインの概念を表すことであったり、ファクトリーやリポジトリオブジェクトのようなライフサイクルの懸念からドメインの概念をすっきりさせることであったりします。ある意味で、ビルディングブロックは、開発者が豊かで有用なドメインモデルを構築するためのフレームワークとして使用するユビキタス言語(UL)と捉えることができます。

感想

  • 値オブジェクトはエンティティと同様にドメインの概念を表す

『Learning Domain-Driven Design』

著 Vladik Khononov(@vladikk)

https://www.amazon.co.jp/dp/B09J2CMJZY

数多くEvans本を参照している

Chapter 6. Tackling Complex Business Logic

Domain Model

The domain model pattern is intended to cope with cases of complex business logic. Here, instead of CRUD interfaces, we deal with complicated state transitions, business rules, and invariants: rules that have to be protected at all times.

Khononov, Vlad. Learning Domain-Driven Design . O'Reilly Media. Kindle 版.

ドメインモデルパターンは、複雑なビジネスロジックのケースに対処するためのものである。ここでは、CRUDインターフェースの代わりに、複雑な状態遷移、ビジネスルール、不変条件、つまり常に保護されなければならないルールを扱います。

Implementation

A domain model is an object model of the domain that incorporates both behavior and data. DDD’s tactical patterns—aggregates, value objects, domain events, and domain services—are the building blocks of such an object model.

Khononov, Vlad. Learning Domain-Driven Design . O'Reilly Media. Kindle 版.

ドメインモデルとは、振る舞いとデータの両方を取り込んだドメインのオブジェクトモデルである。DDDの戦術的パターンである集約、値オブジェクト、ドメインイベント、ドメインサービスは、このようなオブジェクトモデルのビルディングブロックである。

感想

  • 値オブジェクトは振る舞いとデータを含むドメインモデル(ドメインオブジェクト)である、と示されている
  • また、ドメインモデルには状態遷移・ビジネスルール・不変条件(invariant)への関心も含まれるようだ

『現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 』

著 増田 亨(@masuda220)

https://www.amazon.co.jp/dp/B073GSDBGT

数多くEvans本を参照している

「送料」クラスのように、業務で使われる用語に合わせて、その用語の関心事に対応するクラスをドメインオブジェクトと呼びます。アプリケーションの対象領域(ドメイン)の関心事を記述したオブジェクトという意味です。

増田 亨. 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 (Japanese Edition) (Kindle の位置No.597-599). Kindle 版.

・業務の関心事に対応したクラス(ドメインオブジェクト)を作る

増田 亨. 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 (Japanese Edition) (Kindle の位置No.609-610). Kindle 版.

「値」を扱うための専用のクラスを作る

増田 亨. 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 (Japanese Edition) (Kindle の位置No.681). Kindle 版.

正しい数量を扱うための独自クラス(Quantityクラス)を定義する

増田 亨. 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 (Japanese Edition) (Kindle の位置No.650-651). Kindle 版.

このように計算結果も含めて、数量が1以上で100以下であるように制限したQuantityクラスを用意することで、数量計算が安全で確実になります。

増田 亨. 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 (Japanese Edition) (Kindle の位置No.662-664). Kindle 版.

値の種類ごとに専用の型を用意するとコードが安定し、コードの意図が明確になります。このように、値を扱うための専用クラスを作るやり方を値オブジェクト(ValueObject)と呼びます。業務アプリケーションでよく使う値オブジェクトを表に示します。どの値オブジェクトも、int型/String型/LocalDate型など基本データ型のインスタンス変数を1つか2つ持つだけの小さなクラスです。

増田 亨. 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 (Japanese Edition) (Kindle の位置No.686-690). Kindle 版.

このように、業務の用語をそのままクラス名やメソッド名として使うと、プログラムが業務の説明書になってきます。業務ルールに変更があったときにも、クラス名と業務の用語が一致していれば、プログラム上で変更が必要な箇所を直観的に特定できます。その業務に関係するデータとロジックを特定のクラスに集めて整理しておけば、変更の影響範囲をそのクラスに閉じ込めやすくなります。それに対して値オブジェクトを使わない場合はどうでしょうか。コードはint型やString型だらけになります。そういうソースコードは、コンピュータに対するデータ操作命令としては有効です。しかし、動かすことはできても、そのコードが業務的に何をやっているのか、プログラムを読んだだけでは理解ができません。こういうコードは業務ルールの追加や変更がやりにくくなります。また、int型やString型が扱える値の範囲は、業務で必要な値の範囲とはかけ離れています。そういう値を扱えてしまうプログラムは、思わぬバグを生みがちです。

増田 亨. 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 (Japanese Edition) (Kindle の位置No.693-702). Kindle 版.

感想

  • 業務とは対象ドメインのことを意味する(はず)
  • 例示された「送料クラス」はドメインオブジェクトである。送料クラスは値オブジェクトに該当するとは書かれていないが、値オブジェクトとして解釈するのが自然。
  • 「値」を扱うための専用のクラスを値オブジェクトとしている。例として数量クラスが登場する。
  • 説明や等価判定や不変(immutable)以外の目的があることを説明している
    • 値の種類ごとに型を作成し、コードが安定(挙動が安定するという意味?)し、コードの意図が明確になる、とのこと
    • 『セキュア・バイ・デザイン』のドメイン・プリミティブと同じように、その値が取り扱う値の範囲を保護する目的もあると説明されている(不変条件(invariant)の維持)

『ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本』

著 成瀬 允宣(@nrslib)

https://www.amazon.co.jp/dp/B082WXZVPC

数多くEvans本を参照している

私はレビュアーとして参加

1.4.1 知識を表現するパターン

値オブジェクト(第2章)はドメイン固有の概念(金銭や製造番号など)を値として表現するパターンです。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.39). Kindle 版.

1.4.3 知識を表現する、より発展的なパターン

値オブジェクトやエンティティといったドメインオブジェクトを束ねて複雑なドメインの概念を表現します。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.41). Kindle 版.

Chapter2 システム固有の値を表現する「値オブジェクト」

値オブジェクトはドメインオブジェクトの基本です

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.44). Kindle 版.

2.4 ふるまいをもった値オブジェクト

値オブジェクトで重要なことは独自のふるまいを定義できることです。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.71). Kindle 版.

値オブジェクトはデータを保持するコンテナではなく、ふるまいをもつことができるオブジェクトです。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (pp.71-72). Kindle 版.

2.5.1 表現力を増す

値オブジェクトはその定義により自分がどういったものであるかを主張する自己文書化を推し進めます。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.79). Kindle 版.

2.5.2 不正な値を存在させない

もはやシステムにとって異常な値はこのチェックにより許容されません。結果としてシステムは、ルールにしたがっていない不正な値の存在に怯える必要がなくなったのです。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.81). Kindle 版.

2.5.3 誤った代入を防ぐ

値オブジェクトを作ることで型の恩恵に与ることができれば、予測不能なエラーが潜む箇所を減らすことができます。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.85). Kindle 版.

2.5.4 ロジックの散在を防ぐ

ルールをまとめることは変更箇所をまとめることと同義です。ソフトウェアが変更を受けいれることができる柔軟さを確保するためには、このまとめる作業こそが重要なのです。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.88). Kindle 版.

2.6 まとめ

値オブジェクトはドメインの知識をコードへ落とし込むドメイン駆動設計における基本のパターンです。ドメインの概念をオブジェクトとして定義しようとするときに、まずは値オブジェクトにあてはめてみることを検討してみてください。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.89). Kindle 版.

3.1 エンティティとは

第2章『システム固有の値を表現する「値オブジェクト」』で解説した値オブジェクトもドメインモデルを実装したドメインオブジェクトです。

成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (Japanese Edition) (p.92). Kindle 版.

感想

  • この書籍でも値オブジェクトもドメインオブジェクトである、と示されている
  • また、等価判定以外に目的がある、と示されている
    • 振る舞いを持つ
    • 自己文書化
    • 不変条件の維持
    • 凝集度を高める

『良いコード/悪いコードで学ぶ設計入門保守しやすい 成長し続けるコードの書き方』

著 仙塲 大也(@MinoDriven)

https://www.amazon.co.jp/dp/B09Y1MWK9N

Evans本を参照している

私はレビュアーとして参加

値オブジェクト(ValueObject)とは、値をクラス(型)として表現する設計パターンです。アプリケーションでは金額、日付、注文数、電話番号など、さまざまな値を扱います。こうした値をクラスとして表現することで、各値それぞれのロジックを高凝集にする効果があります。たとえば金額を単なるint型のローカル変数や引数で制御していると、金額計算ロジックがあちこちに書かれて低凝集に陥ります。また、同じint型の「注文数」や「割引ポイント」が、金額用のint型変数に不注意で代入されてしまう可能性もあります。こうした事態を防ぐために、値の概念そのものをクラスとして定義します。

仙塲 大也. 良いコード/悪いコードで学ぶ設計入門保守しやすい 成長し続けるコードの書き方 (Japanese Edition) (p.77). Kindle 版.

感想

  • 値オブジェクトがドメインオブジェクトであるか明記されていないが、値オブジェクトに明らかに不変(immutable)と等価判定以外の目的がある、と示されている
    • 凝集度を高めること
    • 不変条件(invariant)を維持すること
    • 値の概念を表現する

『ドメイン駆動’設計 モデリング・実装ガイド』

著 松岡 幸一郎(@little_hand_s)

https://booth.pm/ja/items/1835632

Evans本を参照している

第6章

ドメイン層の実装

ドメインモデルを表現するもの (ドメインオブジェクト)

– エンティティ

– 値オブジェクト

– ドメインイベント

感想

  • この書籍でも値オブジェクトもドメインオブジェクトである、と示されている

『ドメイン駆動設計 サンプルコード&FAQ』

著 松岡 幸一郎(@little_hand_s)

https://little-hands.booth.pm/items/3363104

Evans本を参照している

用語の定義

表 1 重要な単語の定義

値オブジェクト

ドメインモデルを表現するオブジェクトで、同一判定を保持する値で行うもの。必ず不変になる。

感想

  • この書籍でも値オブジェクトもドメインオブジェクトである、と示されている

*1:経験年数が長ければよいのかというとそうでもないですが

*2:詳しいことは下のほうに書いてあるし、具体的にはEvans本を読んでください

*3:優劣の区分ではありませんので間違えないように

*4:歳がバレそうですが、僕が生まれる前からあります

*5:人によっては宗教では?と言われます。そういう人はスクラムも宗教という人が多い。まぁ否定はできませんが、それほど大袈裟なことではないと思っています

*6:優秀な方に多いと思います

Re: Re: ドメイン固有型(値オブジェクト含む)を再考する

kumagi.hatenablog.com

こちらの記事への反応です。

違う。値オブジェクトとはID以外で等価判定をするオブジェクトの事であって、RubyのHash、Pythonのdict、C++のstd::unordered_setすらも値によって等価判定を行うのでこれらは値オブジェクトであるがドメイン固有型ではない

RubyのHash、Pythonのdict、C++のstd::unordered_setは、アプリケーションのドメインからみるとインフラストラクチャに見えるかもしれません。

しかし、RubyのHash、Pythonのdict、C++のstd::unordered_set であっても、解決する問題領域(ドメイン)があります。なので、そのドメインにとっては、ドメイン固有型(=ドメインオブジェクト)である、と解釈しています。(ドメイン固有型の”固有”が紛らわしかったかもしれませんが…)

型クラスを既存の値型にバリデーションを足すために使う人を見たことが無いけれど(やりたいことは素直なのだから素直にif文やクラスを作るほうがまだわかる)Scalaだとよくある文化なのかしら?

単にバリデーションを追加するためだけにこういうことをするわけではないです。ドメインモデルに実装を対応づけるために定義するという意味でした。

コダックさんのツイートには返信済みでしたが、こういう解釈をしています。

追記: 5/19 17:13

ドメイン固有型(値オブジェクト含む)を再考する

Value Objectが盛り上がっているらしい。

Value Objectについて整理しよう - Software Transactional Memo

Value Objectの説明に異論がないものの、主題はValue Object Obsessionのほうですよね。

こちらも聞いてみた。

fukabori.fm

よい機会なので、よくわかっているつもりの、値オブジェクトというかドメイン固有型について再考してみよう。

続きを読む

Rustを使ってスケーラブルなプログラムを書く方法

この記事はRust Advent Calendar 2021の12/24日の記事です。

仕事ではScalaを使っていますが、趣味のプログラミングではRustで書いたものが増えました。Rustは楽しいですね。

今回は、Rustでオブジェクト指向プログラミングに関数型デザインを導入することで、スケーラブルなプログラムを書く方法(スケーラブル・プログラミング)について書きます。

続きを読む

Rustで真に安全なプログラムを書く方法

この記事はRust Advent Calendar 2021の12/8日の記事です。

Rust前提の記事として書きましたが、他の言語にも適用できる考え方なので、ほかの言語勢の方々もよければお付き合い下さい。

今回のテーマは「Rustで真に安全なプログラムを書く方法」についてです。

「真に安全なプログラム」の定義は以下とします。

  • 挙動が安定し、結果が予測可能となる
  • 正しさの基準に基づき、プログラムの間違いを検知することができる

「真に」とはドメイン知識に基づく正しさという意味です。詳しくは後述します。

それと「そもそもRustで実装されるプログラムは安全じゃないのか」という想定質問については「メモリの操作は安全。だが、それだけでは真に安全なプログラムにはならない」が答えになります。これについて興味がある方、ぜひ最後までお付き合いください。

続きを読む

「DDDで複数集約間の整合性を確保する方法 Rev2」に対する考察

どうも、かとじゅんです。

松岡さん(id:little_hands)が以下の記事を更新されたそうです。松岡さん自身が悩まれた中で検討したオプションであって、唯一の正解ではないと踏まえたうえで、率直な感想を述べたいと思います。結論からいうと、論旨は前回の記事と変わりませんが、コード例で具体的な考え方を示している点を工夫しています。

little-hands.hatenablog.com

前回の考察記事も古くなったので、最新の記事に併せて考察をまとめ直したいと思います。

blog.j5ik2o.me

続きを読む

「DDDで複数集約間の整合性を確保する方法」に対する考察

久しぶりにブログ記事を書きますか。

ということで、松岡さん(id:little_hands)のブログ記事に対する考察記事です。

この記事は古くなったので、ぜひ以下も参照してください。

blog.j5ik2o.me

little-hands.hatenablog.com

題材も松岡さんのブログ記事と同じもので考えます。

「実装方法1. ユースケースで複数集約を更新する」について考察したいと思います。

注意事項)この記事で使うトランザクションという用語は単なる一連の手続きという意味ではなく、ACID特性を持つRDBのトランザクションという意味です。

class CreateTaskUseCase1(
    private val taskRepository: TaskRepository,
    private val taskReportRepository: TaskReportRepository,
) {

  @Transactional
  fun execute(taskName: String) {
    // Taskの作成と保存
    val task = Task(taskName)
    taskRepository.insert(task)

    // TaskReportの作成と保存
    val taskReport = TaskReport(task) // 生成したTask経由でTaskReportを作成している
    taskReportRepository.insert(task)
  }

}
続きを読む