An exceedingly clean code

Update 9 Feb 2017 : _Today, it is by far my most read article, and also the most hated. I didn’t intend to publish the holy grails of clean code, there is already a whole book for it. As the title implies, the quality is pushed a little too far, and achieve it on every function is probably not so realistic. I tried to explore new ways to make the code more readable, without too much care about performance. You don’t have to agree with / like it :) Take it easy.

The article is written with ES6 for examples, but the article could be applied to other programming languages.

F*** what does this function try to…

stop, the dev who made it left last week

well, since _.zip is used, proposals and checkboxes are probably arrays.

good … arrays of what? Didn’t know _.zip, I discovered lodash with this project.

and what’s the point of line 4 condition ?

I dunno.

…

A small, very small JS function of 11 lines turns into a maintenance nightmare. The slightest bug, the slightest recovery, the slightest refactoring costs a lot of time and energy.

Knowing that any software is counted easily in thousands of lines of code …

Version 0 : do not change anything

And write automated tests. No need to be unit tests written the TDD way. Integration tests written afterwards are just as good enough to begin with. Or acceptance tests.

Without any test, it’s impossible to improve anything.

Voluntarily I do not show the unit tests of this function, the purpose of the article is to give an example of documentation by the code.

Version 1 : Check preconditions

In order to help the reader, while improving the robustness of the code, and to avoid the edge effects, let’s be sure of the input parameters before going further.

We understand what the input parameters are, but that’s hard. Have you noticed the “!” Exclamation mark ?? No ? So why not write some utility functions that makes it great:

And even better, we use an IDE plugin to get a nice alignment

There you go ! No need to comment at this stage, it’s clear as water.

We use Ruby-like code, where each word is placed in the right order to be sure we will able to read the code as in natural language. For example, here one can read in the 2nd line, excluding everything that is not strictly textual:

if proposals is not array of string return []

There you go ! Again, no need to comment until then.

Note 1 : An effective way of fighting the anxiety of “but-what-if-this-happens” (and against the debugging hours!) is to guard against any unexpected parameters by returning an empty value corresponding to expected type. This is the behavior chosen in a majority of cases for lodash / underscore. (For example, returning an empty string if the function returns a String, an empty array if the array must return an Array, etc.).

Note 2 : Even a strongly-typed language wouldn’t have solved all problems. The checks on the difference of the array sizes / on the non-empty array would still have taken place.

Comment the signature of the function. But-that-serves-nothing-if-the-function-is-well-named.

Not exactly.

The general idea is: document by example. These parameters are relocated in the overall context of the project (for example, it is understood that proposals are proposals or questions posed to the user) By the way the type of parameters of the function are now evident.

Any odd / counterintuitive thing can be reported here. With the help of the word WARNING or XXX in the comments. It’s a bit like Github: do not be afraid to abuse it. There will ALWAYS be issues, always odd thinks in your code, even if you do not like it.

Version 3 : Verticalize your code

This StackOverflow answer is a good example of verticalization.

In our case, the use of applicative programming make code greater.

Even on a very small function, think about what happens when the flow of instruction looks like this

do this do that launch this decision point decision point

This is particularly painful, isn’t it?

On the other hand, a vertical instruction flow make things much simpler.

do foo do A do B

Applied to our example, we replace

By this:

We take a breathe! No decision tree, no “unambiguous” variable (item), functions that make a unitary job …

We comments again by example, line by line:

Final Code

Small synthesis