Skip navigation.

Oleg Andreev

speaking few languages about programming, interfaces, culture, maths and nature

Automated refactoring (idea only)

Consider the following code (Ruby):

class Customer
  attr_reader :name

  def initialize(name)
    @name = name
    @rentals = []
  end

  def add_rental(arg)
    @rentals << arg
  end

  def statement
    total_amount, frequent_renter_points = 0, 0
    result = "Rental Record for #{@name}\n"
    @rentals.each do |element|
      this_amount = 0

      # determine amounts for each line
      case element.movie.price_code
      when Movie::REGULAR
        this_amount += 2
        this_amount += (element.days_rented - 2) * 1.5 if element.days_rented > 2
      when Movie::NEW_RELEASE
        this_amount += element.days_rented * 3
      when Movie::CHILDRENS
        this_amount += 1.5
        this_amount += (element.days_rented - 3) * 1.5 if element.days_rented > 3
      end

      # add frequent renter points
      frequent_renter_points += 1
      # add bonus for a two day new release rental
      frequent_renter_points += 1 if element.movie.price_code == Movie.NEW_RELEASE && element.days_rented > 1

      # show figures for this rental
      result += "\t" + element.movie.title + "\t" + this_amount.to_s + "\n"
      total_amount += this_amount
    end
    # add footer lines
    result += "Amount owed is #{total_amount.to_s}\n"
    result += "You earned #{frequent_renter_points.to_s} frequent renter points"
    result
  end
end


Many code for a single routine, huh? Let's refactor it. See one-line comments like "# show figures for this rental"? These are signs you need outsource a code to another method. So, we do it.

class Rental
  ...
  def determine_amount  
      this_amount = 0
      case movie.price_code
      when Movie::REGULAR
        this_amount += 2
        this_amount += (days_rented - 2) * 1.5 if days_rented > 2
      when Movie::NEW_RELEASE
        this_amount += days_rented * 3
      when Movie::CHILDRENS
        this_amount += 1.5
        this_amount += (days_rented - 3) * 1.5 if days_rented > 3
      end
  end

  def bonus
     if movie.price_code == Movie.NEW_RELEASE && days_rented > 1
       1
     else
       0
     end
  end

  def frequent_renter_points; 1; end
end
class Customer
  attr_reader :name

  def initialize(name)
    @name = name
    @rentals = []
  end

  def add_rental(arg)
    @rentals << arg
  end

  def statement
    total_amount, frequent_renter_points = 0, 0
    result = "Rental Record for #{@name}\n"
    @rentals.each do |element|
      this_amount = element.determine_amount
      
      frequent_renter_points += element.frequent_renter_points
      frequent_renter_points += element.bonus

      # show figures for this rental
      result += "\t" + element.movie.title + "\t" + this_amount.to_s + "\n"
      total_amount += this_amount
    end
    # add footer lines
    result += "Amount owed is #{total_amount.to_s}\n"
    result += "You earned #{frequent_renter_points.to_s} frequent renter points"
    result
  end
end


First, we have thrown away operations involving calls only to "element". Not exactly away, but into element's class - Rental. We have preserved comments over operations involving routine-local variables.

I hope to describe this more detailed to make a tool like tidy/beautifier which could cope with this somehow automatically.

ActionScript 2.0 nonsenseWhen we click a link, we teach The Machine

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies

December 2009
S M T W T F S
November 2009January 2010
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31