The tools we’ve been looking at include:
I’ve already grown pretty familiar with Backbone, having spearheaded its adoption into our tools set a year or so ago. We’ve built out a few non-trivial applications with Backbone and admire it’s simplicity and elegance. Backbone is lean and non-prescriptive, it’s a minimalistic library that gives you the most basic structure and tools for event-based model management.
Backbone is view-agnostic, meaning it gives you a basic wrapper for an event-based view and leaves rendering, model binding and plumbing up to you. It’s designed to work with a REST API out-of-box but can be easily customized. A router is provided but is optional
I built out a fairly simplistic but non-trivial demo application with Knockout a few months back. Microsoft is bundling it with VS 2012 so I thought it was worth taking a look under the hood. Knockout’s focus is on the UI, and it’s primary selling point is declarative two-way model binding. It’s a pretty slick library, but the DOM-based templating and mixture of behavior with markup leave me a little concerned with regard to maintainability at a large scale. My takeaway was that Knockout is best suited for smaller applications or “islands of richness” in traditional web applications.
Last but not least, I’ve been building out a demo with Ember.js. Ember takes a different approach in that it’s designed as a full-fledged application framework. It was designed by Rails and SproutCore contributors Yehuda Katz and Tom Dale, and is essentially a ground-up rewrite of SproutCore. It’s an impressive piece of work, there’s much to admire here, though there are some non-trivial concerns also.
- The learning curve is fairly steep, mostly getting your head around the core concepts of the framework. The Rails heritage of Ember is apparent: the framework is URL-centric - with the router front-and-center - and has a strong preference for convention over configuration. This made it a little difficult to get started at first, coming from a C#/.NET background where configuration is preferred.
- The documentation is still in-progress. The “Ember Guides” are somewhat vague and inconsistent, making it hard to get up to speed.
- The framework is nearing a 1.0 release, after which the core team intends to stabilize and lock it down. Until then, it is very much in transition, with regular breaking changes.
Ember is designed for SPA (single page application) development, and controls your entire document. It requires a global application variable, to which you assign the result of Ember.Application.create(). The Application object is responsible for:
- Acting as your application’s namspace
- Event delegation: adds listeners to your document and delegates them to your views
- Automatically renders your topmost application template
- Creates a router and starts routing with the current URL
I created all my Ember entities as AMD modules, and used the undocumented (as yet) Application.createWithMixins() function to pass in a hash of the resulting module return values, rather than adding instances to the created application.
Routing is the primary focus in Ember. Every state in an Ember application is represented by a URL. Your models, views, and controllers all stem from a URL route and are associated by naming convention to that route. If you follow Ember conventions, and don’t require custom code, Ember will provide a router handler and controller “automagically,” dramatically reducing boilerplate code for common scenarios.
Routes with a dynamic segment, like our “agent” resource above for example, have a common hook that is implemented automatically if not specified by a route handler:
What’s happening here is: the route handler is specifying a model that represents the current state (route) of the application; the default hook is to call a find() method on the corresponding model (named “Agent” by convention after the route) and passing in the dynamic segment of the URL. The next method, setupController() sets the resulting model as the ‘content’ property of the associated controller. (“AgentController”, again by convention)
Ember has deep integration with the Handlebars templating library, by Ember co-creater Yehuda Katz. Handlebars is a string-based templating library that supports conditionals and iterators. Ember some framework-specific semantics to its lexicon.
The canonical approach is to embed templates in your markup using <script> tags with a name attribute matching the template’s associated route. Using this approach it is largely possible to write Ember applications without writing View objects. However, since I’m using AMD and prefer to load my templates from separate files I’m creating View objects and specifying the compiled template as a property of the View:
Ember controllers present application state to templates. They are a representation of a model (or array of models) suitable for rendering by the template. Ember provides ObjectController and ArrayController “classes” for this purpose, which act as proxies to their underlying models.
The Ember Guides on the EmberJS website discuss Ember Data as the de facto persistence provider. From the website:
However, Ember Data does not ship with Ember, it is available via its GitHub repository, which clearly states that it is alpha quality and not production ready. Also, in order the get an current version of Ember Data, you have to clone the repository and build it with Ruby. While this makes sense given the Rails heritage, it’s off-putting for non-Ruby developers.
Anyway, I installed Ruby and built Ember Data so I could do a little investigation. Once nice feature is the FixtureAdapter, which lets you use in-memory data structures (an array of objects) to develop against prior to building out a server persistence layer.
Ember Data has a lot of promise, but I feel the Ember website shouldn’t be promoting it as the de facto solution when it’s clearly not finished.
- Good abstraction, lots of “nuts and bolts” operations are handled for you
- If you follow Ember conventions, you’ll write less boilerplate code than with other tools in this sector
- The newest version of Ember Router provides robust routing/state management
- Automatic memory management: Ember automatically binds and unbinds event listeners for garbage collection
- Global event delegation: event handlers are bound once to the application’s root element (typically the document) and events are delegated downwards for greater efficiency/smaller memory footprint
- Batch DOM updates: Ember gathers potential DOM updates and periodically applies them in batch for better performance. DOM updates are expensive.
- Ember is prescriptive. It’s a very opinionated framework, you have to build an application that fits the Ember architecture vs. building an architecture for your application
- Difficult to debug: abstraction and “automagical” housekeeping comes at the cost of complexity. Errors can be very hard to track down, so much so that Yehuda Katz authored an Ember Inspector extension for Chrome to aid in debugging Ember apps
- Documentation is still a work in progress, the guides are vague and inconsistent, making it hard to get up to speed
- The community is nascent, mostly Ruby or Rails oriented, many plugins have to be built with Ruby
- Nearing a 1.0 release, when hopefully the core will stabilize. Yehuda and Tom’s (admirable) approach has been to let the community drive development, but this comes as the cost of instability
- Ember.js is a powerful framework, showing tremendous promise. There is much to admire here.
- Ember is well-suited to Single Page Applications (SPAs) with longer user interactions, where memory management is a concern.
- If you subscribe to the “Ember way” it provides good abstraction, reduces boilerplate code, and handles a lot fo plumbing for you.
- with great power comes great responsibility… all this power comes at the cost of flexibility and ease of debugging.
- There are some non-trivial concerns, especially the framework’s transitional state as it moves towards a 1.0 release