概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Refactor your Ruby on Rails app with null object pattern
- 原文公開日: 2018/01/22
- 著者: Paweł Dąbrowsk
Rails tips: Null Objectパターンでリファクタリング(翻訳)
Null Objectパターンによるリファクタリングは、指定されたオブジェクトが存在するかどうかをチェックして、存在しなかった場合に指定の属性やメソッドのデフォルト値を返す操作に適用できます。このような操作ではif
条件が必要になることが多く、そのままではコードが少々読みづらいうえにテストも少しばかりやりにくくなります。Null Objectパターンを使うことでコードが非常にシンプルになり、テストも簡単になります。
Null Objectパターンを使うメリットをわかりやすく示すため、次のような事例を考えてみましょう。User
とPost
という2つのクラスがあり、User
クラスのオブジェクトはPost
クラス上で操作を行います。
class User < ActiveRecord::Base
has_many :posts
def latest_post_title
post = posts.order('created_at DESC').first
if post.present?
post.title
else
"No posts yet"
end
end
end
「単一責任の原則」からほど遠いコードです。ここでは以下の操作を行っています。
- 最新の
post
をフェッチする post
が存在するかどうかをチェックするpost
が存在する場合はpost
のtitle
を表示するpost
が存在しない場合は適切な情報を表示する
こんなときはNull Objectパターンの出番です。まずは新しいオブジェクトを作成しましょう。
class NoPost
def title
"No posts yet"
end
end
シンプルなロジックを備えた、ごくシンプルなRubyオブジェクトができました。それではUser
モデルで以下を行ってリファクタリングしましょう。
- クエリを別のメソッドに切り出す
NoPost
Null Objectを用いて、最新のpost
の代入を別のメソッドに切り出す- メソッドの責務を「最新の
post
のtitle
を返す」シンプルな責務に変える
User
クラスにこれらを実装すると、以下のように明快かつ読みやすいクラスに変わりました。
class User < ActiveRecord::Base
has_many :posts
def latest_post_title
lastest_post.title
end
private
def latest_post
find_latest_post || NoPost.new
end
def find_latest_post
posts.order('created_at DESC').first
end
end
User#latest_post_title
の内容が明快になり、if
条件も消滅しました。もうひとつ重要な点は、このNull Objectに適切な名前をつけて、何がしたいのかが名前からわかるようにすることです。
Railsでお困りの方にお知らせ
知りたいことがありましたら、twitter または連絡用フォームにてお気軽にお問い合わせください。
Railsパターンの電子書籍を無料でダウンロード
もっと稼ぎたい方や会社をさらに発展させたい方へ: テスティングのスキルの重要性にお気づきでしょうか?テストを正しく書き始めることが、唯一のファーストステップです。無料でダウンロードいただける私の書籍『Introduction Rails patterns』をどうぞお役立てください。