reona.dev

ActiveInteractionについて


最近業務でよく使うActiveInteractionという Gem について、利用する目的を落とし込みたく、この Gem を使うことでどのようなメリットがあるのかを深堀りしようと記事にすることにしました。

GitHub リポジトリにはこのように書いてあります。

ActiveInteraction manages application-specific business logic. It's an implementation of the command pattern in Ruby.

どうやらデザインパターンの一種である command パターンが使われているようです。

また、この Command パターンについては、

Command パターンでは、ある特定の動作を実行するオブジェクトを構築します。「特定」という部分が重要です。Command パターンのコマンドのインスタンスはどの社員の住所についても変更する方法を知っているわけではありません。代わりに、ある特定の社員を新しい住所に移す方法を知っています。 コマンドは何かを行う方法を知っているだけで、それを実行する対象の状態には関心がありません。

参考:Ruby によるデザインパターン

この表現がわかりやすかったです。 特定のビジネスロジックをコマンドとして作成し、通常の実行メソッドと併せて元に戻す(アンドゥ)メソッドも用意できます。ActiveRecord のマイグレーション機能は Command パターンの実装の典型例です。

話が脱線しましたが、以上の Command パターンを ActiveInteraction クラスを継承することで実現できるようです。

ActiveInteraction を使うことで得られるメリットについて考えていきます。

1. Fat Controller になることを未然に防ぐことができる

コントローラは複雑になりがちであり、コード量が段々と膨れ上がる傾向があります。

def create
  service = CreateUserService.run(user_params)
 
  if service.valid?
    head :created
  else
    render service.errors, status: :bad_request
  end
end

ActiveInteraction は、コントローラとは別にビジネスロジックを記述しておく場所を提供してくれます。 ActiveInteraction クラスを継承した Service クラスに特定のビジネスロジックを書いておけば、 コントローラでは run メソッドで呼び出すだけで済むようになるので、簡潔になりますね。(リファレンスでは app/interactions/ 配下に配置することを推奨しています)

2. ロジックを分離できるため、テストが書きやすくなる

これは 1 つ目のメリットに繋がるものではありますが、ロジックに集中したテストが書けるのでテスト単位が小さくなるのでテストが書きやすくなります。 業務ではサービスクラスのテスト、コントローラのテストを分けておりますが、2 つに分けることでテストも簡潔になりますし、どういったコードの動きを担保したいのかがよりわかりやすくなるので、コントローラと同様に保守性の高いテストコードを保つことができます。

3. より安全なコードを保つことができる

ActiveInteraction は型安全性を提供しているので、型の不一致によるバグが起こりにくく安全なコードを保つことができます。また、使用頻度は高くありませんが、ActiveModel と同様の書き方でバリデーションを定義することもできます。

class Users::SignUpService < ActiveInteraction::Base
  string :name, :email, password
 
  def execute
    user = User.save(inputs)
    unless user
      errors.add(:message,
  - 値が不正です)
    end
  end
end

上記のコードでは、inputs で受け入れる 3 つの String パラメータを定義しています。

個人的に型の恩恵が受けられるのは、バグを発生させにくいコードを書くことに繋がると思っているので非常に大きなメリットだと思っています。型の種類がなかなか豊富で柔軟にロジックが記述できそうなのもいいですね。

最後に

ActiveInteraction を使ってロジックを分離して書くことで、保守性や再利用性の高いコードが実現できそうですね。 ActiveInteraction の READMEは非常に充実しており、基本的な使い方から発展的な使い方まで書いてあるので、使い方に迷った際には迷わず README を参照でよさそうです。