DDD本 「第5章 ソフトウェアで表現されたモデル」を読んで

はじめに

8月くらいからエリック・エヴァンスのドメイン駆動設計(通称:DDD本)の輪読会を主催しています。

ddd-community-jp.connpass.com

毎回多くの参加者の方の気付き・感想・疑問が溜まっていくのですが、自分の学び自体をあまり言語化してないと思い、書いてみます。

なお、ここで書いているのは私の個人的な意見も交えて書いています。

当日の議論メモ

DDD本 5章:ソフトウェアで表現されたモデル - HackMD

関連

現実世界では物事の関係性を考えると「N:N 」のことが多いけど、それをそのままソフトウェアに持ち込むのではなく、今ソフトウェアにとって本当に重要な関連を模索する必要がある、という意見を聞いてなるほど、と思いました。

多対多、双方向の関連を扱いやすくするために、関連を辿る方向を矯正する(≒単方向にする)のが大事なようです。

「双方向の関連があるということは、両方のオブジェクトが一緒になった時にしか理解できないということを意味している」と本書にも書かれている通り、双方向の関連は密結合になっている状態なので、実装をするにしても扱いにくいのだと読み取りました。

属性ではなく、同一性によって識別されるものをエンティティとする

本書の例では口座が出ていましたが、同日に同一口座に対する同額の預け入れが2つあっても、別々の取引として扱われます。

同姓同名の顧客(同じ属性)がいたとしても、それは別々の顧客として区別したいという欲求があるため、そういったものはエンティティとして扱うのだと解釈しました。

同一性と関連した属性は、そのエンティティと一緒に留まる

図5.5と、それに対しての説明が、あるエンティティと別のオブジェクトに分けるかどうかの判断材料として、とても良かったです。

図では顧客と販売連絡先のモデルが書かれていますが、顧客エンティティは「顧客ID」がソフトウェア上の唯一の識別子。

だけど、「電話番号」や「住所」など、現実世界で顧客の検索や突き合わせで利用されるので、これらの属性は顧客を特定する手段の1つとして使用されるので、同じエンティティに残す方が良い(同一性と関連がある属性のため)。

セールスマンという属性の場合、ある顧客の◯◯さんという言い方はするだろうけど、◯◯さんというセールスマンから、顧客を特定することはあまり無いので、同一性と関連のない属性ということで、販売連絡先という別のオブジェクトに移動し、顧客エンティティと関連を持たせるだけに留める、となる。

余談:同一性と連続性

P.87 のエンティティの節の冒頭で、 「連続性と同一性(identity)によって〜」という話が出てきます。

これを私は、「エンティティは同一性と連続性という特徴があるのだろうか」と思い込み、「同一性しかない」時っていうのはエンティティとして考えられるのか。それは概念的に変じゃないか? と思ったりしていました。

これについては、疑問をぶつけて話しているうちに、

オブジェクトの中には、主要な定義が属性によってなされないものもある。そういうオブジェクトは同一性のつながりを表現するのであり、その同一性は、時間が経っても、異なるかたちで表現されても変わらない。 -- p.89

この内容から読み取れるように、同一性と連続性は並列ではなくて、同一性があるから連続性がある、という解釈で納得ができました。

自分が読んだ時には、どうしても並列感があるように読み取れてしまったので、いろいろとおかしな考えになっていた気がします。

値オブジェクト

P.97 値オブジェクトを構成する属性は「概念的な統一体」として形成すべきである。

以下のリンクに説明が載っていました。

sundin.github.io

例として、お金は「通貨と金額」の両方をもって、初めてお金として成り立つということです。

これは逆に考えると、その概念を構成する属性以外を、値オブジェクトに含めてはいけない、とも解釈できました。

先程のお金を例に考えると、お金に必要な振る舞い(お金を足す、減らす、別の通貨レートに換算する、など)を考えたときに、「令和◯年発行」といった情報は要らないので、それはお金オブジェクトの中に含めないといった具合です。*1

サービス

時には、単純に「物」とはできないこともある。 -- p.103

この内容を読んで、私はオブジェクト=「物」。逆に物とは表現できない手続き的な物はサービスとして表現するのかと読み取ったのですが、輪読会で皆さんの意見を聞いていると、結構違うって意見が多かったです。

いろいろ聞いて自分なりに考えた結果、オブジェクトとオブジェクトの相互作用(インタラクション)を、ある特定のエンティティや値オブジェクトに収めようとすると、違和感を覚えるのであれば、サービスとして定義しよう。

それがこのサービスの節でのモチベーションなのかなぁと解釈ができました。

この節の全体的に感じたことですが、たぶん積極的に使うものではなく、「エンティティや値オブジェクトとして表現しづらかったら、こっちを使おう」くらいの消極的なニュアンスに読み取れました。

モジュール

モジュールを使う動機としては、認知のための負荷を下げることが動機となっているという内容にしっくり来ました。

モジュール間では低結合、モジュール内では高凝集であることが大事というのは、本書でも言っており、その原則を守った上で「概念の凝集した集合」としてモジュール化するのが大事だと読み取りました。

集約がそのままモジュールになるイメージなのかな。

それらのモデルが作用するコンテキストもひとつ、大きなモジュール(マイクロサービス?)として、扱えるイメージを持っています(違うのかもしれないけど)。

この節で印象的だったのが、概念の凝集した集合でモジュール化を試みることで大抵は低結合になるけど、もしそれでも技術的なトレードオフ(モジュール間での参照が増えてしまったりするなど)が発生が避けられないのであれば、「概念の明確さを選んだ方が良い」と書かれていることでした。

個人的にはたしかに、と思いましたが、このへんは、賛否両論ありそうな感じがする。

ずっと疑問だったもの

P.85の図5.4に出てくる、1つの株式に対して1つの投資しかあり得ないを表現するために、こんな図がありました。

f:id:ikuta1919:20201108130847p:plain

この株式の部分の記法がよくわからなかったのですが、「限定子」というらしいです。

Javaプログラマーに贈るUML入門 | オブジェクトの広場

DDD本を読み始めた当初から疑問だったのですが、今回ようやく解消できてよかったです。

おわりに

エンティティや値オブジェクトは、今では普通に使っていますけど、あらためて本を読み返してみて、定義とかどうやって区別するかを言葉に出そうとすると、やはりまだぎこちなさを感じるなぁと思いました。

第6章はライフサイクルの話になってくるので、そこも併せて読んでいくと、もう少し理解が進みそうな気がする。

*1:たとえば日本の小銭を個別で管理するようなアプリだったら必要かもしれません。でもその場合はエンティティになりそうな気も…