Kattsu Sandbox

ドメイン駆動設計に入門した

投稿日:

はじめに

『ドメイン駆動設計入門』という本のメモ。

ドメイン駆動設計とは

ドメインとはシステムが扱う領域のことであり、会計システムであれば会計、物流システムであれば物流といったものを指す。ドメイン駆動設計とは、このようなドメインの概念を変更にも強く長期的に運用しやすくする設計手法である。ドメインの概念をシステム設計に取り入れるというのは当たり前のことだが、その当たり前のことを当たり前にやろうというのがドメイン駆動設計である。

そもそもシステムとは現実にある課題を解決するものだが、この現実はそのままコードで表現できるほど単純ではない。例えば、物流システムの輸送手段であるトラックひとつ取っても、現実では単純に輸送手段というくくり以外に、エンジンであったり車両価格であったり様々な事象が絡まり合う。ここでシステムを表現する上で必要のない事項にまで時間をかける意味はないので、開発者は無意識のうちに「現実の抽象化」を行い、システムがなるべくシンプルに動くようにする。

ただし、抽象化はなかなか難しい作業であり、そもそもドメイン自体の専門家ではない開発者はそのために誤った抽象化を行ってしまうこともあり得る。そこで、そのようなドメインの抽象化をなるべく誰でも行え、ドメインの変化を含む長期的な運用にも耐えられるようにしたのがドメイン駆動設計である。

ドメイン駆動設計のパターン

ドメイン駆動設計には代表的なパターンがあり、これらのパターンを覚えればドメインの抽象化がしやすくなる。

  • 知識を表現するパターン
    • 値オブジェクト
    • エンティティ
    • ドメインサービス
  • アプリケーションを実現するためのパターン
    • リポジトリ
    • アプリケーションサービス
    • ファクトリ
  • 知識を表現する、より発展的なパターン
    • 集約
    • 仕様

アプリケーションを実現するためのパターンが、知識を表現するためのパターンを利用するような形になる。

値オブジェクト

単なる文字列や数値のような値としての性質と、オブジェクトの表現力を兼ね備えたドメインオブジェクト。値なので次のような性質を持たせる。

  • 不変。内容をメソッドによって変更するようなメソッドを書かない。代入によってのみ交換を許す
  • 等価性によって比較される。オブジェクトのプロパティによって一致させるのではなく、等価演算子のオーバーライドにより隠蔽するのがベター

一方でオブジェクトとして次のような効果を狙う。

  • それがなんであるかをプロパティ、メソッドを通して表現されるようにする
  • 不正な値を存在させないようにオブジェクトにルールを追加する
  • ロジックの散在を防ぐ

値オブジェクトには、例えば UserName などが挙げられる。

エンティティ

ライフサイクルを持ち属性が変化しても同一性を保つオブジェクト。値オブジェクトは値そのものなのでそれが変わったら同一性はなくなるが、エンティティは同一性を保つ。例えば、User などが挙げられる。 エンティティは次のような性質を持つ。

  • 可変。代入により変更するのではなく、メソッドによって属性を変更する
  • 同じ属性であっても区別される。同姓同名での別人なのと同じ
  • ID など同一性を表す属性によって比較する

ドメインサービス

値オブジェクトやエンティティに定義すると不自然な振る舞いをまとめ、これらドメインオブジェクトに振る舞いを提供するもの。インスタンス特有の状態をもたないオブジェクト。 あまりなんでもドメインサービスに書きすぎるとエンティティの表現力が減り理解しづらいコードになる(ドメインモデル貧血症)ため注意。

リポジトリ

データの永続化や再構築といったデータストアにまつわる操作をまとめる場所。 処理の意図が明確になり、データストアの差し替えも実現しやすくなる。 ドメインを表現するものではないのでドメインオブジェクトではない。 現代的なフレームワークでは、データストア固有の接続などにまつわる操作はアプリケーションの操作とは切り離されたファイルで定義するようになっているので、自然とリポジトリパターンができているものが多いと思う。

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

ドメインサービスと同じくドメインオブジェクトにふるまいを提供するものだが、ドメイン固有のルールのようなドメインを成り立たせるふるまいではなく、ドメインをふるまわせることでアプリケーションを成り立たせるようなふるまいを記述する。 例えば、ユーザーの重複を許さないというふるまいはドメイン自体を成り立たせるものだが、ユーザーの登録・削除・更新などの処理はアプリケーションを成り立たせるふるまいである。 サービスはクライアントにふるまいを提供するものであって状態は持たない。正確には状態によって自身のふるまいを変化させるような状態を持たないこと。

ファクトリ

オブジェクを生成する責務をもったオブジェクト。 オブジェクトの生成は複雑になることも多いため、モデルを表現するオブジェクトそのものに記述するより、オブジェクト生成そのものを別のオブジェクトとする方がコードの意図が明確になる場合がある。例えば採番処理などが挙げられる。生成処理をカプセル化する狙いがある。

感想

ドメイン駆動設計という設計手法は名前だけは知ってて、ドメインを中心に設計するって当たり前では?と思っていたが、冒頭で当たり前のことを当たり前にやるためのものだと説明があって納得した。ソフトウェアは現実(ドメイン)を抽象化するものなので、それをうまく実現するにはどうしたらよいかということで、これまで無意識のうちに行っていた点に焦点が当たり学びがあった。 DB 設計ではオブジェクトを中心に ER 図を考えていくのは当たり前のことだが、ソフトウェア設計も同じでドメインオブジェクトを中心に考え、ドメインとは本質的でない処理(例えばデータストアへの登録自体のコード)を抽象化・カプセル化したり、ドメインオブジェクトを表現するふるまいとそれらを操作するふるまいを分けて記述するのは意識してやっていきたい。

書いている人

大阪でソフトウェアエンジニアとして働いています。

© 2020 Kattsu Sandbox