Wednesday, 12 December 2012

Ruby on Rails AntiPatterns (1)

Saleh, T.とPytel, C.著の"Rails AntiPattern"から幾つか私が参考になった箇所を少しずつ書いていきます。

AntiPattern: Fat Models

"Fat Model, Skinny Controller"という言葉は聞きますが、too fat modelはそもそもコードが読めなくなるし、Railsのパターン以前にOOPやもっと足下の理念から外れてしまいます。

クラスを分ける、モジュールを使う、callbackを使うなどORM自体で搭載されている機能は使用するという解決策を。

AntiPattern: ながーいSQLチェーン

例えば人気のある記事トップ10を引っ張って来る時にコントローラの中で、

@posts = Post.where(status: "published", order: "number_visited DESC").limit(10)

とするよりも

モデルの中で

class Post

  scope :tops, where(status: "published", order: "number_visited DESC").limit(10)

end

とすれば

@posts = Post.tops

だけですみます。これはテストを書く際にも

before(:each)
  published_posts = create(:posts)
  Post.stub(:where){published_posts}
  tops_posts = published_posts.take(10)
  published_posts.stub(:limit).with(10) {top_posts}
end

などというスタッブ・モックチェーンを書かなくても済みます。テストを書く際にメソッドチェーンはしんどい…。"Don't ask codes but tell what to do."というような言葉もありましたが、やはりTDDのプラクティスをうまく実行すればしんどいコードを書かなくても済みそうですね。

AntiPattern: 入り組んだユーザ権限処理(authorization)

authorizationの実装を下の様にするケースが多いそうです。
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
### Some methods are written here...
def can_post?
self.has_roles?(%w(admin editor contributor))
end
### Some more methods are written here...
end
view raw gistfile1.rb hosted with ❤ by GitHub

こうやっていくとだんだんとスパゲッティーになっていくので、こういう書き方は一切辞めて下のように is_guest? is_manager?  などと役割役割の名前でauthorizationを実装します。また、役割もデータベースに保存しないでコンスタントとしてハードコードしてしまいます。

class User < ActiveRecord:Base
has_many :roles
Role::TYPES.each do |role_type|
define_method "#{role_type}?" do
roles.exists?(name: role_type)
end
end
class Role
TYPES = %w(guest contributor manager admin)
validates :name, inclusion: (in: TYPES)
end
end
view raw gistfile1.rb hosted with ❤ by GitHub
多くの場合、役割をデータベーすに保存するのはメリットが少ないそうです。

No comments:

Post a Comment