ActiveRecordのような、データベースとやり取りするライブラリをビジネスロジック内で直接使いたくない、とか思ってしまう。
なぜ?
ビジネスロジック内で直接ActiveRecordを使うとAcriveRecordに依存したコードになってしまう。
ビジネスロジック的にはデータIOをするのがActiveRecordであろうと、他のなにかであろうと別にいいはず。
であるのに、ActiveRecordをビジネスロジック内で直接使うと、データ取得はActiveRecordでなければいけなくなってしまう。
ビジネスロジックのテストコードを書こうとした時にも、テスト用DBを用意して、テーブルを用意して、前提になるデータをつっこんで、、とかなり大掛かりな事になってしまっている。
純粋にビジネスロジック部分のテストだけをやりたい場合、データ取得と保存の部分だけをモックしてやれればテストできると思うが、 ActiveRecordの場合インターフェースが汎用的過ぎて簡単にモックを用意できない。 だからテスト用DBを用意して、、となっている。 (まぁそのあたりはrailsがまるっと機能を提供してくれているからいいっちゃいい。「実際に正しくDBにデータが入るのか」もテストできるメリットもある)
どうすればいい?
データ取得用のClassを作ってそれをビジネスロジックで使うようにする。 データ取得用Class内部でActiveRecordを使ってデータ取得を実現する。
例えばこんな感じ
class UserDto def initialize() @id = nil @name = nil @age = nil end attr_accessor :id, :name, :age end class UserRepository def get_user(id:) # 何らかの方法でdbからデータを取得して返す。ここではActiveRecord user_data = User.find(id) ret_user = UserDto.new ret_user.id = user_data.id ret_user.name = user_data.name ret_user.age = user_data.age ret_user end end def SomeBusinessLogic # ユーザーデータを取得する rep = UserRepository.new user = rep.get_user(3) # 以下、userデータに対してなんかする end
こうしておけば、ビジネスロジック的にはデータ取得はActiveRecordで行われていようと、別のライブラリであろうと構わないし、DBであろうとメモリであろうとかまわない。
上記では直接newしているけど、DIにしておけばテスト時には代わりにモックをDIしてシンプルにテストできる。(DIしなくてもrubyは動的言語なので処理を上書きしてモックできたりもする。)
フレームワークとの依存度も下がるので、別のフレームワークに載せ替えることもやりやすくなるのではないか。
たぶんこの辺りの事がDDDで言うRepositoryなのかと思っている。
そこまでする必要があるか問題
とはいえ「別のフレームワークを載せ替えることがあるのか?」「ActiveRecordから別のORマッパーに変える事があるのか?」を考えるとそんなに無い気がするし、 それよりも「パッパと作ってしまうことが優先」な気もする。
Repositoryを使うとレイヤー構造が増えて複雑性が増すし、railsのドキュメントで見ない構造になるので初見ではなんのために何をしているのかよくわからないということになってしまうのかもしれない。
でもいつも頭を悩ませるのは依存問題なので、可能ならできるだけ依存しない構成にしておきたいという気持ちがある。