More on “npm” leftpad
Win-Vector Blog 2016-03-24
Being interested in code quality and software engineering practice I have been following (with some relish) the current Javascript tempest in a teapot: “NPM & left-pad: Have We Forgotten How To Program?” (see also here for more discussion).
Image: Ben Halpern @ThePracticalDevWhat happened is:
- A corporate site called NPM decided to remove control of a project called “Kik” from its author and give it to a company that claimed to own the trademark on “Kik.” This isn’t actually how trademark law works or we would see the Coca-Cola Company successfully saying we can’t call certain types of coal “coke” (though it is the sort of world the United States’s “Digital Millennium Copyright Act” assumes).
- The author of “Kik” decided since he obviously never had true control of the distribution of his modules distributed through NPM he would attempt to remove them (see here). This is the type of issue you worry about when you think about freedoms instead of mere discounts. We are thinking more about at this as we had to recently “re-sign” an arbitrary altered version of Apple’s software license just to run “git status” on our own code.
- Tons of code broke because it is currently more stylish to include dependencies than to write code.
- Egg is on a lot of faces when it is revealed one of the modules that is so critical to include is something called “leftpad.”
- NPM forcibly re-published some modules to try and mitigate the damage.
Everybody is rightly sick of this issue, but let’s pile on and look at the infamous leftpad.
Here is leftpad (copied from the source):
module.exports = leftpad;function leftpad (str, len, ch) { str = String(str); var i = -1; if (!ch && ch !== 0) ch = ' '; len = len - str.length; while (++i < len) { str = ch + str; } return str;}
It is going to be a bit long (as it is library code and has to check for more exceptional cases). It appears to be dealing with issues of ch
being missing or masquerading as an integer.
But let me show you how padding the word “string” to have total length 10 (by adding 4 zeros) is done in a couple of other languages (one of the reasons authors in these languages would never consider importing something for this purpose).
- Python:
v = 'string''0'*(10-len(v))+v
- R:
v <- 'string'paste(paste(rep('0',max(0,10-nchar(v))),collapse=''), v,sep='')
And the Javascript has the classic bit of code that costs you the job during a Google style interview:
while (++i < len) { str = ch + str; }
Now I don’t code in Javascript, and I know this doesn’t matter for small len
: but this snippet looks bad to the educated eye. Unless there is some clever optimization we don’t know about (such as a compiler visibility analysis replacing the commonly immutable Javascript string with some sort of string builder) the code is inefficient in that it likely takes Omega(len^2)
time (often colloquially mis-called O(len^2)
time). Now there are some cases where what looks like inefficient code is replaced by efficient code (due to a clever escape analysis, the R language supplies such facilities as we discuss here). But I doubt that is the case here. If it is the case (the code performs differently than it superficially appears), that is important to point out in comments or documentation.
We assume Javascript authors use dependencies so much because they are tired from the automatic semi-colon insertion wars (I won’t even link to that).
It has been our experience that you can find defenders for any bad code under the “its all subjective” rubric. However it is not all subjective, there are actually a few principles of code and development quality which you ignore at your own peril.