Tero Piirainen • 2013-09-17
Why Angular, Ember, or Backbone don't work for us
Moot 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.
My primary goal for the Moot 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.
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.
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 Moot 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 validation||Backbone.js||33.9kb|
|Syntax highlight with support for 20+ languages||Rainbowjs||28kb|
|Tooltips, overlays, select boxes, tabs etc..||Misc. tools||20kb|
That's around 150kb of code before the actual development has even started.
Currently, the combined size of Moot 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.
Moot 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.
Moot 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 Moot 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.
Moot's engineering challenges were unique.
Let's look at Google Trends for Angular (blue), Backbone (yellow) and Ember (red) (2):
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):
Moot 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?
First, it's about the same size as Moot 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
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.
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 Moot 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.
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:
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.
As a result of our combined perfectionism and minimalism, Moot 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 Moot client.
Edits (Dec 7, 2013)
- Updated Google Trends graphs
- Updated file sizes and jQuery usage statistics
- Added link to the Riot.js blog entry