Wednesday, April 30, 2014

Embular Part 5 - How Ember Should Be More Like Angular

Constructor-based dependency injection as an obvious feature. Angular forces a constructor-based DI style that uses constructor functions with parameters. The style is carried throughout the framework and is plainly obvious to any developer that is writing code against Angular. In essence, it forces dependency injection. As an added bonus, this style of dependency declaration and injection enables Angular to detect circular dependencies at run-time.

Ember on the other hand, does not have this exact same mechanism. While you can inject your dependencies at time of creation with Ember via EmberObject.create({ deps: here }), the actual injection of those dependencies is optional. Meaning if one of those dependencies doesn't exist, it will still create the object. There also currently isn't a mechanism for circular dependency checking. The final issue related to how Ember handles the injection of dependencies is that it's not really apparent to the developer where dependencies are being "injection". The short answer: Anywhere you see this.get('something") is an entry point for a dependency. So there are multiple points where dependencies can be injected into your classes, whereas in Angular, there's one obvious point they are injected from, and it helps guide the developer towards dealing with dependencies in that manner.

Angular has a cleaner, neater API. Angular’s api revolves around a small set of primitives: controllers, service providers, directives, and filters. Along with a uniform DI syntax, these primitives allow Angular to be learned quickly and easily by new developers. Angular gives you a powerful set of tools, and then gets out of your way.

In contrast, Ember’s API has a broad surface area. There are many different types of controllers and other Ember primitives and it’s really hard to tell what you should and shouldn’t worry about using when you’re first starting out.  Combine this with an API that isn’t always easy to read and it can be difficult for a developer new to Ember to figure out what’s really happening. For example: App.FooController = Ember.Controller.extend({ foo: 'bar' }) to create a controller, while fairly terse, doesn't make any sense to someone from outside Ember. It reads like "set App.FooController  equal to Ember.Controller, and extend Ember.Controller with this object literal I'm giving you were foo is set to 'bar'".... When I first saw this format I was thinking, "What am I extending? Is this like $.extend? If so, why am I extending this Controller object over and over again?" By that token, angular.controller('FooCtrl', function($scope) { $scope.foo = 'bar'; });  just reads more fluently. "Angular, create a controller, named FooCtrl, it needs $scope, and it should put 'bar' on foo on scope".

Even computed properties, one of Ember's better features, don't read easy on the eyes to new developers. excitedFoo: function() { return this.get('foo') + '!!!'; }.property('foo')  ... Anyone new is going to be like "What the hell is this property method on this anonymous function? Where did that come from? How do I call this new function?"

Handlebars is ugly. There I said it. It's ugly. <div {{bind-attr thing="this" blah="that"}}></div> Is just plain ugly compared to dealing with Angular's templating... which is just plain HTML.  That said, however, HTMLBars is coming, and it will completely change all of that and *should* level that part of the playing field.

Angular can stand alone. Angular doesn't require any additional libraries to to function. Ember on the other hand, requires JQuery and Handlebars to function. Which only adds to Ember's already fairly immense download size. Generally speaking though, this is not a big deal. Once it's downloaded, it's downloaded. But it's worth mentioning because some people do care about this, for whatever reason.

Angular is a lot more lightweight. Let's compare the two current production versions: Angular 1.2.16 (104K min / 37K gzip) vs Ember 1.5.1 (277K min / 75K gzip) is almost half the size gzipped, and almost a third the size if your server admin forgets to enable gzip compression on your web server. And to be clear, that doesn't include the other two files that Ember requires: JQuery 2.0.1 (81K min / 28K gzip) and Handlebars 1.3.0 (43K min / 13K gzip). Those bring the required download to spin up an Ember app to around (401K gzip / 116K gzip) versus (104K / 37K) for Angular. For added fairness we'll include Angular's routing module (4K min / 2K gzip), but that's hardly going to make a difference.  But this probably isn't a big deal. This particular concern is really only a concern the first time a user hits a page, because all of these files should be cached after that. Still, some people look at file size and might not like what they find.

NEXT: Embular Part 6 - Two Paths Up The Same Mountain

2 comments:

  1. Great post, I appreciate you sharing your thoughts.

    Maybe it's because I'm an Ember dev, but

    App.FooController = Ember.Controller.extend({ foo: 'bar' })

    seems much more readable to me than:

    angular.controller('FooCtrl', function($scope) { $scope.foo = 'bar'; });

    ReplyDelete
  2. Vic, 1+...

    Also, in the Ember code you're obviously extending, not instantiating, a base class whereas in the Angular code you're presumably creating an instance... or are you? Coming from outside Angular, I actually have no idea... Readability is mostly a function of exposure, experimentation, and documentation.

    Ember has a very active freenode.net IRC channel, #emberjs. If you're trying to figure it out, and have read the (very excellent) guides and API docs thoroughly, jump on IRC with your questions...

    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)