ドメイン駆動設計　ドメインオブジェクトの使い分け

# ドメインオブジェクト

- ドメインオブジェクトの種類
    - 値オブジェクト
    - エンティティ
- ドメインオブジェクトを採用する利点
    - コードのドキュメント性を高める
        - NewJoinerのために
            - NewJoinerが新しくプロジェクトに参加する際は、業務知識や既存のコードを理解するのがとても時間がかかる。
            - ドキュメントで既存のコードを理解しようとすると、差異があった場合理解が矛盾してしまう可能性がある（ドキュメントを常に最新にすることは難しい）
            - コードが業務ロジックが詰まった設計になっていれば、例えば「ユーザーの名前は3文字以上」など、現在実装されているコードが最新のシステムの仕様になるので、差異がなく、コードを理解する、業務ロジックを理解する時間、労力が大幅に削減される
    - ドメインにおける変更をコードに伝えやすくする
        - 変更箇所見つけやすい
            - ビジネスロジックが変更され、システムを改修しないといけない場合、コードがデータ構造体だった場合、変更箇所がわかりづらく時間と労力を費やす。
            - ドメインオブジェクトとしてビジネスロジックが表現されていれば、変更箇所が明確で変更が楽になり、結果変更に強いシステムが出来上がる
- 値オブジェクトとエンティティの使い分け
    - どうやって
        - エンティティ
            - ライフサイクルがある
            - 可変である
            - 同一性で判別
        - 値オブジェクト
            - ライフサイクルがない
            - 不変である
            - 等価性で判別
        - ビジネスロジックによってその値はエンティティにもなりえて、値オブジェクトにもなりえる
            - 車から見ればタイヤは値オブジェクト：同じ種類のタイヤを識別する必要なし
            - 工場から見ればタイヤはエンティティ：同じタイヤでも個体別に識別する必要あり

## 値オブジェクト

- 不変である
    - プログラムが複雑になると
        - 複雑になっていくと値が不変であるのはとても重要になってくる
        - 可変であると途中で値が変更され、バグにつながるリスクが高まる
- 交換が可能である
    - 値の変更はOK
        - 不変である＝値の交換OK　は矛盾しているように感じるが、可変は値自体を変更しているので、ダメ。不変にしていた場合、代入操作による「交換」で行うしかなくなり、不変は保たれることになる
        
        ```kotlin
        //可変の代入（値の変更）
        var stg = "first"
        stg = "secound"
        
        //不変の代入（値の交換）
        var fullName = new FullName("goto", "kenta")
        fullName = new FullName("sato", "takashi")
        ```
        
- 等価性によって評価される（お金）
    - 値オブジェクトで比較
        - 値オブジェクトはその値オブジェクト自身が等価性で評価されるべき
        - 値オブジェクトには属性がいくつかある場合がある（例：val kana, val name）
        - 値オブジェクト同士を比較したい場合、下記のような比較を行った場合、属性で比較をしてしまうと値オブジェクトに追加で何か属性が追加された場合、他の属性が違う場合に判断ができず、おかしい比較になってしまう
        
        ```kotlin
        var fullName1 = new FullName("sato", "satoru")
        var fullName2 = new FullName("sato", "satoru")
        
        if (fullName1.firstName == fullName2.firstName) // true
        //同一人物なのかな？
        
        //変更がありageが追加される
        var fullName1 = new FullName("sato", "satoru", 23)
        var fullName2 = new FullName("sato", "satoru", 50)
        
        if (fullName1.firstName == fullName2.firstName) // true
        //本当は同姓同名の違う人
        ```
        
        - 上記のような比較はするべきではなく、値オブジェクト同士で比較する必要があり、値オブジェクト自身の等価性によって判断されるべき
        
        ```kotlin
        var fullName1 = new FullName("sato", "satoru")
        var fullName2 = new FullName("sato", "satoru")
        
        if (fullName1 == fullName2) // true
        //同一人物
        
        //変更がありageが追加される
        var fullName1 = new FullName("sato", "satoru", 23)
        var fullName2 = new FullName("sato", "satoru", 50)
        
        if (fullName1 == fullName2e) // true
        //同姓同名の違う人
        ```
        
- モチベ
    - ふるまいを記述する
    - 不正な値を存在させない
    - 誤った代入を防ぐ
    - ロジックの散在を防ぐ

## エンティティ

- 可変である
    - エンティティにはライフサイクルがある
        - そのドメインにライフサイクルがあるかがエンティティかの判断になる
        - ライフサイクルとは：時間経過と共に変化するサイクルのこと。人間が年齢という属性が変わっても同じ人間であるという考えから、人間はエンティティであると考える
        - その為、エンティティにある値は可変の可能性を秘めている（不変にすべきではある）
- 同じ属性であっても区別される
    - とは
        - 同じ属性でも区別される：人間エンティティの属性が同じであっても、同姓同名の人が存在し区別される。
        - 違う属性でも同エンティティと区別される：人間の年齢（属性）が時間の経過とともに増えていっても同じエンティティとして区別される。
- 同一性によって評価される
    - とは
        - 何で区別するか：属性で区別ができないので、エンティティを区別する為の特別な属性（id）を用いて区別される
            - 属性の違いに囚われることなく、同一性を示す識別子（id）で区別できるの