In his “Clean code” Uncle Bob univocally condemns boolean arguments.
Boolean arguments loudly declare that the function does more than one thing. They are confusing and should be eliminated.
To some extent, it makes all the sense
Take a look at this method:
def articles_base(only_published) return Article.published if only_published Article end
Easy to read, right? Now try to forget it, and imagine yourself being a client of that method. You can call the method in two possible ways:
Is everything clear from this perspective?
For me, it’s certainly not. A rather important from clean code perspective question arise:
- What the heck is the argument?
A followup question is: how to prevent developers from never confusing
Unfortunately, you have to remember the implementation when calling the method. But it’s not the point of extracting methods! Once extracted, the method should clearly communicate what it does!
In other words,
articles_base is an example of a leaky abstraction.
Instead, Uncle says, there should be two independent methods, even if they share some functionality. This is how those methods could look like:
def articles_base Article end def published_articles_base Article.published end
Now when you call it, there is no doubt about the meaning of an argument, because the is no argument at all.
I agree. Boolean arguments are bad… in Java.
We can do better in Ruby
We can leverage keyword arguments to dub the arguments. For example, instead of this:
we can do this:
mock_authy(success: true) mock_authy(success: false)
The upside is obvious – you know the meaning of that boolean argument.
But not only that. Aesthetically, and from the clean code standpoint, I probably like that approach over this one:
The keyword arguments way indicates that the methods have something in common. In fact, if the difference is minor (unlike the
articles_base example above), I would push it aside, to the argument, rather than create a separate method. Another thing to consider – if the number of arguments ever grew, the caller wouldn’t have to worry about their order.
As a Rubyist, clean coder, and “context is king” approach fan (that is, everything depends), my thesis is:
- there’s some space for
- there’s some space for
- there’s no space for
mock_authy(true). Use keywords argument instead.
Some understanding why to use which Martin Fowler explained in his FlagArgument post. The last paragraph advocates the idea of boolean arguments in some so-called “boolean setting method”.
Because of duck-typing (meaning no static type checking), there’s no concept of boolean argument in Ruby. There’s only hope :). No compilator stops you from calling
mock_authy(success: User.all) .
There are ways to deal with this caveat. Mostly, however, a decent test coverage and being clean in the code should suffice.
As much as I agree with Uncle Bob in many ways, I think he explains the idea of the clean code for Java and similar languages. Ruby is different. Some rules don’t entirely apply to our ecosystem.