When we write code, who is it for? Is it for the machine? It is the machine that will parse and run your code. Is it for the next developer? It is that person that will spend time reading and updating the code. Is it for the business? After all, the code wouldn’t exist if it had no purpose. Obviously I think code targets all of them.
The goal is to not only make your code understandable by the machine, but also to your future self and to the business itself. This isn’t an easy thing. In this article I only aim to go past the machine-readable to reach the next developer level. To do that, let’s refactor a small fictive class…
In the previous article of the serie, I started extracting a chunk of code from a Rails’ controller to an external object. I did it in a very simple way and here is the result:
It is machine-readable. Does that mean that you can read that easily? Nope… I explain a bit what the code is doing in the other article but it isn’t enough and more importantly, do we want to maintain an up to date documentation for everything?
One of the technique I use is to abstract things in methods. As we do with variable, picking relevant name could create a narrative that’s much easier to follow.
For instance, let’s look at that validate
block, starting with this:
We don’t want to clutter the reader’s mind with the detail of the conditional. It doesn’t even fit on my screen! We could instead wrap this in a method:
This doesn’t put all the details in the validate
block. And I think it is for
the best because when I read that block, I would like to have an overview of
what’s validated, not every single implementation details.
We could apply the same for the other conditional and get this:
To make this happen, we need to define 3 private methods:
After that we end up with more lines in the file but the validate
block can
now provide a faster understanding to anyone reading the class.
It is possible to go to an higher level of narrative with something like:
You’re the judge of the abstraction level you want to give. The first refactoring
uses unless
. It is understandable by any Ruby developer. The second version could be
understood even by the business person asking for that feature.
If we continue to apply this to the perform
block, we could end up with something
like:
If you’re interested in the create_invoice_and_update_status
, you’re free to
dig deeper, but if you don’t you have the choice not to bother with the details.
By creating different narratives you can optimize for different targets. Targeting the business forces you to think in the same mindset which has great communication benefits.
You can find the gist of the code here