LoginSignup
6
7

More than 5 years have passed since last update.

Railsアンチパターン<モデル編>④重複の複製

Last updated at Posted at 2015-06-19

DRYなコードを書くために気をつけることがつまった章。あとちょっとコードペタペタ貼りすぎて見通悪いと思ったので文章メインです。

ソリューション:モジュールに分けよう

  • 共通メソッド:そのままモジュールに書けば良い。
  • validationなど:ActiveSupport::Concernをextendしてincludedブロックで定義すれば共有できる。

一部のロジックを共通化するためにtemplateパターンを一つの参考にすると良い。include先で実装してもらいたいメソッドをモジュール自体の定義で例外を投げるようにしておくと、エラーにすぐ気付ける。Javaのインターフェースのようなものだ。

例としてあげられる、Car,Byccycleクラスでincludeされることを想定されたDrivableモジュール。

module Drivable
  extend ActiveSupport::Concern
  class TemplateError < RuntimeError; end

  included
    validates :direction, :presence => true validates :speed, :presence => true
  end

  def turn(new_direction) 
    self.direction = new_direction
  end

  def brake 
    self.speed = 0
  end

  def accelerate
    self.speed = [speed + acceleration, top_speed].min
  end

  def top_speed
    raise TemplateError
  end

  def acceleration 
    raise TemplateError
  end
end

よくある話としてはこれらの共通ロジックを親クラスに実装して継承するというものだが、モジュールの方が柔軟性がある(たとえばいろんなロジックを別々のモジュールに分けることによって一部のロジックだけを他のクラスにMix-inしたり、なんてことが考えられる)と書かれている。確かにそうかもしれない。

結論:共通ロジックをモジュール化できないか常に考える

ソリューション:プラグインを書こう

モジュールがアプリケーションレベルでの重複を防ぐ行為だとしたら、プラグインを書くことはコミュニティーレベルでの重複を防ぐ行為だと言えよう。有名なプラグインとしてはたとえば、Capistiranoなどがあるが、あそこまで巨大なものを想像しなくても良い。ほんのちょっと基底クラス(たとえば、ActiveRecord::Base)に便利メソッドを足すだけでもそれは立派なプラグインだ。
pulginについての詳しい記述はRailsガイドに任せることにする。

結論:抽象性のためにpluginを書くことを考えよう。gemとして公開できるのならなおその方がよい。

メタプログラミングの魔法

たとえば、以下のようにstatusの候補が明確に配列として定義されていてそれに対してメソッドが動的に定義されているというのは良い例だろう。

class Purchase < ActiveRecord::Base
  STATUSES = %w(in_progress submitted approved shipped received)
  #~中略~
  STATUSES.each do |status_name| 
    define_method "#{status_name}?"
      status == status_name 
    end
  end
end

結論:RubyのメタプログラミングはDRYのための非情な強力な力だ。頑張って使おう。

ただしDRY意味を勘違いしてはいけないよ、と最初に注釈がある。それはコードの行数を減らすという意味ではなく、意味の重複、振る舞いの分散を集約するという行為だということを忘れないように、という意味らしい。なんでもかんでもメタプログラミングでまとめてしまうという悪癖がたまに聞かれることがあるが、そのあたりはDRYの理解がまだ足りてないのかもしれない。

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7