今回から複数回に分けてリファクタリング・Rubyエディションのまとめを書いていこうと思います。僕はというと、Ruby/Railsを勉強し始めて1年半ほどで、実務経験としては3ヶ月と新米エンジニアです。そんな僕が手にとったリファクタリング・Rubyエディションですが、何がよりよいかを毎日手探りをしている自分にとってまさしく欲しかった本でした。読んでいるだけではすぐに忘れてしまう…ということでブログでまとめていくことにしました。最初はメソッドの抽出です。
メソッドの抽出 (Extract Method)
コードの断片をメソッドにして、その目的を説明する名前をつける。
これを行う理由
- メソッドの粒度が細かくできていれば、他のメソッドがそのメソッドを使うことができる可能性を高める。
- メソッドの名前を見れば処理が分かるので、読む量が少なくなり可読性が向上する。
- メソッドの粒度が細かいほどオーバーライドしやすくなる。
このようなメリットを享受するためには、分かりやすい名前をつけることが重要である。
サンプル① ローカル変数なし
def print_out
outstanding = 0.0
# バナーを出力
puts "*********************************"
puts "**** Customer Owes ****"
puts "*********************************"
# 料金を計算
@orders.each do |order|
outstanding += order.amount
end
# 詳細を表示
puts "name: #{@name}"
puts "amount: #{outstanding}"
end
このようなメソッドからバナーを出力するのは簡単にできる。
def print_out
outstanding = 0.0
print_banner
# 料金を計算
@orders.each do |order|
outstanding += order.amount
end
# 詳細を表示
puts "name: #{@name}"
puts "amount: #{outstanding}"
end
def print_banner
# バナーを出力
puts "*********************************"
puts "**** Customer Owes ****"
puts "*********************************"
end
サンプル② ローカル変数の使用
def print_out
outstanding = 0.0
print_banner
# 料金を計算
@orders.each do |order|
outstanding += order.amount
end
# 詳細を表示
puts "name: #{@name}"
puts "amount: #{outstanding}"
end
def print_banner
# バナーを出力
puts "*********************************"
puts "**** Customer Owes ****"
puts "*********************************"
end
ここから詳細を表示の部分は変数が呼び出されるだけで変更されないので簡単に抽出することができる。
def print_out
outstanding = 0.0
print_banner
# 料金を計算
@orders.each do |order|
outstanding += order.amount
end
print_details outstanding
end
def print_details(outstanding)
# 詳細を表示
puts "name: #{@name}"
puts "amount: #{outstanding}"
end
def print_banner
# バナーを出力
puts "*********************************"
puts "**** Customer Owes ****"
puts "*********************************"
end
サンプル③ ローカル変数への再代入
抽出したコードが後の部分でも使われている場合、抽出したコードから変数の変更後の値を返す必要がある。
def print_out
outstanding = 0.0
print_banner
# 料金を計算
@orders.each do |order|
outstanding += order.amount
end
print_details outstanding
end
ここから料金を計算するメソッドとして抽出する。
def print_out
print_banner
outstanding = calculate_outstanding outstanding
print_details outstanding
end
def calculate_outstanding
outstanding = 0.0
@orders.each do |order|
outstanding += order.amount
end
end
さらにコレクションクロージャメソッドのinjectを使うと以下のように完結に書ける。
def calculate_outstanding
@orders.inject(0.0) { |result, order| result + order }
end
さいごに
これで、メソッドの抽出については以上なのですが、ここからはリファクタリングする前とした後で比較してみた感想を書いていきます。
def print_out
outstanding = 0.0
# バナーを出力
puts "*********************************"
puts "**** Customer Owes ****"
puts "*********************************"
# 料金を計算
@orders.each do |order|
outstanding += order.amount
end
# 詳細を表示
puts "name: #{@name}"
puts "amount: #{outstanding}"
end
def print_out
print_banner
outstading = calculate_outstanding
print_details outstanding
end
def print_details(outstanding)
# 詳細を表示
puts "name: #{@name}"
puts "amount: #{outstanding}"
end
def print_banner
# バナーを出力
puts "*********************************"
puts "**** Customer Owes ****"
puts "*********************************"
end
def calculate_outstanding
@orders.inject(0.0) { |result, order| result + order }
end
print_outメソッドはかなり読みやすくなったと思います。たった3行を読むだけで何をしているか理解することができます。ただしこれはメソッドに分かりやすい命名ができたからであり、できないのであればメソッドの抽出をするべきでないという筆者の主張も納得できました。
また、個人的にはinjectによる簡潔化がすごく勉強になりました。Rubyにはこのような便利なクロージャメソッドが用意されているので、積極的に使っていこうと思いました。
今回は以上になります。次回はメソッドのインライン化について書いていこうと思います。
ここまで読んでいただきありがとうございました!