RailsのModelからレポジトリ層とドメイン層の責務を分割する設計を考える
前提
- RailsはMVC構成になっている
- Model部分にDBを使ったデータ操作とドメインロジックの実装が入ってくるのでレポジトリ層とドメイン層の責務が両方入ってくる
- この状況だとテストをDBが依存する部分と依存しない部分に分離して実装できなくなる
- 集中的にテストを実装したいドメインロジック部分のコードにDBが絡む事になる。つまり、テストデータの生成にDBの制約が絡んでくるので、テストが重たくなったり、テストデータの生成が時に難しくなり保守性が下がる
- この状況を改善しテストを実装しやすくするために、レポジトリ層とドメイン層の責務を分割する設計を考えたい
設計一覧
どんな設計をしたら問題を解消できるのかを考えてみる
① RepositoryとEntity or Dtoを登場させてみる

説明
- DBを使ったデータ操作に関する責務をRepositoryとModelに、ドメインロジックをEntityに分割する
- DIして渡されたEntityをRepositoryが使う
- Repositoryに対して、DB関連のテストを実装する
- Entityに対して、ドメインロジックのテストを実装する
- 業務システムで、Entityに対して名前をつけるのが難しい場合はDto(data transfer object)でも良い
- テスト実装数は、
Entity > Repositoryにする
メリット
- ないかもしれん
デメリット
- ロジック操作にEntityが入ってくるので、他モデルから辿って使う場合ドメインロジックに触れにくくなる
- 例えば、
member.school.xxxみたいな使い方ができなくなる
- 例えば、
- データ操作に関する責務がModelとRepositoryに散る
- Entityの実装コストが高そう
② ModelとServiceに分離してみる

説明
- DBを使ったデータ操作に関する責務をModelに、ドメインロジックをServiceに分断する
- DIして渡されたModelをServiceが呼び出す
- Modelに対して、DB関連のテストを実装する
- Serviceに対して、ドメインロジックのテストを実装する
- テスト実装数は、
Service > Modelにする
メリット
- DBを使うデータ操作 = Model, ドメインロジック = Serviceってなるから統制しやすい
デメリット
③ Model/Domain層を作ってみる

説明
- Modelと対の関係にあるModel/Domain層を作る
- Model/DomainをModelが呼び出す
- Model/Domainは、複雑なドメインロジックを実装する責務を持つ
- 複雑度が高かったり、テストケースが膨れ上がりそうなドメインロジックにフォーカスする
- Modelに対して、DB関連のテスト+ドメインロジックのテストを実装する
- Model/Domainに対して、複雑なドメインロジックのテストを実装する
- テスト実装数は、
Model > Model/Domainになる- Model/Domainは複雑なドメインロジックのみ切り出すという制約があるのでModelの方が多くなるはず
メリット
- 他モデルから辿って使う場合ドメインロジックに触れられる