徒然なるままに

学習メモがメインです

「ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本」を読んだ感想と学び

最近この本を読んでみたので学んだ点や感想を書きます。 www.shoeisha.co.jp

読んだきっかけ

最近は設計やアーキテクチャといった領域に興味をもっています。
設計力を向上したいため、ドメイン駆動設計を知ることで設計力の向上につながるのではないかと思い、読んでみました。

特に学びになった点/面白かった点

値オブジェクトとエンティティ

値オブジェクト エンティティ
ドメインモデルを実装したドメインオブジェクト ドメインモデルを実装したドメインオブジェクト
プリミティブ型ではなく、システム固有の値を表現するために定義されたオブジェクト。ライフサイクルは持たない ライフサイクルを持つ可変なドメインオブジェクト
性質1. 不変である 性質1. 可変である
性質2. 交換が可能である 性質2. 同じ属性であっても区別される
性質3. 等価性によって比較される 性質3. 同一性により区別される

値オブジェクト

3つの性質の詳細

  1. 不変である
    • 値の書き換えをしたいときは、新しいインスタンスを作り直す
    • 値オブジェクトクラスにchangeToxxxみたいな値を変更するメソッドは持つべきではない
  2. 交換が可能である
    • 1にも関連するが、値の交換(新しいインスタンス生成)以外で値を変更できない
  3. 等価性によって比較される
    • 値オブジェクトはシステム固有の値、あくまでも値。その属性を取り出して比較をするのではなく、値と同じように値オブジェクト同士が比較できるようにする方が自然な記述
    • 値オブジェクト同士を比較する際には値オブジェクトの属性を取り出して比較するのではなく、Equalsメソッドを利用して比較を行う

値オブジェクトを使用するモチベーション

  1. 表現力を増す
    • 例えば製品番号を扱いたい場合、stringというプリミティブ型だけだと、xxxxx-xxx-xのような特定の規則性がすぐにわからない。無口な文字列となってしまう。
    • ModelNumberクラスの定義を確認してみれば、製品番号はプロダクトコード(productCode)と枝番(branch)、そしてロット番号(lot)から構成されていることがわかる
    • 値オブジェクトはその定義により自分がどういったものであるかを主張する自己文書化を推し進める
  2. 誤った代入を防ぐ
    • 🤔筆者の理解メモ:恐らく代入時にシステム固有の型を期待し、もし違うときはエラーを返せるという点だと思う。となる前提として静的な言語か、動的な言語で型ヒントを使う必要がありそう

エンティティ

3つの性質の詳細

  1. 可変である
    • エンティティの属性を変化させたいときにはエンティティクラスのメソッドを通じて変更する
    • すべての属性を必ず可変にする必要はない。エンティティはあくまでも、必要に応じて属性を可変にすることが許可されている。可変なオブジェクトは基本的には厄介な存在なので可能な限り不変にしておくことがよい
  2. 同じ属性であっても区別される
    • エンティティ同士を区別するためには識別子(Identity)が利用される
  3. 同一性により区別される
    • 属性を変更しても変更前と変更後のオブジェクトは同一として扱われる
    • Equalsメソッドでは、idでだけで比較するイメージ

🤔筆者の理解メモ:ActiveRecordを継承したモデルのidと似てそう。エンティティがライフサイクルを持つものであること、そしてCRUDのようにDBの1レコードがライフサイクルを持っているからかもしれない。

ドメインオブジェクト定義するメリット

  • コードのドキュメント性が高まる
    • ドメインモデルのルール(仕様)が、そのままドメインオブジェクト(エンティティや値オブジェクト)に記述される、これにより、コード自体がドキュメントとして機能する
  • ドメインにおける変更をコードに伝えやすくする
    • ドメインモデルのルールが記載されているところは明白で、その修正もまた容易いもの
    • 人の営みは移るいやすく、ドメインもまた変化するものです。ソフトウェアはドメインに生きる利用者のために存在するものである以上、こうした変化への対応が頻繁に求められます。ソフトウェアが健全に成長していく未来を守るため、コードを饒舌にする努力は常に念頭に置くべき事項でしょう。

ドメインサービス

  • システムには値オブジェクトやエンティティに記述すると不自然になってしまうふるまいが存在し、それを解決するオブジェクトのこと
    • 「不自然なふるまい」に限定すること。実をいうとすべてのふるまいはドメインサービスに記述できてしまう
    • ふるまいをエンティティや値オブジェクトに定義するべきか、それともドメインサービスに定義するべきか、迷いが生じたらまずはエンティティや値オブジェクトに定義すべき。可能な限りドメインサービスは利用しないべき
  • ドメインサービスにはデータストアといったインフラストラクチャが絡まないドメインオブジェクトの操作に徹したのが本流

🤔筆者の理解メモ:アプリケーションサービスはクリーンアーキテクチャならばいちばん外側のレイヤーだろうか?

アプリケーションサービス

  • アプリケーションサービスは、ユースケースを実現するオブジェクト
    • アプリケーションサービスはあくまでもドメインオブジェクトのタスク調整に徹するべき
    • アプリケーションサービスにはドメインのルールは記述されるべきではない
    • サービスは自身のためのふるまいをもちません。したがってサービスはものごとではなく、活動や行動であることが多い
    • サービスは自身のふるまいを変化させる目的で状態を保持しません
  • アプリケーションサービスで結果を返却する必要がある場合について、「ドメインオブジェクトを返却する」「ドメインオブジェクトを返却しない」2パターン存在する。ドメインオブジェクトを公開するかしないかは大きな分岐点
    • ドメインオブジェクトを返却する場合
      • アプリケーションサービス以外のオブジェクトがドメインオブジェクトの直接のクライアントとなって自由に操作できてしまうデメリットが存在する
    • ドメインオブジェクトを返却しない場合
      • 推奨
      • ドメインオブジェクトを非公開としたとき、クライアントにはデータ転送用オブジェクト(DTO、Data Transfer Object)にデータを移し替えて返却する

🤔筆者の理解メモ:アプリケーションサービスはクリーンアーキテクチャのUse caseに似てそう

クリーンアーキテクチャへの関連

  • クリーンアーキテクチャのEntitiesは、ドメイン駆動設計のエンティティではない
    • ビジネスルールをカプセル化したオブジェクトないし、データ構造と関数のセットを指すので、どちらかといえばドメインオブジェクトに近い概念が当てはまる

おわりに

値オブジェクト、エンティティなど、名前は知ってたけど詳しく知れて、使用するメリットをしれて良かったです。
特に値オブジェクトは誤った代入を防いだり、コードの表現力が増えることでバグの防止に役立ちそうだと思いました。
今回ドメイン駆動設計に関する技術書で初めて読んでみました。ドメイン駆動設計初心者に向けて分かりやすい本だと思いました。
また、ドメイン駆動設計の雰囲気をはつかめたものの、詳細を理解できていない部分もあるました。ただ、第一歩として知れて良かったです。
ドメイン駆動設計の入門書を探している人にはおすすめです。

引き続き設計やアーキテクチャのことを学んでいきます。