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:
/** * Gets a cookie from the browser * * @param String name * Cookie to get the value of * * @return String */ functiongetCookie(name) { var cookieName , cookieValue , cookieArray = document.cookie.split(';'); for (var index = 0; index < cookieArray.length; ++index) { cookieName = cookieArray[index].substr(0, cookieArray[index].indexOf('=')).trim(); cookieValue = cookieArray[index].substr(cookieArray[index].indexOf('=') + 1); if (cookieName == name) { returnunescape(cookieValue); } } }
/** * Gets the value of a variable in the query string of this URL. * * @param String variable * Name of the variable to get the value of * * @return String */ functiongetQueryVariable(variable) { var querystring = location.search.split('?')[1]; if (isDefined(querystring)) { var vars = querystring.split('&'); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('='); if (pair[0] == variable) { return isDefined(pair[1]) ? pair[1] : ''; } } }
returnnull; // Query Variable not found }
/** * Set a cookie in the browser * * @param String name * Name of the cookie to set * @param value * Value to set for the cookie * @param Number minutes * Duration in minutes until the cookie expires */ functionsetCookie(name, value) { var expirationDate , expirationString , cookieValue; // Expire cookie on 1/17/2038 (due to 32-bit integer overflow bug in some browsers) var minutes = (2147299200000 - +newDate()) / 60000; expirationDate = newDate(); expirationDate.setTime(expirationDate.getTime() + (minutes * 60 * 1000)); expirationString = '; expires=' + expirationDate.toUTCString(); cookieValue = escape(value); document.cookie = name + '=' + cookieValue + expirationString + '; path=/'; } ```
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. ```javascript /** * Gets a cookie from the browser * * @param String name * Cookie to get the value of * * @return String */ functiongetCookie(name) { ...
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 2
functiongetCookie(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:
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.