Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RailsアプリとRedisの正しい付き合い方:責務を分離したモデル設計のすすめ

Railsアプリを開発していると、別のデータストアを使ったほうが簡単に解決できる問題に出会うことがあります。たとえば、サイト内の質問に答えて獲得したポイント数をもとにユーザーをランキング表示するリーダーボードを実装したい場合、Redisのソート済みセット(Sorted Sets)を活用すれば、実装の大部分をRedis側が担ってくれます。とても便利ですよね。しかし、ここで疑問が生じます。Redisとやり取りするコードは、どこに置くべきなのでしょうか?

NG例:Userモデルから直接Redisを操作する

まず思いつくのが、Userモデルに直接Redisとの通信を書く方法です。

class User < ActiveRecord::Base
  def award_points(points)
    Redis.current.zincrby("leaderboard", points, id)
  end
end

しかしこの書き方には問題があります。Userモデルが「ユーザー情報の表現」だけでなく、「Redisとの通信」や「リーダーボードの管理」という複数の責務を抱え込んでしまうのです。その結果、Userクラスは理解しづらくなり、テストも難しくなります。これはまさに避けたい状況です。

推奨パターン:責務ごとにクラスを分離する

代わりにおすすめしたいのが、Redisへのアクセスを「Redisを何のために使っているのか」を表す専用オブジェクトでラップする方法です。たとえば、Redisとの通信を担うLeaderboardクラスを作成します。このクラスはActiveRecord::Baseを継承せずapp/modelsディレクトリに配置します。

app/models/leaderboard.rb
class Leaderboard
  def award_points_to_user(user_id, points)
    Redis.current.zincrby("leaderboard", points, user_id)
  end
end
app/models/user.rb
class User < ActiveRecord::Base
  def award_points(leaderboard, points)
    leaderboard.award_points_to_user(id, points)
  end
end

どちらのクラスもapp/modelsに置けますが、この構成ならActiveRecordモデルに余計なロジックが混ざりません。LeaderboardクラスがRedisとの通信を一手に引き受けるため、Userクラスはリーダーボードの実装詳細を意識する必要がなくなります。テストのしやすさも大きく向上します。

新しい責任に対して新しいクラスを切り出すことで得られるメリットは非常に大きく、app/modelsはそうしたクラスを置くのにうってつけの場所です。外部サービスの力を借りて機能を実装しつつ、コードベースの保守性も保てます。

実際に試してみよう

あなたのプロジェクトでも、ActiveRecordモデルやコントローラー、ビューからネットワークサービスを直接呼び出している箇所はありませんか?そのコードを非ActiveRecordのデータモデルへ移動し、コードがより理解しやすく、扱いやすく、テストしやすくなるか確かめてみてください。うまくいったら、ぜひ筆者までメールで結果を教えてください!

最後に、この格言を忘れずに。

コンピュータサイエンスにおけるあらゆる問題は、間接参照をもう一段挟むことで解決できる。

— デビッド・ウィーラー(David Wheeler)

……ただし、間接参照のレイヤーが多すぎるという問題は例外だ。

— ケヴリン・ヘニー(Kevlin Henney)


  1. Windows 10でアプリをミュートする方法|音量ミキサーや設定を使った5つの手順を解説

    Windows 10には、オーディオデバイスやインストール済みのさまざまなアプリの音量を細かく制御できる優れた機能が備わっています。「Windows 10でアプリをミュートするにはどうすればいいの?」とお悩みの方は、この記事が役立ちます。ヘッドホンごとに個別の音量レベルを設定でき、接続すると自動的に切り替わる仕組みも用意されています。さらに、音量ミキサーを使えば、特定のアプリだけの音量を調整することも可能です。 Windows 10でアプリをミュートする方法 PCやノートパソコンで複数のアプリを同時に実行している場合でも、それぞれの音量を簡単に管理する方法があります。音量ミキサー(Volum

  2. SwiftUIでGameKitリーダーボードを実装する方法【6ステップ完全ガイド】

    この記事では、アプリにGameCenterのリーダーボード(Leaderboard)を実装すべき理由と、その具体的な実装方法を詳しく解説します。なぜGameCenterが再び注目されているのかスコアボードがなくてもiPhoneゲームは作れますが、リーダーボードを導入するとゲームの競争性が高まり、「世界中のプレイヤーと競い合っている」という感覚をユーザーに与えることができます。自前でバックエンドを構築・管理する代わりに、GameCenterリーダーボードを利用すれば、トラフィックに応じて無限にスケールでき、認証のためのログイン画面を丸ごと省略でき、さらにプレイヤーの画像・名前・同じゲームを遊んで