Project Ramon

A learning journey from a Ruby noob perspective

Refactoring Ruby: Remove Named Parameter

remove_named_parameter_header_img

Hello and happy Friday!

If you remember the last refactoring pattern we reviewed, Introduce Named Parameter, we covered how placing our method parameters in a hash provides us a benefit of being able to name (with our hash’s key) our long and/or complicated parameters, providing better readability for ourselves and other code readers. Today’s refactor pattern is the inverse of Introduce Named Parameter.

Remove Named Parameters

There is a definite fluency that is added when introducing named parameters to our calling code. But named parameters come with a price in that they add complexity to the receiving method. Its impossible to tell exactly the contents of the hash without investigating the method body or calling code.

Many times, this complexity is worth the increased readability on the calling side. But there are other times when this added complexity isn’t warranted. Some reasons include some of the required parameters being removed, performing Extract Method or Extract Class, taking only one of the parameters to those refactors. Basically, whenever it is no longer necessary to determine parameter meaning via the hash key names, we would be best served to remove our named parameters.

Lets take a look at the mechanics of this pattern:

  • Replace the named parameter (hash[:key]) from our parameter hash with a normal parameter in the list. Remember to keep your newly unnamed parameter ahead of your hash if you have other named parameters you’d like to keep. This allows you to omit the curly braces { }, thanks to some Ruby sugar.
  • Replace the named parameter in the calling code with a normal parameter
  • Test

Example

Lets take a look at the code example from last post.

before:

class MrPotatoHead
  def initialize(hash={})
    @hands = hash[:hands]
    @eyes = hash[:eyes]
    @nose = hash[:nose]
    @mouth = hash[:mouth]
    @hair = hash[:hair]
    @hat = hash[:hat]
    @shoes = hash[:shoes]
    @age = hash[:age_in_days]
  end
end

This is how we ended in our last post, we took a very long list of ordered parameters in our initialize method’s parameter list and replaced all of those with a simple hash={}. Then we assigned the hash values to instance variables. This gave us a bonus of not not needing to remember the order of the parameters as we would in the example shown below.

class MrPotatoHead
  attr_reader :hands, :eyes, :nose, :mouth, :hair, :hat, :shoes, :age_in_days
 
  def initialize(hands, eyes, nose, mouth, hair, hat, shoes, age_in_days)
    @hands = hands
    @eyes = eyes
    @nose = nose
    @mouth = mouth
    @hair = hair
    @hat = hat
    @shoes = shoes
    @age = age_in_days
  end
end

Now lets assume that we’ve received orders from our higher ups that Mr potato head will always come with eyes, hands and a mouth. But the other parameters will still be deemed optional. We would want to probably remove those parameters (the ones now deemed as mandatory for this object) from our hash.

Lets make an attempt at this:

after (a):

class MrPotatoHead
  attr_reader :eyes, :hands, :mouth

  def initialize(eyes=Eye.new, hands=Hand.new, mouth=Mouth.new, hash={})
    @eyes = eyes
    @hands = hands
    @mouth = mouth
    @hat = hash[:hat]
    @nose = hash[:nose]
  end
end

In the code snippet above, we’ve extracted the mandatory parameters from our hash and we’re now able to make sure we have the attributes we need, as well as add any number of additional parameters through our hash at the end, in this case we’ve only chosen to add two, hash[:hat] and hash[:nose].

after (b):

class MrPotatoHead
  attr_reader :eyes, :hands, :mouth
  
  def initialize(eyes=Eye.new, hands=Hand.new, mouth=Mouth.new, hash={})
    @eyes = eyes
    @hands = hands
    @mouth = mouth
    @flip_flops = hash[:flip_flops]
    @ukulele = hash[:ukulele]
  end
end

Conclusion

The way I understand this so far, besides the benefits of removing the additional complexity of named parameters, is that we now have two types of parameters. The first type eyes, hands and mouth are ordered and required. The second type of parameters are optional, and we can actually add in new objects like we see in the last two variable assignments in the example above for @flip_flops and @ukulele.

In the future, I’m thinking of pausing on these refactor patterns and start writing about design patterns. Let me know what you think of this in the comments!

Stay tuned…

Advertisements

Categories: Ruby

Tags: ,

2 replies

  1. The benefit of the last example where you’re passing in Hands, Mouth and Eyes is that you’re now using Dependency Injection to manage your collaborators – this will make your testing easier as you can inject test doubles (for each of Hands, Mouths and Eyes) into your MrPotatoHead class rather than having to go through all the setup involved in instantiating those objects otherwise.

  2. Hello Ralphos,

    Looking forward to saving time in my unit testing in this fashion from now on!

    Thanks for your comment 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s