Code Signal to Noise
In my post on LibertyJS I raved about the talk “Javascript is Too Convenient” as well as a few other Functional Programming talks. A lot of them centered around the core concept that code is meant to be read more than it is written, so you should increase the signals and decrease the noise. Recently, I have been adding the “Ratio of Signal to Noise” to my mental checklist when writing and refactoring code, and how can I use function composition or curring to increase that ratio.
The first example where this became apparent to me was in refactoring some utils in a javascript module.
We had code (written for old browser compliance before babel existed) that looked a little like this:
1 | /** |
So basically some helper methods you could copy off of W3Schools to manage querystrings and cookies.
One of the first things I noticed was that the JSDoc Documentation for setCooke()
was wrong. There is no minutes parameter. I have a friend at work who calls
comments “lies”; and that applies perfectly here. The comments have gotten out
of sync with the code and are now misleading and decreasing the readability of
the code.
Not only that, in that short code blob, we have 26 lines of comments to ~ 31 lines of code, but only 23 code statements. There are more lines of comment than statements. There was a period in my development career that I would have looked at this code and thought it was great. It is well documented and commented. But this module was now too long to look at without scrolling.
This made me come to a realization:
Code Comments can be noise
Sure code comments help convey meaning, but take a look at the getCookie() method.
1 | /** |
It spends 9 lines of code comment stating the obvious, that this method gets a cookie. Developers know that cookie keys are strings and they return strings. I would much rather see a typescript def like
1 | function getCookie(name: str): str { |
That conveys the same amount of meaning in one line as the 9 lines of JS doc. Which makes the 9 lines of JS Doc noise.
The other thing I noticed is we are taking up a ton of real estate here for what are basically boilerplate functions. There is no control or coordinate functions here, these are just calculations; and not only just calcuations, boilerplate calculations that could live in any app.
I didn’t end up using typescript in the refactor of this module yet, but I did refactor this in ES6 to look something like:
1 | const getKeyFromDelimitedString = (input_string, delimiter) => key => { |
We went from 72 lines down to 20. We made use of function currying to dry up the
fact that both querytrings and cookies are strings delimited by some character, made
up of {key}={value} pairs. We named the currying function something obvious,
and made sure the names of the resulting curried functions were as good as documentation.
This refactor expressed the same functionality from 72 lines and 23 statements down to 20 lines and 11 statements. Besides the bit of ES6 specific syntax, I would argue the readibility hasnt suffered; and now the whole thing can easily fit inside a window without scrolling.
In conclusion, dont blindly apply comments everywhere, because it may be affecting the readibility of your code, if not just dilluting your code. Absolutely apply comments where needed, but make sure it is increasing your signal to noise ratio.