Sonntag, 28. September 2014

Express boolean parameters the Ruby way!

At first: prevent using boolean parameters in method definitions!
In Ruby land boolean parameters are outlawed. And there is a reason for. They:
  1. are not readable
  2. duplicates code or responsibility inside and outside the method
1.) Boolean parameters are no readable, because they do not express which meaning is behind true or false.
2.) And they duplicate the condition, which led to the boolean parameter inside and outside the method. The reason for having a boolean parameter often is the wish to generalize the message (method). But the wish is insidious, because it moves the arisen condition out of the method and repeats checking the boolean parameter inside the method. This fact couples the message (method) to its callers (code coupling).
A solution often is making the method private and revealing 2 public message points instead, calling the private method.
Since there are APIs expecting boolean parameters for various reasons, there is also a nice way to deal with it. For example the Ruby on Rails helper method ActionView::Helpers::FormTagHelper#check_box_tag with the method signature:
check_box_tag(name, value = "1", checked = false, 
  options = {})
expects a boolean parameter as the third.
The original code generates a HTML check box tag being unchecked:
check_box_tag("Permitted", "1", true, id: "permitted")
which is unreadable in terms of the boolean parameter. What does "true" mean? You only know, if you know the API method signature...
But it can be refactored to:
check_box_tag("Permitted", "1", :checked, id: "permitted")
which solves the readability issue, because it reveals that the HTML check box tag will be checked, since all objects except FalseClass and NilClass are true and therefore a Symbol is too.
Improving the readability by assigning expressive symbols/ strings is a solution for all APIs expecting a FalseClass boolean parameter by default, which is common practice.
Further articles of interest:

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17