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:
articles_base(true) articles_base(false)
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 true
with false
?
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:
mock_authy(true) mock_authy(false)
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:
mock_authy_success mock_authy_fail
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
mock_authy(success: true)
- there’s some space for
mock_authy_success
- 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”.
Aside
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.
Takeaway
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.
Thank you for sharing thoughts 🙂
So, what does mock_authy(success: false) do, what it returns and how result is used?
Would it be possible to show how “ruby is different” with the same example Uncle Bob used to explain this idea? I found current examples a bit confusing, the first one seems to having the same clarity problem even with keyword argument, e.g. ‘articles_base(only_published: false)’ is it “not only published, i.e. all articles” or “only not published”?
> So, what does mock_authy(success: false) do, what it returns and how result is used?
All I remember at this moment is that we had been using Authy (3rd party to handle 2FA), and in order not to make a real HTTP request, we had to mock the request. `mock_authy` was a wrapper doing just that, responding with either success or failure, based on the argument.
> Would it be possible to show how “ruby is different” with the same example Uncle Bob used to explain this idea?
I would certainly try to, but I don’t have the book at hand, and I don’t think the example is available online. Unless you have it somewhere…?
> I found current examples a bit confusing
Gotcha. Well, I’m only saying that `articles_base(only_published: false)` is a bit clearer than `articles_base(false)`. At least the author has a chance to give “a name” to that (otherwise definitely illegible) boolean value. Sometimes both ways are confusing, because the rest of the code is badly designed (the example is a real-life example from Redmine, afair)