やる気がストロングZERO

やる気のストロングスタイル

ビジネスロジック内でActiveRecordを直接つかいたくない

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のドキュメントで見ない構造になるので初見ではなんのために何をしているのかよくわからないということになってしまうのかもしれない。

でもいつも頭を悩ませるのは依存問題なので、可能ならできるだけ依存しない構成にしておきたいという気持ちがある。