In object-oriented programming, it's best to keep code DRY (Don't Repeat Yourself), as opposed to code that is WET (Write Every Time, Write Everything Twice, We Enjoy Typing, or Waste Everyone's Time).
If a line of code is repeatedly written or copied and pasted, it triggers a "code smell." A code smell is any characteristic in the source code of a program that possibly indicates a deeper problem. In the case of repeated code, the problem is repetition. This makes it an ideal time for refactoring.
Refactoring code is the process of simplifying existing code without modifying its functional behavior. The results in code that is easy to read, debug, and maintain. It also produces syntactic sugar, which is any aspect of the syntax of a programming language that makes programs easier to read, write, or understand.
In Ruby, one way to refactor code is using attr_accessor in a Class. Using attr_accessor eliminates the need to write the reader and writer methods as shown below:
class Dog
attr_accessor :name, :breed
@@all = []
def initialize(name, breed)
@name = name
@breed = breed
@@all << self
end
def self.all
@@all
end
#def name=(name)
#@name = name
#end
#def name
#@name
#end
#def breed=(breed)
#@breed = breed
#end
#def breed
#@breed
#end
end
Another way to refactor code and keeping it DRY is using a helper method. Using helper methods can also help to reduce errors and make it easier to debug by having the logic in one place.
In the example below, the lifters method is refactored by reusing the previous method (memberships) as a helper method. If a helper method wasn't used, there would be repetitive code as seen in the two alternative methods.
# Get a list of all memberships at a specific gym:
def memberships
Membership.all.select {|m| m.gym == self}
end
# Get a list of all the lifters that have a membership to a specific gym:
def lifters
memberships.map {|m| m.lifter}
end
# Methods with repetitive code:
def memberships
Membership.all.select {|m| m.gym == self}.map {|m| m.lifter}
end
def lifters
lifter_memberships = Membership.all.select {|m| m.gym == self}
lifter_memberships.map {|m| m.lifter}
end
Sure, refactored code requires less typing and looks cleaner. However, the first priority should be writing code that is functional. Get the code working then edit and refine for increased efficiency.
In the example below, two methods are shown to return the average lift total of all lifters. Both methods have the same functions: mapping over an array to retrieve the lift total of each lifter, adding them up, and then divide the total by the number of lifters.
As you can see, the original method has more lines of code. The second method abstracts the steps and reduces it into two single line blocks:
# Get the average lift total of all lifters:
# ORIGINAL METHOD
# def self.lifters_average
# lifts_total = @@all.map do |lifter|
# lifter.lift_total
# end
# return lifts_total.inject do |sum, element|
# sum + element
# end / lifts_total.length
# end
def self.lifters_average
lifts_total = @@all.map {|lifter| lifter.lift_total}
lifts_total.sum / lifts_total.length
end
In conclusion, the first priority when writing code is always making sure the code works, no matter how long or messy it is. From there, clean it up by refactoring to make it more efficient.
Top comments (0)