For a language written in a mere 10 days in 1995, JavaScript has come a long way. It has become the de-facto language for the web, and has even started venturing out into server-side and desktop/mobile app development. The fans call it the language for the masses. The future of software development. Purveyor of happiness. Saviour of humanity. Nothing short of the Second Coming.
The rumours of JavaScript’s superiority have been greatly exaggerated.
Alas! Having worked exclusively in JS for the last 2 years, I’m afraid I must admit that the rumours of JavaScript’s superiority have been greatly exaggerated. It is a poorly designed language and the stockpile of terribly written code that the JS community thrives on could very well be weaponised by a sentient AI in the future.
But what is so bad about JavaScript?
The Elements of a Good Language
Before we start, it’d be useful to set some sort of a benchmark for what makes a programming language good. Any measure of the goodness of a language must hark back to the three pillars of design: reliability, maintainabilty and efficiency. In that order.
Although programmers favour different languages for their subjective reasons, yet it can be argued that there does exist a core set of features which enjoy widespread consensus as the bare minimum qualities a language must have to be deemed good.
- A comprehensive standard library. Sure you can implement algorithms yourself of course, but those are likely to be slower and buggier than heavily optimised and battle tested standard library methods.
- Excellent memory management. For 99.99% of programming tasks, there’s no glory in using
malloc
and the likes. It’s good to have the power, but the language runtime must provide an automatic and optimised memory handling mechanism out of the box. - Readability and writability
- A purpose. A language is a tool. It should serve a definite purpose rather than trying to be everything to everyone. This need not constrain a language from being general, it merely stops it from being a confusing, bloated and self-contradicting mess.
How does JS fare?
Comprehensive standard library
Forget comprehensive, JavaScript has virtually no standard library. The ES6 release (that is only now starting to be used in production) introduced for/of loop, typed arrays, collections (maps and sets), and a Math module
. Vast majority of the JavaScript out there (ES4/5) cannot even do basic maths.
In the absence of any useful help from the language, developers turned towards the community and thus the NPM package manager and registry (proprietary) was born. At the time of writing, there are 679,339 packages on NPM. Impressive stat indeed, but growth for the sake of growth is the modus operandi of the cancer cell. Most NPM packages are one-liners with questionable utility. Do we really need to import a package to check if a number is positive or to pad a string with spaces on the left? Apparently a lot of JS developers do. The left-pad
package has been downloaded 865,710 times in the last 7 days and even large projects such as babel
and atom
have it listed as a dependency.
Growth for the sake of growth is the modus operandi of the cancer cell.
NPM packages do work for the most part but they require you to trust the package publisher to keep the code available and use semantic versioning to prevent breaking changes. Wishful thinking at its best. Moreover, every package you import introduces a black box into your code, and that package in turn imports other packages it depends on and soon enough you have your entire codebase littered with hundreds of blackboxes. You can trust them to be doing what it says on the tin, or you can spend months inspecting the code.
Excellent memory management
JavaScript, like Java and C#, is a garbage collected language, and well-written apps running in the browser tend to be memory efficient. JS’s memory woes rear their head when the language is shoehorned into environments it was never built for: servers, desktops and mobile.
Unlike systems programming languages like C#, JavaScript can’t run natively on a computer. It was never built to do so. You can’t run JS apps outside of the browser. So what did people do? Well they ripped out the browser engine that runs JS and shoved it down everyone’s throat. Let alone server-side apps, even background Node.js processes can easily gobble up over a 1GB of memory. Electron is even worse. It bundles the entire Chromium runtime (25.3 million lines of code) with each app, even though a web runtime already exists natively on all platform (Edge on Windows, WebKit on macOS/iOS). When you start an Electron app, the Chromium runtime is first loaded into the memory as a process, which then loads the actual application. So you’re essentially loading an OS within an OS just so you can “share codebase”. The relentless advocacy of “full-stack JavaScript” reeks of creative bankruptcy and seems to be driven by cost cutting rather than actual development benefits. Slack uses 500MB, Atom uses 200MB, Spotify 150MB, throw in a couple more “modern cross-platform app” and soon enough you are running out of memory on your 16GB machine. Takes you back to the 128KB memory, pre-multitasking era.
Readability & Writability
Writability and readability aren’t two sides of the same coin. Writability is motivated by convenience while readability is concerned with clarity. The language syntax is easy to understand and write.
Lack of type information does make JavaScript code hard to follow. But it’s philosophy of never throwing an error and making a best guess of the programmer’s intention has been a total catastrophe. See for yourself.
Number.MAX_VALUE > 0 // true
Number.MIN_VALUE < 0 // false
1 < 2 < 3 // true
3 > 2 > 1 // false
42.toFixed(2) // Syntax error
42. toFixed(2) // Syntax error
42 .toFixed(2) // "42.00"
42 . toFixed(2) // "42.00"
Number(undefined) // NaN
Number(null) // 0
Number({}) // NaN
Number([]) // 0
String(null) // "null"
String([null]) // ""
Purpose
JavaScript was originally designed as an off-the-cuff scripting language for web browsers. It was never intended for serious sytems programming. ECMA is unwilling to fix the basic, fundamental problems with JavaScript as the changes won’t be backwards compatible and they don’t want to break the internet.
In its current incarnation, JavaScript is an excellent language for prototyping. The tooling and NPM allows one to go from concept to MVP incredibly quickly. But it would be foolish to think that it can compete with the likes of C#, Python, C++ etc. for writing industrial strength software.
Conclusion
JavaScript is an inconsistent, bloated and unreasonable language that is being used for purposes it never intended to address. The language has introduced some brilliant concepts (I’m a big fan of the Promises
construct) but its overzealous users (HTML/CSS “programmers”) have cut loose a monster that would be the end of us all.
Okay maybe not. I’m desperately waiting for WebAssembly.
tl;dr
