リポジトリクラスのメソッド設計
データベースの検索メソッド(リポジトリとかDAOとか呼ばれる責務のもの)をどう設計するかは、選択肢が多く考えられる。それぞれの例と判断基準について検討してみよう。
例えば、このカルーセル(carousel)みたいなものを考える。現在のRoomClipのカルーセルは、その日に投稿されたフォトを10件程度選択する仕様である。
https://gyazo.com/03903fd5b334457ff954f311090a4f3c
A. ページ仕様特化型で作る
レイヤーを分けずにコントローラ一本で作り、RepositoryというよりDAOとしてSQLのテストをするためだけにメソッドを切り出す場合に、この設計が速いだろう。
code:PhotoRepository
public List<PhotoEntity> selectForTopPageCarousel();
(Pros) 全く抽象化がいらないので開発は速い。
(Cons) 当然ながらそのページ専用なので、もしちょっとだけ違う検索要件が出てきたときに、似た別のメソッドが生み出される恐れがある。
(Cons) 上記ケースでインタフェースを変えて対応しようとしても、改修範囲が大きくなってしまう。
B. ページ仕様特化型だが将来の再利用を考慮
いくつか変動がありそうなものを予測して、引数で渡せるようにしておく。
code:PhotoRepository
public List<PhotoEntity> selectForCarousel(int limit);
(Cons) 予想は外れるものだ。多少汎用的に見えて、他では使われないメソッドは可読性に害をもたらすことになる。
C. 最近注目のPhotoとして検索する
カルーセルの要件を抽象化し、ビジネス的な意味を与える。
カルーセルはそこから詳細ページへ遷移させ、アクションをユーザに喚起させるための機能なので、いわば「最近注目のPhoto」を表示するものといえる。なので、そういう名前をメソッド名に合わせ設計する。
code:PhotoRepository
public List<PhotoEntity> selectOfInterest();
(Pros) 「最近注目のPhoto」の仕様が、「本日の投稿日のフォトを降順に取得する」だけではなく、例えばカルーセルを商品化して「枠を買った人のPhotoを混ぜて優先的に表示させる」という仕様が追加されたときに、seletOfInterestメソッドの修正だけで済み、使う側には影響を与えない。
D. 投稿日で検索し、投稿日降順に並び替える
要は「投稿日で検索し、投稿日降順に並び替える」のが現状カルーセルの仕様なので、そのとおりにメソッドを設計する。
code:PhotoRepository
public List<PhotoEntity> selectByPostedAt(LocalDate targetDate, int limit, Direction sortDirection);
(Pros) 他の箇所で、投稿日を指定して取得する要件があれば、再利用できる
(Cons) カルーセルの投稿日以外の検索条件が追加されると、インタフェース(少なくともメソッド名)を変更しなくてはならず、利用側にも影響を及ぼす。別のところで再利用されちゃっていると、新しくメソッドを作り直した方がいいことも。
E. 検索条件やソート順をMapやメソッドチェーンで与えるインタフェース
検索条件が投稿日以外が入ってくることも考慮し
code:PhotoRepository
public List<PhotoEntity> selectByCondition(Map<String, Object> condition, int limit, List<SortKey> sortKeys);
(Cons) これもはやデータアクセスライブラリを直接使うのと大差ないじゃん?
考察
A→Eにいくほど、汎用性は高くなるが、データアクセスライブラリとの違いがなくなり、使う側が正しく汎用的なメソッドを使えているかの検証が必要になる。逆に特化しすぎると、再利用が効きにくく、似て非なるメソッドがたくさんできてしまう事態に繋がる。どのバランスにするかはアーキテクトの選択である。
では、Evansのレイヤリングアーキテクチャに代表されるような、ドメイン層を設ける場合、どの塩梅がいいのだろうか?
https://gyazo.com/6bf0c239f7ecc967c01405250f6b57dd
アプリケーション層とドメイン層で関心が分離されていて欲しい。Repository(のインタフェース)はドメイン層に置くので、その中での変更がアプリケーション層に影響を与えないように設計されていることが望ましい。
そうすると、上記C案がちょうどいい塩梅の設計といえるだろう。
実は前述のAとCは同じメソッドシグネチャで、引数を取らないことは変わらない。が名前にその意味が宿るので、再利用され方が変わってくる。これは命名が究極的にドメイン設計そのものであることを示している(命名のプロセスを参照)。