AngularJS vs Ember

Tags: #<Tag:0x00007f52c298a230> #<Tag:0x00007f52c2989f60>

#1

Recently I got together with some local developers to discuss client side MVC frameworks. We ended up discussing many of the differences between AngularJS and Ember.

Discourse is an Ember application and has been since the first prototype, so I have a lot of experience with it. However, it became clear during the conversation with my peers that there was a lot about AngularJS I didn’t know.

There is evidence that AngularJS is beating out Ember in terms of developer mind share: there are more Stack Overflow questions dedicated to AngularJS. AngularJS has more stars and forks on Github. At a recent Javascript meetup in Toronto, when polled virtually every developer expressed interest in learning more about AngularJS. Clearly there is something to this framework!

I decided to take some time to seriously investigate AngularJS and see what all the fuss was about. I read through as much documentation, blog posts and guides as I could. I downloaded AngularJS and made simple applications. I reached out to local developers and pestered them with questions about the framework.

I have a good idea now why AngularJS is gaining momentum: it is simpler. There is a lot less to the framework and as a consequence it’s easier to learn. If I were to rank the amount of tools various client side MVC frameworks give you, Angular seems to exist somewhere near the half way point between Backbone and Ember.

The pitfalls of simplicity

A few years ago, many Rails developers I knew were excited about Sinatra. Sinatra is far simpler than Rails. It allocates a fraction of the objects Rails does. I observed a pattern as those developers started to build out their applications. Some were used to Rails' large toolbox of convenience functions so they included ActiveSupport. Some needed ORMs so they included ActiveRecord. At that point, what was the advantage of Sinatra? You were basically running a Rails application.

Framework simplicity is good if your application is meant to be simple. But you should be cautious when choosing simplicity if your application is ambitious and you care about supporting it for a long time.

Don’t get me wrong: if an API is convoluted and verbose, and a competing one is equally functional yet simpler to use, by all means use the competitor. However, people are far too quick to mistake simplicity for good design.

Ember has more concepts to learn and more to wrap your head around than AngularJS. Before you write off Ember due to its complexity, consider why the developers added all that extra stuff. Perhaps it’s there for a reason?

Ember is a toolbox full of concepts you will find useful if you want to build a large and maintainable application. The trade offs it has made in its API are there to help you structure your code in a sane way. As you learn Ember you will notice several philosophies and opinions that are completely absent from the AngularJS framework.

This is far better illustrated via example. In this post, I’m going to try and demonstrate a few major shortcomings in AngularJS and how the Ember approach is much better.

In pursuit of a single source of truth

Let’s say you’re working on a web application that does rendering on the server. The current page you’re working on is meant to display a list of items as rows, and if the user clicks on a row, it will change color to indicate it’s been selected.

If you were using jQuery to do this, you’d likely bind a function to the click event on each row. When fired, your function would change the CSS class of the row to highlight it.

You can’t stop there, though. Your function also has to remove the CSS class from any other rows that were previously selected. That’s a little crazy if you think about it! Changing which item is selected means we have to know everywhere that it’s been represented in our UI.

Whenever you store the same piece of data in multiple places, it is likely to go out of sync. Additionally, your code ends up being longer and more complex as it has to manage all the various updates every time it changes.

Client side MVC (Model View Controller) frameworks like Ember and AngularJS separate your data model from its presentation. Your model becomes the single source of truth. If you change it, your HTML template changes automatically. If you want to know its current value, you read it from the model instead of the DOM.

This is a a huge boon to developer productivity while simultaneously reducing the potential for errors related to out of sync data.

What’s an AngularJS Model?

AngularJS touts itself as a MVC or MVW (Model View Whatever) framework.

It’s clear where AngularJS' view layer is: you annotate regular HTML documents with ng-* attributes and handlebars style {{variable}} expressions. It’s also easy to understand where the controllers are; you link Javascript classes to elements using ng-controller attributes.

What isn’t clear, especially if you come from a server side MVC background, is what is an AngularJS model? There is no standard Model base class, nor is there a component or interface in AngularJS that defines what a model is supposed to be.

In an AngularJS controller, you are given an object called $scope. Any data you attach to it is rendered in your HTML template:

function SomeCtrl($scope) {
  $scope.countries = ['can', 'usa', 'fra', 'jap'];
  $scope.user = {name: "Evil Trout"};
  $scope.age = 34;

  // Our template now can render {{age}}, {{user.name}} and a list of countries!
}

According to the AngularJS documentation any named data in an AngularJS $scope is a model, not just Javascript objects and arrays, but primitives, too! In the above snippet, there are three models!

What’s wrong with Javascript primitives as models?

AngularJS gives you tools you need to manage a single source of truth in your templates. This is a concept known as data binding. If we created a template that has an AngularJS expression {{age}}, we can say it’s bound to the $scope.age model. If you wrote {{age}} several times in one template, and executed $scope.age = 40 in your controller, all would update simultaneously.

There is a secondary level of data binding, however, that you need if you truly want to express a single source of truth, and that is within your data model itself. In other words, AngularJS stops short by only allowing for data binding only between your $scope and template, not within the structures in your Javascript code.

In Ember, all models extend the Ember.Object base class. When you do this, you gain the ability to declare relationships within and between models. For example:

App.Room = Ember.Object.extend({
  area: function() {
    return this.get('width') * this.get('height');
  }.property('width', 'height')
});

Here, we’ve created a model called Room. We’ve declared area which is known as a computed property. The property syntax you see at the end there tells Ember that the Room’s area depends on its width and height.

Creating an instance of this model is easy:

var room = App.Room.create({width: 10, height: 5});

Now we can create a template:

<p>Room:</p>

<p>{{width}} ft.</p>
<p>{{height}} ft.</p>
<p>{{area}} sq ft.</p>

And Ember would render the attributes correctly. In this case, it’s impossible for area to be out of sync with width and height. If either of those two properties change, area will be updated automatically.

Modeling this in AngularJS

Because AngularJS models are regular Javascript objects, AngularJS doesn’t have an equivalent to computed properties. However, you can approximate them using functions on your objects:

var Room = function(args) {
  this.width = args.width;
  this.height = args.height;
}

Room.prototype.area = function() {
  return this.width * this.height;
}

To access the area of our Room, you have to add a set of parentheses to your area() call:

<p>Room:</p>

<p>{{width}} ft.</p>
<p>{{height}} ft.</p>
<p>{{area()}} sq ft.</p>

This illustrates a key difference between Ember and AngularJS. Ember subscribes to the Uniform Access Principle. In an Ember template, regardless of whether you are accessing something that is computed or something that is a primitive, the expression looks the same. In AngularJS, functions have to be specifically demarcated.

This can cause maintainability nightmares down the road. Over time, in a large software project, you will inevitably want to replace something that was previously a primitive with a method. In Ember you can do this painlessly; in AngularJS you’ll have to update every template where that model is used.

Using getters and setters

It’s worth discussing a related trade-off you might have noticed in the Ember code above: to access properties of a model, you have to use getters and setters. This means a little extra typing, but you reap the same benefit in the Javascript code that you do in the template: replacing a primitive with a function will just work!

A secondary benefit to using getters and setters is you can chain them safely. Consider the following code:

console.log(room.inhabitant.name);

What happens if the inhabitant is not present? You’ll raise a Javascript error. In the Ember equivalent you’ll get undefined back, which makes it easier to write more resilient code:

// outputs undefined
console.log(room.get('inhabitant.name'));

Performance issues

There is another downside to using a functions instead of computed properties: it’s much slower.

In our Ember code, we expressed that area depends on width and height. In AngularJS, we didn’t do that. So how could AngularJS possibly know to re-render the area if the width or height changed? In fact, how does AngularJS ever know to re-render when things change if it’s not using special Javascript objects for models?

The answer is: it doesn’t. AngularJS uses a process called dirty checking to determine what it needs to update in the DOM. When a controller finishes executing code, AngularJS compares everything in the $scope to its previous values. If they’ve changed, it updates the DOM.

AngularJS cannot know whether it needs to execute the function again because it doesn’t know what the function does, so it executes its code every time it has to update the template. What if your function is executed hundreds or thousands of times on a template? What if the function does a non-trivial computation? That would be very slow!

I asked around how AngularJS developers get around this and apparently the best answer is to cache the result of the function yourself in a different variable. But if you do that, you’ve got more than one source of truth for that value. If you ever update the Room’s dimensions, how do we guarantee that the area property will be updated too?

I was pointed to an AngularJS function called $scope.$watch that allows you to watch an expression and execute some code when it changes. The problem is that the $watch function belongs to the $scope and NOT the Room. If you had an array of Room instances for example, you can’t watch them all without looping through them all constantly.

What if the same Room object instance existed in multiple controllers? You’d have to have the $watch in every controller which would mean a lot of unnecessary recalculations. Good luck debugging issues if you take that approach! Talk about a maintenance nightmare!

Reusing object instances

AngularJS makes it much harder to reuse object instances than Ember does. In an Ember template for example, you can link to another route using the {{linkTo}} helper:

<ul>
{{#each user in users}}
  <li>{{linkTo 'users.show' user}}Show {{username}}{{/linkTo}}</li>
{{/each}}
</ul>

Here, we’re looping through a list of users and creating a link to show that particular user. If you hovered over the link, you’d see something like /users/show/123 if your routes were set up properly. However, when you click the link, Ember actually passes the reference to the user through to your other route.

Ember’s router is smart enough to not have to resolve the user by id again if it already has the user object in memory. It just makes use of the object it already has. In AngularJS, every time you visit a route, it passes an id and has to resolve it in your controllers.

One of the great advantages of long lived browser applications is you can reuse objects as the user navigates around. AngularJS doesn’t follow this philosophy; it encourages you to throw away what you already had and find it again (probably from the server!).

Another consequence of this is that if you ever end up with two instances of the same User in memory, you’ve violated the single source of truth again!

Conclusion

I think it’s clear at this point that Angular’s focus on simplicity has some serious consequences. There are workarounds for some of these issues that you can implement yourself in your project with great discipline, but ask yourself this: are all developers on your team going to follow the same conventions? Additionally, if you add all sorts of extra constructs to AngularJS to make it work like Ember, why not just use Ember in the first place?

Due to it’s lack of conventions, I wonder how many Angular projects rely on bad practices such as AJAX calls directly within controllers? Due to dependency injection, are developers injecting router parameters into directives? Are novice AngularJS developers going to structure their code in a way that an experienced AngularJS developer believes is idiomatic?

In fact, what is idiomatic AngularJS? None of the examples or blogs I read through demonstrated how to reuse object instances, for example. Is that just not done in AngularJS applications?

Ultimately, I think you should examine your application’s goals. Do you want to build something that pushes the boundaries of what people expect from the web? Is your application going to be super simple, or do you want to add powerful features and maintain it well over time?

If you’re serious about front end development, I advise you to take the time to learn Ember properly. Once you figure out how all the pieces fit together, you’ll won’t be able to live without them.

Final Note

If you know Angular and I’ve written something wrong here, please contact me to let me know! I’d love to revisit or correct any mistakes or omissions.


Imported from: http://eviltrout.com/2013/06/15/ember-vs-angular.html

#2

Very interesting article. This has put me off of using angular in larger scale applications.


#3

Fabien, if one blog post chanes your mind you should search for another way to make your living


#4

yeah. My general impression is that Angular's ease of use will at least make it a short term winner. Hopefully Ember can find the right way to bring in developers and explain these concepts so that Ember will become the long term winner. Trying to learn Ember has been a bit of challenge for me and I look forward to better guides as time goes on.


#5

(sorry for my bad english) As developer creating a new web app I think the hardest part it to choose what js framework to use. Since I already have some knockout (and a lot of caliburn micro) experience, I ended up going the durandal way. I never used ember and played a little with angular. In my mind (based on all I read about it), angular was nice and easy to start but hard to dominate and ember was complex. After I knew Discourse was made with ember, it make me curious about it - but after this post, ember take the second spot on my frameworks to learn list (durandal still the first, angular third by a long margin).

Now I only need you to write an comparison like this with ember vs durandal :D


#6

While learning Angular I've had great trouble finding out how do something "properly". As you said, there is a lack of central authority when it comes to "the correct way", the idiomatic way etc.

There are scattered best practices, but they barely penetrate the user documentation. An example is the supposed best practice of a read-only $scope [1]. If you go through the Angular docs you'll notice that many of the examples (including on the homepage) read from primitive values directly on $scope. According to the 'best practice', they should be creating proper "object" models on the $scope and then reading from those.

For me, a humble Angular learner, the documentation is my first port of call. And if I can't figure it out, I end up at some sorry StackOverflow thread where most of the comments seem to be people like me figuring out how the hell this all ties together. There are only a precious few amount of blog posts and SO answers that seem to enlighten.

I can't comment on Ember because I haven't delved deep enough yet, but you've convinced me to give it a proper look. I hope greener pastures await.

[1]: http://www.youtube.com/watch?v...


#7

Nice article.
I don't know EmberJS as well, especially since the latest revisions so I will just write about Angular.
I think you nailed it when you said AngularJS is popular due to its simplicity (Although I would argue the 'by google' stamp also help a bit!).

Unfortunately, in my experience, Angular's simplicity won't get you all that far if you plan on writing any non-trivial application (And there are many of them in the realm of the single page applications). I will concentrate on dirty checking, since it's by far the shortcut number 1 that helped make the framework simple and appeal to the mass.

The dirty checking leads to a very scary performance curve: Angular is probably as fast, if not faster than alternatives for simple applications (Btw, notice how most if not all applications in the 'Written with angular' sections are dead simple); For medium complexity applications, you start having to put speed hacks (i.e not using 'idiomatic' angular) and some users will still complain the app lags on their setup; Complex applications are just impossible, angular will just be spending its time dirty checking all the time, leaving your user's CPU burning. The main excuse for not supporting complex applications is that it's "bad UX" (Misko's famous answer on stackoverflow). Come on :-) Some back-office style apps need to display a lot of data at once, some applications are naturally very dynamic (collaborative, or anything with a lot of server pushes). You can have more than 2 buttons and still keep good UX. What's scary is that your app may start simple and become more complex after a while, without necessarily becoming bloated (Sounds like Agile), exploding the capacities of Angular when you needed it the most.

Writing "idiomatic" Angular directives means writing inefficient directives. Just check ng-grid from the angular-ui project (I'm not bashing them in particular, they have some good stuff like the router), it's unusable, even on my top notch laptop if you use more than the 2 columns displayed in the examples.You would have to not care about your users at all to dare use this. So yeah, you *could* just hand write everything yourself and optimize like crazy, minimizing $apply calls, etc, and then maybe you could get somewhat OK perfs. But then a developer chimes in for a simple bug fix and use a function like you showed that does a little bit of string concatenation and is called a bit too many times (just to be sure!) and then your whole screen becomes slow. Sure, you can use the Batarang profiler and constantly keep an eye on what is the bottleneck of the day in your app, but really, a tiny addition in an isolated module shouldn't slow down literally all the features in one given screen.

I have a bit of a love-hate relationship with Angular: With simple requirements, you will have a neat codebase with good-enough performances (Check the todo mvc's angular example, it features the best and neatest html/js combination in my opinion) but then if you work on anything non trivial or target a wide-ish audience (Some may even have slower machines than your dev's 8 cores MAC!!!), mobiles, etc then the dirty hacks comes in and you can't make use of other people's directives because they were written using the "idiomatic angular way" (Basically using a cascade of templates with their own directives) whereas what you actually need is decent speed; Resulting in a bastardized codebase where idiomatic Angular is a forgotten dream (and you still have average perfs)

Nice point about the single source of truth of models. I guess you could mitigate it by extracting the model in some shared dependency but some of your points certainly remain valid. What's the point of using a full stack framework if all the challenges of managing state (A la JQuery app) remain because of performance issues?

I'm afraid Angular's comfortable zone is quickly putting together average applications.

Now because all the above is quite negative and probably expressed a bit too strongly to make a point, I have to leave saying Angular is still a very good piece of engineering and has its uses; Just be careful when you use it; Don't pick it because it's the new fad and has over 10.000 stars on github, but weight the pros and cons of including it in your stack, please.


#8

My approach is api is the source of all intelligence, business logic etc, and clients must act as presentation machines, which have all the UI logic. And for this, I haven't found anything to work better than angular.


#9

I'm going to disagree entirely. I use Angular JS in production mode in a chiropractic clinic with thousands of patients, our application is incredibly interactive and reliant on stats for our doctors which means events are fired all the time (Laravel backend). I built this as a sole developer, once I got the hang of it I LOVED it. You're just bashing AngularJS, and until you build a production application you've got no room to talk.

EDIT:
I replied with a post addressing the issues specifically I that I have with this post. Below.


#10

They two are great frameworks. And each one has its own (dis)advantages. After playing with not only these two, I found that most of all the choice is a matter of developer's personality (or developer's manager personality). In my case, a developer/manager myself, I've been chosing AngularJS over anything else. I may change in the future, if somebody gives me good reasons, which is, data venia, not the case of this post.


#11

Ember is definitely challenging to learn. I can definitely see it being the winner down the road, but right now I really feel like it's lacking in some important areas, mainly *good* documentation and tutorials. As an example, writing complex views in Ember is ( at least to me ) non-trivial, whereas writing directives in AngularJS was relatively straightforward. Most of the tutorials I've seen so far have been relatively easy to follow todo or blog examples, but that's not what most people are going to be writing. On the positive side, I absolutely love how things like computed properties just work and are consistent in their use as you pointed out.

The other big point for me at the moment was actually the lack of a good build process for Ember. Angular's dependency injection and async template support ( if needed ) makes it dead simple to accomplish this since with very few exceptions ( in my case ), it just doesn't matter what order scripts are included in. Since that's not the case in Ember, we're left to our own devices to figure out it.


#12

This is a typical reaction from someone who hasn't used AngularJS to build a complex web app. I would strongly suggest you check out our boilerplate for building complex web apps with AngularJS, which uses Backbone for models and AngularJS for UI and data binding.

http://brandid.github.io/parse...

"In AngularJS, every time you visit a route, it passes an idand has to resolve it in your controllers."

- not true, just use nested controllers and prototypical inheritance to access the already resolved object

"AngularJS doesn’t follow this philosophy; it encourages you to throw away what you already had and find it again (probably from the server!)."

- not true, thats why $rootScope exists

"None of the examples or blogs I read through demonstrated how to reuse object instances, for example. Is that just not done in AngularJS?"

- not true, all scopes inherit from each other, javascript prototypical inheritance applies

"The problem is that the $watch function belongs to the $scope and NOT the Room."

- not true, you can put a $watch on the model if use Backbone for your models

"If you had an array of Room instances for example, you can’t watch them all without looping through them all constantly."

- not true, you can watch a collection of models, and you can do things like watch the length of the array for less processor intensive use of $watch


#13

Nice article. Ember is definetly more flexible and structured at the same time. But is it much faster to built an initial prototype in Angular and this matters a lot.


#14

Thank you very much!. Very interesting post, indeed. Anyway, I get the impression we've already had this discussion somewhere (eg. http://www.quora.com/Ember-js/....

Without a doubt, writing apps in angular *can* be really simple, but, as in any other thing - it's about mastering the hard stuff and being able to comprehend the way it works in a deep level. I don't see this as a disadvantage. People will still have to learn to develop apps following good practices and design patterns and there's no tool taking this burden from them. To be honest, in my personal experience, Ember seemed much less difficult to understand, and despite the fact that I think it's a really great tool (I'm still amazed to see it's progress since old Sproutcore times), after several mid-sized projects in both of these frameworks, I decided to build a really big (>200K LOC) project with Angular. I've chosen it because I think this is the way the web will look like soon, with Object.observe, DOM templates, shadow DOM, scoped CSS and all that sweet ES6/ESWhatever HTML5 goodness. I think Angular is exactly about pushing the boundaries of what people expect from web (think Polymer), but, hey, it's not about tools, but us who want to make the change:) I wouldn't agree with the statement that the purpose of Angular is creating simple things. It just makes it really easy. Always a new, higher layer of abstraction always involves some resistance (think of rewriting Unix from Bell labs with C, or javascript developers in general). The biggest problem of angular is poor or even misguiding documentation. On the other hand - Ember.js has a great one. But still, all frameworks have their limitations, what counts is: how do we approach them and what's the final result.


#15

More Shares, stars and forks don't mean better. I guess it is understandable that if something is easier to learn, more people will follow it, most of them might just need what Angular provides. The relation between complex apps vs simple apps I would dare say will be the same as te popularity of Angular vs Ember.

They both need to exists, we need simple-to-learn options so that eventually people that need more power make the jump, but going straight to Ember might scare more than one developer.

I wouldn't worry about the amount of ppl following or working around them, but more on the quality of their contributions.


#16

At a high level, I don't think either has "won", they are different; not bad, not good, just different. Both Angular and Ember are pretty close in terms of functionality. I'd like to highlight a couple of areas the author talked about for further discussion.

**Models**

I think the Angular teams decision to avoid the use of framework built-in model objects to extend from is advantageous when considering testing and simplicity (which the author covered). Choosing to inherit from `Ember.Object` adds the overhead of needing to know what is going on under the hood when it comes to model objects, much the same way that extending ActiveRecord or any other ORM does.

Having worked with Backbone (and Backbone.Model) extensively for the last 18 months I actually longed for a simpler abstraction; when I encountered Angular controllers and their use of JavaScript primitives as models it was a breath of fresh-air. No overhead to understanding what I was getting by extending some built-in, extreme ease of testability (just inject primitives in tests), and the flexibility to craft my own higher level abstractions if necessary.

**Reuse**

> "One of the great advantages of long lived browser applications is you can reuse objects as the user navigates around. AngularJS doesn’t follow this philosophy; it encourages you to throw away what you already had and find it again (probably from the server!)"

I don't think Angular encourages you to throw anything away; in fact, creating services that are reusable is a core framework feature. Due to simple dependency injection, creating injectable services that, for example, cache results of fetches would be pretty trivial. If anything the general principle of abstracting remote and local data away into injectable services is a huge win for Angular, especially when you contrast it with the relative lack of stability in Ember.Data. ($resource isn't quite up to par, but you can get a long way already with $http and good things are coming in the impending 1.2 release that will help solidify it as a great utility when working with RESTful web services.)

**Encapsulation/Modularity**

Another area where Angular shines is `angular.module` and the idea of encapsulation and modularity built into the framework. It provides some very simple constructs you can use to structure your code to achieve encapsulation, and in 1.2 much of the core framework will all be extracted further into modules that you can pick and choose.

**Performance**

The performance card is often played in posts like these, but I have yet to run into a scenario using Angular where the dirty checking algorithm (and even the use of custom $scope.$watch) has lead to significant overhead.

Overall I think the reason Angular has more developer mind-share at the moment boils down to the things it places importance on abstracting; treating interacting with the DOM as a core framework feature, Angular acts like middleware to relieve developers having to do manual updating we've become so used to in the world of simple jQuery, and the manual "wiring" of those updates that we do when using Backbone.View and Backbone.Model. The separation of `declarative` markup and `imperative` application code that Angular implies is, in my opinion, the best way to separate concerns when building rich-client applications.


#17

From what I've gathered the best way to handle data is to package it up as a service, and use that service between your controllers.

Using something like

app.factory("RoomService", function ($rootScope){})

then use $rootScope.$watch() to watch for changes inside the service instead of within your controllers.


#18

The fact that you "LOVED" it is anecdotal nonsense at best. Also, welcome to the internet; everyone here has room to talk. If you think Robin is wrong here, by all means point out the mistakes... it adds to a healthy discussion.


#19

That would work, although it does seem a little awkward to set up the computation outside of its domain (the model.) Additionally, it doesn't protect something from overwriting area. It would be harder to go out of sync, but it's not impossible.


#20

"I downloaded AngularJS and made simple applications."

I think you misunderstood my context. I was referring to the subject of building complex / mission critical applications in AngularJS which he has no knowledge of but then claim that the comparison is not even close is ridiculous. He doesn't have the experience to make a claim like that.

With his extensive background in ember and only making something simple in AngularJS, This is just someone who has used something for so long that when something different comes along there is a dislike because it's different than how you're used to doing things.