Explaining the Perplexing JavaScript Landscape - Why it's so confusing

This is the first part of the Explaining the Perplexing JavaScript Landscape series, which aims to clarify and explain different tools, libraries and frameworks, and how they all fit together.

Before we look back at how JavaScript has evolved, let's try to understand why JavaScript is so much like the wild west today, to bring some comfort to those feeling lost.

We've breaked it down into three sections:

  • Rapid Introduction of New Specifications - JavaScript is changing at a pace no other languages have seen before
  • Paradox of Choice - too many libraries doing the same thing
  • Propensity for Jumping on Bandwagons - many developers throw out existing (tested) frameworks and adopt the new framework without understanding their merits

Rapid Introduction of New Specifications

JavaScript (NodeJS, specifically) is changing at a rapid rate. But is it as rapid as other languages? Let's take a look.

The Rise of NodeJS

HTML5 is the fifth (duh!) and current implementation of the HTML markup language (yes, we know we're comparing a programming language with a markup language). Since HTML was initially released in 1993, in its 23 years of existence, there has only been 5 versions - 1993 (v1), 1995 (v2), 1997 (v3, v4), 2014 (v5).

Python, a general-purpose programming language, was released in 1991 and has had only 3 major (and 17 minor) versions.

PHP, arguably the most popular web programming language (I call it the gateway language), was released in 1995 and has had 6 major versions and 17 minor versions.

ECMAScript (which JavaScript is based from), was first released in 1997, and has had 6 editions - 1997 (v1), 1998 (v2), 1999(v3), 2009(v5), 2015(v6), 2016(v7).

In contrast, NodeJS, which was first released in 2011, has had (depending on how you count it) 6 major and 40 minor versions.

The introduction of NodeJS made JavaScript a much more popular language since developers can now write isomorphic code (code which can run on bot client and server). This lowered the barrier of entry and improved efficiency.

But it also made the evolution of the language much more rapid - ECMA is now planning to roll out a new set of ECMAScript specifications every year, and NodeJS has released 3 major versions already in the past 12 months.

The Problem with Rapid Evolution

Each time a new ECMAScript specification appears, the follow list of problems becomes inevitable:

  • Lack of support - The development team behind different browsers (and their respective JavaScript runtimes) will prioritise which features to implement first differently. Look at the support for CSS filter, WebRTC (HTML5), indexedDB (HTML5), for example. As for support for ECMAScript features, you can refer to this compatibility table for ES5 and ES6.
  • Lack of backwards-compatibility - Developers using the new specification needs to ensure that their new codebase is backwards-compatible with older browsers/runtimes. This might not sound too complicated - you just add a shim/polyfill and forget about backwards-compatibility!

    If only it was that easy! For ES5, there were one standout shim - the aptly-named es5-shim. For ECMAScript 2015 (ES6), there is Babel - a suite of tools which includes an ECMAScript 2015 to ES5 compiler, polyfills amongst others.

    es5-shim is a shim, which means intercepts existing API calls and provide a new or alternative implementation. A polyfill detects if an API is present, and if not, provide an implementation for it. A compiler (in our case) transforms code written in the new specification (e.g. ECMAScript 2015), to code which conforms to a previous specification (ES5).

    However, if you refer the previously-mentioned compatibility table, neither es5-shim nor Babel fully support all the new features.

    By the time the new features are supported, the next specification would probably have already overtaken over as the newer standard.

  • Lack of guidelines - A specification is just that - it specifies what you can do, but it doesn't show you in what situation you should use it, or how an over application would look like with the new specification.

    For beginners, they'll often refer to tutorials; but when some tutorials use specification X, and others use Y, it can be very confusing.

    Just look at this Stack Overflow question to see how confusing a syntax change can be when React tried to be more ECMAScript 2015-conforming.

As we said, these problems are necessary for the evolution of a language. However, when it occurs at such a high pace, there is no stability - code which conforms to the latest (best) standards a year ago is now seen as out-dated.

And these changes does not only affect the language, it affects the libraries, frameworks and applications which are built on that language.

In the case of Meteor

We have been working with Meteor for about 2 years now, and since version 1.0.0, there have been major changes, most notably with React, native npm support and ECMAScript 2015.

In February 2015 (still 1.0.0), if you want to use ECMAScript 2015, you need to install the grigio:babel package from Atmosphere - Meteor's package manager.

Then in September 2015, Meteor 1.2.0 was introduced, which supported ECMAScript 2015 but requires the installation of the ecmascript package. It did not, however, support all ECMAScript 2015 features.

Meteor 1.2.0 was meant to be backwards-compatible, which means you can write ECMAScript 2015 for new components while leaving the old code just as it is (I would never recommend this as consistency in a code base is more important that ensuring it follows the latest specifications).

In March 2015, Meteor 1.3.0 was released, and with it came the support of ES6 modules - or the import/export syntax.

So in just over a year, it went from writing traditional ES5, to using Babel to write ECMAScript 6 that is compiled back to ES5, then to using the ecmascript package which did not support all ECMAScript 2015 features, to finally 'full' support.

It is impossible to update your entire codebase each time a new standard comes out. And if you work on multiple projects at the same time (like we do), mentally switching from Meteor 1.0 to 1.2 and then to 1.3+ is time-consuming and confusing.

The Paradox of Choice

Whether it'd be ego, or disagreements, there are many libraries and frameworks out there which essentially perform the same tasks (even though all of them claim they do it better). This leaves new developers with having to research X vs Y vs Z before even a single line of code is written.

Here are some examples:

This is, of course, an essential part of the evolution of a language (or library, or framework, or anything really) - improvements are proposed, some are tested, those which prove to be popular are adopted.

But when, in the case of Continuous Integration tools, all of them seems equal in terms of popularity, and there is no stand-out winner, you can commit to using a tool which, in 2-3 years, may become obsolete.

Developers have to Google X vs Y for everything before anything is written - that's a real issue.

Propensity for Jumping on Bandwagons

When a new library or framework comes out, there's always some hype - that much is expected. But I get the feeling that developers always thinks that the grass is always greener on the other side and that framework X is better than framework Y.

So when a new framework comes out every few months, they're often heralded as the next-best-thing, and we should all abandon the obsolete framework we are using and use the new one. This leads to instability in the code and high cost of maintenance.

Let's take a look at some front-end frameworks.

I remember around the end of 2013 to early 2014, ember.js was reaching the peak of its popularity - it was all the hype.

And then in mid-2015, Angular became really popular.

And now, React's popularity is still rising and is seen as the new best thing.

But it still doesn't end there, new kids on the block - Aurelia and vue.js has been making the rounds.

To be frank, I have tried both Angular and React, and each has their own merits. Whilst React is very simple and easy to understand, it does require a lot of boilerplate code to do a very simple task. Angular, however, adds a lot of custom attributes into the HTML, which breaks the separation of concerns that I value (Whilst React does have 'inline styles' and custom attributes in the JSX code, this is translated into pure JavaScript and does not show up on the final page).

This is very common - with Meteor, Iron Router is a perfectly fine router, but then Flow Router was introduced by a well-known developer and almost everyone started using Flow Router instead, without understanding why.

But maybe this is not a recent thing. Back in 2008, Jeff Atwood (of Stack Overflow fame) described those developers which jump on the new and shiny things as Magpie developers.

Don't feel inadequate if you aren't lining your nest with the shiniest, newest things possible. Who cares what technology you use, as long as it works, and both you and your users are happy with it?

taken from The Magpie Developer by Jeff Atwood

Be the Early Majority

But if everyone is jumping on, you must jump on also - because the new libraries (which will become standard later) will be written in this new language.

But many libraries do not survive the initial hype, and so what I recommend developers do is to jump on in the early-majority stage:

Graph taken from http://www.jamasoftware.com/blog/5-tips-software-adoption/

This way, you're still ahead of most people, whilst the innovators and early adopters have already gone through the frustrating and depressing stages of figuring out what works and what doesn't, refactoring the codebase to be production-ready, writing the most commonly-used libraries - you just stroll in take advantage of other people's work!

Conclusion

If you feel navigating through the JavaScript is confusing, this article was written for you. It's written to make you realise that you're not alone in feeling this - JavaScript is changing at a rapid pace, and it's fine to feel lost at times.

The web (specifically the Javascript/Node community) has created some of the most complicated, convoluted, over engineered tools ever conceived.

taken from The Sad State of Web Development by Drew Hamlett

That's why it is extremely important for you to have time to update yourself, either during work hours (if your employers are decent), or during your own free time.

Most of all, try out the different tools and make a judgement for yourself of which tools fit your style, and understand that there are merits with each tool, so don't use just one stack for everything.

You may also like to read Stop Using React for EVERYTHING! by Zack Argyle

Remember, with every framework, there is a 100% chance that someone will write a negative critic of it, which often sounds like:

Whilst they may raise some valid points, it's more important that you pick platforms you are familiar with. It's no point picking the latest platform but taking 6 months just to do a To-do app. Remember - frameworks and libraries are there to help you develop better and faster, not to hinder you with unnecessary complexity.

Pick something you understand, stick with it for a year, learn to be good at it, and if it still doesn't tick the right boxes for you, find something else. But it's better to be good at one 'outdated' platform and be productive than to be mediocre in three 'current' platforms and be lost 80% of the time.

And if anyone has the ignorance to say my X is better than your Y, just ask them 'Why?', and keep asking them 'Why?'. Chances are they don't know either.

Daniel Li

Full-stack Web Developer in Hong Kong. Founder of Brew.

Hong Kong http://danyll.com