Wednesday, April 30, 2014

Embular Part 4 - How Angular Should Be More Like Ember

Angular has a lot to learn from Ember. I think the ease of use in Angular and it's wide spread popularity may have gotten the idea into the community's head that it's "the best", but that's simply not the case.

Ember's use of convention over configuration. Angular allows developers to follow whatever convention they choose, which sounds like freedom to some, but on a large team it's more chaos than anything. Inconsistent names are a pet peeve at best, and a debugging nightmare at worst. For example a developer could name a controller "FooCtrl", "FooController", or "fooControllerer" or "fooServiceThing"... all legal names, none of them consistent. In fairness, Angular does provide a style guide, but in my experience getting people to follow a convention is a lot easier when a framework enforces and rewards the behavior.

Ember doesn't allow logic in templates. Angular, on the other hand does, via "expressions". These expressions are not quite "Turing-Complete" on their own, but they are very, very close. Expressions in templates are dangerous because they're harder to test. They also move what should have been a concern of your controller into your view. Angular's expression parsing engine is extremely impressive. It really is. Anyone that loves JavaScript should just go look at it, it's lexing pseudo-JS into tokens and parsing into a function that can be called against any JS object, usually scope. The problem with expressions is that they've allowed developers to put way, way too much logic into the templates, which makes that logic harder to test, and impossible to test in isolation. For example ng-bind="someVar + 'some string' + dangerZone('!!!')" or maybe something like: ng-click="foo = 'bar'; blah(foo + bar + '!!!); shazbot = nanoo && nanoo" ... that's totally legal in Angular, and completely insane. Ember does not allow this, you can bind to properties, calculated properties, or in the case of events, actions on the controller; All of which are easily tested in isolation.

Robust routing. As I've stated above, Ember's routing is flat out the best I've seen. The third-party ui-router for Angular comes close, but in the end, it's just a pale replica of what Ember has done, as best I can tell. That's not to belittle ui-router at all, it's a fine piece of code craftsmanship, but Ember has spent more time so far refining routing, and it shows. ngRoute, which is the Angular core offering doesn't even compare, and if it has a "best feature" it's simply that it's not included with Angular by default any longer.

Wire up more for the developer. I realize this might not be a goal the Angular team has, but in the end, Ember has solved the problem of "how can we help the developer" much better when it comes to wiring things up. In the case of routing, as mentioned in my previous article, when you setup a route in Ember and you simply give it a name, it will automatically know where to look for that route’s controller, model and template, as well set up the path it’s looking for.

For example in Ember:
Router.map(function(){
   this.route(‘foobar’);
});

would be this in Angular:

$routeProvider.when(‘/foobar’, {
   templateUrl: ‘/templates/foobar.html’,
   controller: ‘FoobarController’
});

That’s not really the end of it though, Ember also has a {{link-to}} helper that allows the developer to create a link to a page, by route name, and also pass a model to that route via the link {{link-to “foobar” shazbot}} will take whatever value (object or otherwise) is in the current controller’s `shazbot` property, as pass it as a parameter to the route, which carries over into the controller as a property.

Ember also has a feature which enables very simple two-way binding to query parameters. Basically, this means when a query parameter such as `#/routePath?foo=bar` becomes `#/routePath?foo=wee` then a property `foo` on the current controller will update from `”bar”` to `”wee”. Likewise, if you update the controller property `foo` to be something else, it will reflect it in the query param in the url bar.

Inheritance and mixins. Ember allows the developer to create a controller, or a component, or a route, or anything really, and then create subclasses of any of those things through basic inheritance. This is a very powerful tool. Combine that with Ember's mixins, and you've got a powerful toolset at your disposal that simply doesn't exist in Angular, at least not without some finagling

4 comments:

  1. So, I'm the lead developer of ui-router. I've read everything I can about Ember's router, and I still don't see what all the hype is about. It looks like it's just the conventions?

    ui-router doesn't offer any conventions out of the box, since that's not really the Angular way, but we expose an API that allows you to wire up your own conventions app-wide in a fairly small number of lines of code.

    Anyway, some insight into what the big deal is would be appreciated.

    ReplyDelete
    Replies
    1. First, I'd really like to thank you for working on ui-router. It's hands down the best thing that happened to Angular. Much, much better than ngRoute.

      What's great about Ember's router is that it allows nesting n-deep while preserving state in each layer. {{outlets}} which have {{outlets}} inside of them, to the n-th level. Combine this with some of the niceness you get with link creation helpers link {{link-to 'routeName' this}} and the ability to actually pass a model to your next route via a link and it's solidly the best.

      I think this is one of those areas where it warrants a more in-depth comparison to show off the features of both of these routers. 1. To show Angular developers why they should be using ui-router, and 2. To show those that aren't familiar with Ember what is so great about Ember's routing.

      Delete
    2. ... to be clear, I know that ui-router also allows n-deep nesting. Just realized by reply didn't convey that very well.

      In Ember it's the syntax and the tooling around it that really makes it shine.

      Delete
  2. About mixins / inheritance:

    - You can use coffeescript or some framework to have inheritance beyond prototyping

    - look at https://github.com/mgcrea/angular-strap/blob/master/src/typeahead/typeahead.js it is really nice how uses providers (like $typeahead) to help you to create your own directives (it's a kind of inheritance,



    What I really miss from from Ember in Angular is the data model, it's so nice with its computed values, etc... but it comes with a price: you cannot use POJOs

    btw, thanks for your posts!!

    ReplyDelete

This form allows some basic HTML. It will only create links if you wrap the URL in an anchor tag (Sorry, it's the Blogger default)