Ruby

【リファクタリング・Rubyエディションまとめ①】メソッドの抽出

今回から複数回に分けてリファクタリング・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にはこのような便利なクロージャメソッドが用意されているので、積極的に使っていこうと思いました。

今回は以上になります。次回はメソッドのインライン化について書いていこうと思います。
ここまで読んでいただきありがとうございました!

ABOUT ME
sakai
東京在住の30歳。元々は車部品メーカーで働いていてましたが、プログラミングに興味を持ちスクールに通ってエンジニアになりました。 そこからベンチャー → メガベンチャー → 個人事業主になりました。 最近は生成 AI 関連の業務を中心にやっています。 ヒカルチャンネル(Youtube)とワンピースが大好きです!