Frameworkless JavaScript

Tero Piirainen2013-09-17

Why Angular, Ember, or Backbone don't work for us

Muut is a special discussion platform with ambitious goals. While the server side is fanatically optimized for performance, the client has its own goals: simple API, small size, and quick release cycle. The code is written from scratch and is split into more than 50 files. A client-side framework such as Angular or Ember were out of the question.

Here's why.

API first

My primary goal for the Muut client was a simple API. It had to be easy to use, have no extra properties or methods, and shouldn't present new programming idioms. It would feel familiar for a newcomer. Not only would the end users be using it, but I would personally be using it for years to come, since the whole web UI is built on top of it.

When starting to design an API I always want to start from scratch. Just a clean table, a pen, and paper. I'm thinking about the API and the end user only. No frameworks are present at this point.

This API becomes the Model in MVC, in a form of "Plain Old JavaScript Object" (POJO). For framework advocates the API is a "single source of truth". The API runs on browser as well as on server (node.js). It's a completely separate, testable unit.

I really don't want to clutter the API with framework related methods and properties. Both Backbone.Model.extend and Em.Object.extend add tens of redundant methods, adding complexity for the end user. This is simply not acceptable from our minimalistic approach.

Small size

A smaller file is faster to load and saves us money in bandwidth costs. That's an instant benefit. The biggest advantage, however, is in the code maintenance. A smaller codebase is easier to handle, faster to learn, and has less issues.

Currently the Muut client weighs 89kb when minified, 32kb when gzipped. This is roughly 10 times less than other discussion platforms out there. Size definitely matters. And when 50% of all internet usage happens from mobile devices (1), developers are seeking for the slimmest tools for the job.

The following table gives you an idea of the size had we used a separate tool for each feature. I'm listing projects that I would have used — not the biggest projects I could find just to look good in comparison. The sizes are from minified files.

Templating, data-binding, form validationBackbone.js33.9kb
Syntax highlight with support for 20+ languagesRainbowjs28kb
Tooltips, overlays, select boxes, tabs etc..Misc. tools20kb
WebSocket communicationsocket.io40kb
Markdown parsermarkdown-js23kb

That's around 150kb of code before the actual development has even started.

Currently, the combined size of Muut with all the UI views and controllers (the glue between API and views) is just 40kb when minified. How much would that be with a framework? It should be much smaller if the purpose of a framework is to reduce the amount of work to achieve the goals.

40kb is easy to manage and build upon. I can add massive amounts of features before things start to get complex.

Full control

Muut uses native pushState for managing URLs, John Resig's "micro templating" (6) for views, and internal communication between model and views happens with a custom event library. There is no router or automatic data-binding.

Everything works exactly how we want it to, and the bugs are easy to find. There is no wasteland of unknown code of which you have no idea how it works. There are no mysteries and the stack traces are shallow. We can structure the code according to the specific needs of the application – there is no framework to dictate how things must work.

No mixed programming styles.

No external package updates.

No dependency hells.

It's fun to make a new release every week.

Special needs

The Muut client is a single JavaScript file including all the HTML code as well. The client renders itself inside a single anchor (A) tag when the page loads. The product packaging and bootstrapping are very different from a traditional single-page application.

Muut servers must be able to notify clients at any time. Both clients and servers communicate in a peer-to-peer bi-directional fashion.

We send JSON-RPC messages with WebSockets. REST is not an option here: real-time applications such as Muut cannot be built on it, because it uses a request-response pattern and does not understand things like push events.

Today's frameworks, such as ember data, are REST-oriented and the examples and documentation are based on REST. WebSocket examples are missing or experimental.

Muut's engineering challenges were unique.

Technology lock-in

If you look at the history of frameworks in any programming language, it's a history of failures. Frameworks come and go. Today's JavaScript frameworks are all very young. Backbone, Angular, and Ember may be trendy now, but not necessarily in a few years' time.

Let's look at Google Trends for Angular (blue), Backbone (yellow) and Ember (red) (2):

JavaScript Framework trends

JavaScript is the most popular programming language in the world, and allows multiple programming styles. Things are changing at an incredible speed. As a result the angry framework communities constantly fight over the best way to build an application.

And there is no best way.

There are a lot of different ways instead. Now Angular is in tremendous rise. "AngularJS lets you extend HTML vocabulary for your application." Is that the best way? Are Backbone and Ember in a risky position? The companies that invested in Framework X in 2012 may soon realize that their development team is already talking about the next big thing. As a developer using one of these frameworks, I'd worry about their life expectancy.

On the other hand, let's compare jQuery with Angular (3):

jQuery vs Angular

This gives you a good idea of the popularity of jQuery. It's currently being used on 57.2% of all websites in the world and 92.7% of all the websites whose JavaScript library is known. (4) There is no technology lock-in. As an embedded application we cannot expect people to load another framework on their site but jQuery is there already.

Muut uses all parts of jQuery, I even borrow ideas from jQuery when designing an API. It's simple and it works. I (still) love the beauty of it.

Why not Angular?

Angular looks promising. The fact that I can just write my model in plain JavaScript and let angular render the views without any glue code sounds awesome! But there are certainly things that I don't like about this framework.

First, it's about the same size as Muut as a whole (91kb). I want two-way binding only, but I'm forced to take the whole framework. There is too much overhead for me. I hope they will make the data-binding a separate piece and make it simpler. People shouldn't need to worry about the internal mechanisms such as $watch, $apply or $digest.

And despite it's been marketed as being simple, the API is huge. Currently there are 147 different sections on the sidebar of their documentation area. That's a big cognitive load. I need an empty table for building stuff.

And I really don't like to put so much logic in views or wrap my precious code to proprietary "directives" or "filters". The fairly complex logic of Muut is better expressed with plain old JavaScript.

Why not Ember.js?

Ember is huge. I mean HUGE! The minified size of the library is 240kb. Needless to say their API is huge too. I picked the first section from the sidebar of their documentation (Modules > Ember) and that section only had 80 different subsections.

The biggest turndown, however, is that I need to wrap my handcrafted objects with Ember.Object causing the API to explode with new methods.

A big framework with a lot of proprietary idioms is a risky choice. Remember Enterprise Java Beans?

Why not Backbone.js?

Backbone is the smallest and simplest of the three frameworks, 33.9kb when minified. That includes underscore.js which is a hard dependency. More than half of the size of the whole Muut application.

My issue with Backbone is that I never liked the "backbone way" of structuring code. There is too much of boilerplate. I prefer the code to be compact. I completely agree that it's important to separate the API code from the UI code but Kim Joar Bekkelund's popular article (5) about turning your jQuery code into Backbone makes no sense to me. For me the resulting code is actually harder to follow.

And just like Ember, Backbone does not promote the use of POJO's, so you need to wrap your objects with Backbone.Model.extend, introducing unnecessary framework-specific methods.

From the three Backbone is the least risky choice. It's not doing any magic and even if its development stops it could be patched or replaced with your own wrapper.

Finally, as a RESTful framework, it's not a perfect fit for real-time communication.

Scrapped frameworks

But jQuery leads to spaghetti, right?

Common thesis is that after you've piled your application with thousands of lines a jQuery hell will break loose. The application has no structure and the code is a large plate of spaghetti. This is simply not true. When API is fully separated from the rest of the code, it's easy to build the controller code with jQuery.

Basically my controller code looks like this:

// controller for a Topic model
function drawTopic(topic) {
 
// generate new element with micro templating
var root = tmpl("<div>some html</div>", topic);
 
// topic elements
var seed_post = $(".seed", root),
replies = $(".replies", root);
 

// listen to events on model
topic.expand(function() {
// do something with the elements
 
}).collapse(function() {
// do something else
 
}).remove(function(post) {
// etc
 
}).reply(function(post) {
 
})...
 
}

JavaScript

That's how I personally want my code to be organized. Goals for a web application should not be in imperative DOM manipulation, object oriented practices, or in "pure" MVC. A successful application aims to be simple, and there is no room for academic jargon.

The results

As a result of our combined perfectionism and minimalism, Muut is an extremely lightweight, manageable, and independent web application sitting on top of your page's html. With the same "from-scratch" approach applied to our server side code and UX, it is not likely that you'll see comparable discussion platforms very soon — unless groups of highly capable and relentless people already got the same idea some years ago.


Next blog entry: Riot.js – the "1kb MVP library" behind the Muut client.

Edits (Dec 7, 2013)

  • Updated Google Trends graphs
  • Updated file sizes and jQuery usage statistics
  • Added link to the Riot.js blog entry

Tero Piirainen

tero@muut.com