はじめに
本記事は、『ドメイン駆動設計(DDD)』について少し勉強し始めた筆者が学ぶ中で「わからん!」→「なるほど!」と思ったことを書いたものです。
間違っていたらそっと教えていただけると幸いです。
値オブジェクトって何なんだ
DDDを学び始めると、まず「値オブジェクト」と「エンティティ」という聞きなれない単語にぶち当たると思います。
値オブジェクトには、以下の特徴があります。
- 不変である
- 交換可能
- IDがない(属性の値が同一なら同一)
エンティティには、以下の特徴があります。
- 可変である
- 属性の値が同一でも別のオブジェクト
- IDがある
「エンティティ」は何となくわかるような気がします。
ユーザーIDで区別できるWebサービスのユーザーとか、社員番号で区別できる社員など、とあるユニークな要素で個々を区別できて、その他の属性(名前とかアイコンとか年齢とか)が変わったり全く同じ属性を持つものが他にあったりしても同一性を保証できるもの、というイメージです。
しかし、値オブジェクトがよくわかりませんでした。
「値なのに、不変ってどういうこと?」
「x=1で定義した後にx=2にするのは、値の変更じゃないの?」
「変数をreadonlyにする、みたいな? でもそれだと使いにくくない?」
値を「変える」のではなく、値を「交換する」
「値が不変である」 とは、「x=1のときに、xに2を代入してはならない」 ということではありません。
「x=1のときに、『1=2』とすることでx=2にしてはならない」 ということなのです。
「変数をreadonlyにする、みたいな? でもそれだと使いにくくない?」
一度定義した値オブジェクトは破棄する時まで一切値が変更できません!となると、当然使いにくいです。
しかし、値は不変です。1という値に「お前は今日から2だよ」と言ったって2にはなりません。1は1のまま未来永劫不変であり、2は2のまま未来永劫不変です。
しかし、値オブジェクトの特徴には 「交換可能である」 というものがあります。
つまり、値自体は不変ですが、値を変えたいものに「交換」 することはできます。
1=2にはなりませんが、xという入れ物に入っている1をポイして、代わりに2を入れる(代入する)ことでxの値の変更(x=2)を実現できるのです。
そして、値オブジェクトとして定義したオブジェクトは、この「交換」操作以外で値を変更してはなりません。
値オブジェクトはシステム固有の値を表すものです。たとえ複雑な振る舞いを持っていようと扱いは"1"や"2"と同じ「値」なのです。
たとえば、とあるシステムがステータスとして「実行中」という値を持っていたとします。
ステータスを変更したいときは、ステータス = "停止" のように、「停止」という値を代入すると思います。
ここで、「実行中」ステータスそのものを「停止」ステータスに書き換えることでステータスを変更してはならないのです。
「実行中」「停止」は値、つまり不変のものとして定義されています。だからこそ、「『実行中』だからシステム動いてるのね」、「『停止』だから今メンテしていいのね」とステータスを信用し、安心して使うことができます。
これがもし、「実行中」の意味が「停止」に変わることがあるとしたら、「『実行中』だからシステム動いて……なくない!?」ってなりますよね。
まとめ
「値が変わらない」というのは、「変数の中身が変わらない」のではなく、「値そのものの持つ意味が変わらない」ということなのかなと思いました。
「変数の中身が変わってるなら値変わってるじゃん! x=1の後にx=2したら、xは2になるじゃん!」と思っていましたが、変数と値の理解がごちゃごちゃになっていたんですね。
参考書籍
『ドメイン駆動設計入門(成瀬 允宣 著)』