DEV Community

Jon Lunsford
Jon Lunsford

Posted on

Refactoring Ruby: Extract Method

Last time, we looked at possibly one of the smallest refactorings you can do, Extract Variable. Let's take another tiny step and look at the Extract Method pattern.

Extract Method can be used when you have several expressions, a code fragment, that can be grouped together. Even if there is one expression that could be better explained with a well thought out method name, it’s still a good move.

Let’s use Extract method on the Invoice#print method:

Before:

class Invoice
  ...

  def print
    print_branding

    # print line items
    line_items.each do |line_item|
      puts "#{line_item.name}: #{line_item.price}"
    end

    # print subtotal
    puts "Subtotal: #{line_items.sum(&:price)}"
  end
end
Enter fullscreen mode Exit fullscreen mode

After:

class Invoice
  ...

  def print
    print_branding
    print_line_items
    print_subtotal
  end

  private

  def print_line_items
    line_items.each do |line_item|
      puts "#{line_item.name}: #{line_item.price}"
    end
  end

  def print_subtotal
    puts "Subtotal: #{line_items.sum(&:price)}"
  end
end
Enter fullscreen mode Exit fullscreen mode

The method before refactoring looks like:

def print
  print_branding
  # print line items
  line_items.each do |line_item|
    puts "#{line_item.name}: #{line_item.price}"
  end
  # print subtotal
  puts "Subtotal: #{line_items.sum(&:price)}"
end
Enter fullscreen mode Exit fullscreen mode

Often times, if you see comments explaining what a code fragment does, it’s a smell indicating there is a method to be extracted.

The method after refactoring looks like:

def print
  print_branding
  print_line_items
  print_subtotal
end
Enter fullscreen mode Exit fullscreen mode

Let’s walk through the steps used when applying Extract Method:

  1. Identify candidate fragments by looking for some common smells like, expressions that cluster together, comments explaining the intent, or if a good method name could add clarity.
  2. Turn those fragments into a method whose name explains the purpose of the method.

Reach for this when a method contains groups of seemingly un-related code fragments, or when better naming will make it easier for you or your coworkers to understand the intent of code.

Top comments (0)