Yet Another JavaScript Framework
On March 6, 2018, a new bug was added to the official Mozilla Firefox browser bug tracker. A developer had noticed an issue with Mozilla’s nightly build. The report noted that a 14-day weather forecast widget typically featured on a German website had all of a sudden broken and disappeared. Nothing on the site had changed, so the problem had to be with Firefox.
The problem, the developer noted in his report, appeared to stem from the site’s use of the JavaScript library MooTools.
At first glance, the bug appeared to be fairly routine, most likely a small problem somewhere in the website’s code or a strange coincidence. After just a few hours though, it became clear that the stakes for this one particular bug were far graver than anyone could have anticipated. If Firefox were to release this version of their browser as-is, they risked breaking an unknown, but still predictably rather large number of websites, all at once. Why that is has everything to do with the way MooTools was built, where it drew influence from, and the moment in time it was released. So to really understand the problem, we’ll have to go all the way back to the beginning.
In the beginning
First came plain JavaScript. Released in 1995 by a team at Netscape, Javascript began making its way into common use in the late 90’s. JavaScript gave web developers working with HTML a boost, allowing them to dynamically shift things around, lightly animate content, and add counters and stock tickers and weather widgets and all sorts of interactivity to sites.
By 2005, JavaScript development had become increasingly complex. This was precipitated by the use of a technique we know as Asynchronous JavaScript and XML (Ajax), a pattern that likely feels familiar these days for anyone that uses a website to do something more than just read some content. Ajax opened up the door for application-like functionality native to the web, enabling the release of projects like Google Maps and Gmail. The phrase “Web 2.0” was casually lobbed into conversation to describe this new era of dynamic, user-facing, and interactive web development. All thanks to JavaScript.
It was specifically Ajax that Sam Stephenson found himself coming back to again and again in the early years of the turn of the century. Stephenson was a regular contributor to Ruby on Rails, and kept running into the same issues when trying to connect to Rails with JavaScript using some fairly common Ajax code. Specifically, he was writing the same baseline code every time he started a new project. So he wrote a few hundred lines of code that smoothed out Ajax connections with Rails he could port to all of his projects. In just a few months, a hundred lines turned into many more and Prototype, one of the earliest examples of a full JavaScript framework, was officially released.
Extending JavaScript
Ruby utilizes class inheritance, which tends to lend itself to object-oriented development. If you don’t know what that means, all you really need to know is that it runs a bit counter to the way JavaScript was built. JavaScript instead leans on what’s known as prototypal inheritance. What’s that mean? It means that everything in JavaScript can be extended using the base object as a prototype. Anything. Even native object prototypes like String
or Array
. In fact, when browsers do add new functions and features to Javascript, they often do so by taking advantage of this particular language feature. That’s where Stephenson got the name for his library, Prototype.
The bottom line is, prototypal inheritance makes JavaScript naturally forgiving and easily extendable. Its basically possible for any developer to build on top of the core JavaScript library in their own code. This isn’t possible in a lot of other programming languages, but JavaScript has always been a bit of an outlier in terms of its approach to accommodate a much larger, cross-domain developer base.
All of which is to say that Stephenson did two things when he wrote Prototype. The first was to add a few helpers that allowed object-oriented developers like himself to work with JavasScript using a familiar code structure. The second, and far more important here, is that he began to extend existing Javascript to add features that were planned for some point in the future but not implemented just yet. One good example of this was the function document.getElementByClassName
, a slightly renamed version of a feature that wouldn’t actually land in JavaScript until around 2008. Prototype let you use it way back in 2006. The library was basically a wish list of features that developers were promised would be implemented by browsers sometime in the future. Prototype gave those developers a head-start, and made it much easier to do the simple things they had to do each and every day.
Prototype went through a few iterations in rapid succession, gaining significant steam after it was included by default in all Ruby on Rails installations not long after its release. Along the way, Prototype set the groundwork for basically every framework that would come after it. For instance, it was the first to use the dollar sign ($
) as shorthand for selecting objects in JavaScript. It wrote code that was, in its own words, “self-documented,” meaning that documentation was scarce and learning the library meant diving into some code, a practice that is more or less commonplace these days. And perhaps most importantly, it removed the difficulty of making code run on all browsers, a near Herculean task in the days when browsers themselves could agree on very little. Prototype just worked, in every modern-at-the-time browser.
Prototype had its fair share of competition from other libraries like base2 which took the object-oriented bits of Prototype and spun them off into a more compact version. But the library’s biggest competitor came when John Resig decided to put his own horse in the race. Resig was particularly interested in that last bit, the work-in-all-browsers-with-the-same-code bit. He began working on a different take on that idea in 2005, and eventually unveiled a library of his own at Barcamp in New York in January of 2006.
It was called jQuery.
New Wave JavaScript
jQuery shipped with the tagline “New Wave Javascript,” a curious title given how much Resig borrowed from Prototype. Everything from the syntax to its tools for working with Ajax — even its use of a dollar sign as a selector — came over from Prototype to jQuery. But it wasn’t called New Wave JavaScript because it was original. It was called New Wave JavaScript because it was new.
jQuery’s biggest departure from Prototype and its ilk was that it didn’t extend existing and future JavaScript functionality or object primitives. Instead, it created brand new features, all assembled with a unique API that was built on top of what already existed in JavaScript. Like Prototype, jQuery provided lots of ways to interact with webpages, like select and move around elements, connect to servers, and make pages feel snappy and dynamic (though it lacked the object-oriented leanings of its predecessor). Crucially, however, all of this was done with new code. New functions, new syntax, new API’s, hence a new wave of development. You had to learn the “jQuery way” of doing things, but once you did, you could save yourself tons of time with all of the stuff jQuery made a lot easier. It even allowed for extendable plugins, meaning other developers could build cool, new stuff on top of it.
MooTools
It might sound small, but that slight paradigm shift was truly massive. A shift that seismic required a response, a response that incidentally came the very next year, in 2007, when Valerio Proietti found himself entirely frustrated with another library altogether. The library was called script.aculo.us, and it helped developers with page transitions and animations. Try as he might, Proietti just couldn’t get script.aculo.us to do what he wanted to do, so (as many developers in his position have done in the past), he decided to rewrite his own version. An object-oriented developer himself, he was already a big fan of Protoype, so he based his first version off of the library’s foundational principles. He even attempted to coast off its success with his first stab at a name: prototype.lite.js. A few months and many new features later, Proietti transformed that into MooTools.
Like Protoype, MooTools used an object-oriented programming methodology and prototypical inheritance to extend the functionality of core JavaScript. In fact, most of MooTools was simply about adding new functionality to built-in prototypes (i.e. String
, Array
). Most of what MooTools added was on the JavaScript roadmap for inclusion in browsers at some point in the future; the library was there to fill in the gap in the meantime. The general idea was that once a feature finally did land in browsers, they’d simply update their own code to match it. Web designers and developers liked MooTools because it was powerful, easy to use, and made them feel like they were coding in the future.
There was plenty there from jQuery too. Like jQuery, MooTools smoothed over inconsistencies and bugs in the various browsers on the market, and offered quick and easy ways to add transitions, make server requests, and manipulate webpages dynamically. By the time MooTools was released, the jQuery syntax had more or less become the standard, and MooTools was not going to be the one to break the mold.
There was enough similarities between the two, in fact, for them to be pitted against one another in a near-endless stream of blog posts and think-pieces. MooTools vs. jQuery, a question for the ages. Websites sprung up to compare the two. MooTools was a “framework,” jQuery was a “library.” MooTools made coding fun, jQuery made the web fun. MooTools was for Geminis, and jQuery was for Sagittariuses. In truth, both worked very well, and the use of one over the other was mostly a matter of personal preference. This is largely true of many of the most common developer library debates, but they continue on all the same.
The legacy of legacy frameworks
Ultimately, it wasn’t features or code structure that won the day — it was time. One by one, the core contributors of MooTools peeled off from the project to work on other things. By 2010, only a few remained. Development slowed, and the community wasn’t far behind. MooTools continued to be popular, but its momentum had come to a screeching halt.
jQuery’s advantage was simply that they continued on, expanded even. In 2010, when MooTools development began to wind down, jQuery released the first version of jQuery Mobile, an attempt at retooling the library for a mobile world. The jQuery community never quit, and in the end, it gave them the advantage.
The legacy and reach of MooTools, however, is massive. It made its way onto hundreds of thousands of sites, and spread all around the world. According to some stats we have, it is still, to this day, more common to see MooTools than Angular or React or Vue or any modern framework on the average website. The code of some sites were updated to keep pace with the far less frequent, but still occasional, updates to MooTools. Others to this day are comfortable with whatever version of MooTools they have installed. Most simply haven’t updated their site at all. When the site was built, MooTools was the best option available and now, years later, the same version remains.
Array.flatten
Which brings us all the way back to the bug in the weather app that popped up in Firefox in early 2018. Remember, MooTools was modeled after Prototype. It modified native JavaScript prototype objects to add some functions planned but not yet released. In this specific case, it was a method called Array.flatten
, a function that MooTools first added to their library way back in 2008 for modifying arrays. Fast forward 10 years, and the JavaScript working group finally got around to implementing their own version of Array.flatten
, starting with the beta release of Firefox.
The problem was that Firefox’s Array.flatten
didn’t map directly to the MooTools version of Array.flatten
.
The details aren’t all that important (though you can read more about it here). Far more critical was the uncomfortable implication. The MooTools version, as it stood, broke when it collided with the new JavaScript version. That’s what broke the weather widget. If Firefox were to release their browser to the larger public, then the MooTools version of flatten
would throw an error, and wipe out any JavaScript that depended on it. No one could say how many sites might be affected by the conflict, but given the popularity of MooTools, it wasn’t at all out of the question to think that the damage could be extensive.
Once the bug surfaced, hurried discussion took place in the JavaScript community, much of it in the JavaScript working group’s public GitHub repo. A few solutions soon emerged. The first was to simply release the new version of flatten
. Essentially, to let the old sites break. There was, it was argued, a simple elegance to the proposal, backed fundamentally by the idea that it is the responsibility of browsers to push the web forward. Breaking sites would force site owners to upgrade, and we could finally rid ourselves of the old and outdated MooTools versions.
Others quickly jumped in to point out that the web is near limitless and that it is impossible to track which sites may be affected. A good amount of those sites probably hadn’t been updated in years. Some may have been abandoned. Others might not have the resources to upgrade. Should we leave these sites to rot? The safe, forgivable approach would be to retool the function to be either backward or fully compatible with MooTools. Upon release, nothing would break, even if the final implementation of Array.flatten
was less than ideal.
Somewhere down the middle, a final proposition suggested the best course of action may simply be to rename the function entirely, essentially sidestepping the issue altogether and avoiding the need for the two implementations to play nice at all.
One developer suggested that the name Array.smoosh
be used instead, which eventually lead to the whole incident to be labeled Smooshgate, which was unfortunate because it glossed over a much more interesting debate lurking just under the surface about the very soul of the web. It exposed an essential question about the responsibility of browser makers and developers to provide an accessible and open and forgiving experience for each and every user of the web and each and every builder of the web, even when (maybe especially when) the standards of the web are completely ignored. Put simply, the question was, should we ever break the web?
To be clear, the web is a ubiquitous and rapidly developing medium originally built for sharing text and links and little else, but now used by billions of people each day in every facet of their lives to do truly extraordinary things. It will, on occasion, break all on its own. But, when a situation arises that is in full view and, ultimately, preventable, is the proper course of action to try and pull the web forward or to ensure that the web in its current form continues to function even as technology advances?
This only leads to more questions. Who should be responsible for making these decisions? Should every library be actively maintained in some way, ad infinitum, even when best practices shift to anti-patterns? What is our obligation, as developers, for sites we know have been abandoned? And, most importantly, how can we best serve the many different users of the web while still giving developers new programmatic tools? These are the same questions that we continue to return to, and they have been at the core of discussions like progressive enhancement, responsive design and accessibility.
Where do we go now?
It is impossible to answer all of these questions simply. They can, however, be framed by the ideological project of the web itself. The web was built to be open, both technologically as a decentralized network, and philosophically as a democratizing medium. These questions are tricky because the web belongs to no one, yet was built for everyone. Maintaining that spirit takes a lot of work, and requires sometimes slow, but always deliberate decisions about the trajectory of web technologies. We should be careful to consider the mountains of legacy code and libraries that will likely remain on the web for its entire existence. Not just because they are often built with the best of intentions, but because many have been woven into the fabric of the web. If we pull on any one thread too hard, we risk unraveling the whole thing.
As the JavaScript working group progressed towards a fix, many of these questions bubbled up in one form or another. In the end, the solution was a compromise. Array.flatten
was renamed to Array.flat
, and is now active in most modern browser releases. It is hard to say if this was absolutely the best decision, and certainly we won’t always get things right. But if we remember the foundational ideals of the web — that it was built as an accessible, inclusive and always shifting medium, and use that as a guide — then it can help our decision-making process. The seems to have been at the core of the case with Smooshgate.
Someday, you may be browsing the web and come across an old site that hasn’t been updated in years. At the top, you may even notice a widget that tells you what the weather is. And it will keep on working because JavaScript decided to bend rather than break.
Enjoy learning about web history with stories just like this? Jay Hoffmann is telling the full story of the web, all the way from the beginning, over on The History of the Web. Sign up for his newsletter to catch up on the latest… of what’s past!
The post Yet Another JavaScript Framework appeared first on CSS-Tricks.