A Year and Some Later...

I like Ember, but with some reservations - my own personal weirdness reservations that I'll go into in a bit. I finally "got it" and it took some doing. Maybe my brain's slowing down or I've been doing this stuff for too long but my brain just doesn't work the way Ember wanted it to.

After a few key insights, however, the light went on and it was all downhill after that. Once that happened I was completely stunned by what I could do with Ember, and how fast I could do it.

Here are those insights, if you need them.

First Thing: Yeah It's Not MVC, But Who Cares

Ember, like Angular, like Knockout and any other framework on the client is MVVM. This might sound pedantic or nitpicky - but it really isn't!

MVC assumes a lot of things and if you're a web developer you instantly have an idea of what a Controller should do with a Model and a View. Toss that out of your head.

Ember was built with Cocoa in mind - like you're building an iPhone app. If you've ever done that, you know that every View is backed by a Controller directly, which may or may not have some data.

This is the key: Controllers in Ember are actually ViewModels in the MVVM sense - but they're called Controllers because the team wanted to keep with the Cocoa thing (apparently). Makes sense, I spose.

Why is this important? Because names are important and so are software concepts. Controllers as ViewModels unlocked a WHOLE BUNCH of goodness in my head - and it made Ember click for me.

Second Thing: Ember Loves Promises

This one might seem obvious, but only after you read through the docs in frustration. I wanted to use jQuery with Ember and one would think I'd be able to do something like this:

var myRoute = Ember.Route.extend({
  model : function(){
    return $.getJSON("SOME_URL", function(result){
      return result;
    });
  }
});

If you know Javascript then you know this won't work - returning out of a callback means ... pain. I get that - so what do we do here? Well, here's one solution:

var myData = {};
var myRoute = Ember.Route.extend({
  model : function(){
    $.getJSON("SOME_URL", function(result){
      myData = result;
    });
    return myData;
  }
});

And that works. Sort of. Not really it actually works once then never again. It's at this point you hit the docs trying to figure out what's going when all of a sudden...

In general, Ember's goal is to eliminate explicit forms of asynchronous behavior. As we'll see later, this gives Ember the ability to coalesce multiple events that have the same result.

It also provides a higher level of abstraction, eliminating the need to manually register and unregister event listeners to perform most common tasks.

(blah blah blah architect-speak blah blah)

So, translating the rest of this for you: Ember likes promises. This means that you can just return a promise and Ember will do the rest:

var myRoute = Ember.Route.extend({
  model : function(){
    return $.getJSON("SOME_URL");
  }
});

By "do the rest" I mean that Ember will queue and cache these promises so they are executed in the order needed. You could have 3 or 4 nested views, one inside the other, and Ember is smart enough to grab the outermost promise, wait for it to return, and proceed on down into the nested stuff.

This... is wonderful. It blows your mind to see it in action. Great stuff, all the way around!

Third Thing: Ember's Testing Story is Dreamy

Like most of the Ember API - getting testing setup is a matter of incanting the right magical lines of code to move mountains. Once you do, however, you have a testing experience like no other.

//UserAdmin is my Ember App
//First, I need to setup my app for testing, telling it where to render itself
UserAdmin.rootElement = "#qunit-fixture";
//then I need to setup my app for testing
UserAdmin.setupForTesting();
//then I need to setup my app for testing again
UserAdmin.injectTestHelpers();

Ember has a slew of test helpers that ship ready for QUnit and all you need to do is drop those on your app, which I did above. Next, you have to start your app up before the tests can run:

module("Home Page", {
    setup: function () {
      //reset caching etc for each test
      UserAdmin.reset();
    }
});

Now that we've done that, let's do an integration-level test. I love top-level stuff like this and, in fact, it's the only testing I really do for client apps. Here's a test for the home page:

test("Displays a list of links", function () {
    //the stuff to do 
    visit("/");

    //when stuff to do is done...
    andThen(function () {
        //analyze the DOM
        var homeList = find("#home-list li");
        equal(homeList.length, 3, "There should be three items in the #home-list");
    });
});

You instrument what's to happen at the top, then in the andThen callback you use jQuery to analyze the rendered DOM. Very, very simple and I love how the team has made this accessible for everyone.

Fourth Thing: Insistence on URLs for Routes

Routing is not a primary concern with other JS frameworks (Angular, Backbone) - you can do it, but it's not all that central and it's not required.

With Ember, the URL is everything, and all flows from it.

I didn't fully understand this until I saw Tom Dale on stage at NDC 2013. Tom's a great presenter and it's a fun watch - I highly suggest you take the time to see him in action.

Anyway - once I understood just how much Tom likes URLs things started to make more sense conceptually. In fact it helped me to come up with an incantation when creating an Ember app:

  • URLs describe the state of your app
  • URLs want a Route
  • A Route wants data for the model
  • A Route sets up a Controller
  • A Controller backs a View

Understanding the relationship of URLs to Views was key for me. Traditional event-driven frameworks (like Backbone) rely on changes in the state of a given model to effect change in the UI. Ember does this the other way round - the URL dictates the state of the UI.

URLs map to "Routes" (which really should be called RouteHandlers) which then grab some data, prepare a controller, and render out the view. This simple concept is wonderfully elegant once you get the hang of relying on URLs so heavily in a client-side app.

Some Reservations

There are other things I dig about Ember - but the four "a ha" moments above were the key for me. I'm not a very good programmer so it's likely all of this already sinks in for you - it didn't for me. At least not immediately.

All of that said, I still have some reservations about Ember - and these reservations are completely from my own weirdness. I'm sharing them here because I think a bit of balance is important. It might sound like I'm being negative, or attacking Ember - far from it. I like Ember so much it's making me question just what I like about it!

First Weirdness: Ember Does Almost Too Much

I know, quite the complaint isn't it? Here's what I mean: there's a reason I don't use Wordpress for every site I build - primarily that's because I don't know PHP but it's also because I don't mind writing code to do a thing.

This is a hotly-debated topic in the developer world: how much do you want a framework to do for you?. In the beginning, the more it does the happier you are because you have rather immediate results - think Rails' scaffolds and Angular's slick ng-repeat demos with no Javascript.

As time wears on, these big frameworks make themselves felt more and more. I've been running/maintaining a Rails app for the last 4 years and the thing is a monster! Files everywhere and models that bleed into each other with modules on top of modules that extend models with observers using callbacks to fire triggers in the database.

Yuck - and yes I know it's all my own doing - of course it is. Which is my point - wrestling with these large frameworks sometimes backs you into the corner of suck and by "suck" I mean that I suck. Your knowledge of programming ebbs in favor of knowledge of pushing the framework around.

Which puts us in Wordpress land.

I can build just about any Wordpress site with a set of plugins and a bitchen theme. The database is extensible and the basic Wordpress site has just about everything I need.

So why don't we all just use that, then? That answer you just gave yourself - I have a version of that with regards to Ember.

As I was working along building out the demos which I'll tell you about in a second - I realized that I'm not really writing code, I'm telling the framework what to do for me. Honestly I don't think I wrote a single line of pure Javascript during the whole experience. Does that matter? I'm not really sure.

At what point to I call myself a developer vs. an Ember Developer?

In the Ember video I just finished for Pluralsight (that's where all of this is coming from), I interview Tom Dale about what I built with Ember and I said this to him point blank:

Ember does a lot, should I be scared?

His answer was brilliant (paraphrased):

Working with Ember is like using Excel for the web. You simply plug in the data and tell Ember how to display it - same way you do with Excel - plug in the data, color some cells, write a formula or two.

Interesting point.

So, to summarize - this isn't a critique of Ember so much as a confession of my weirdness. I'm not comfortable with where Ember ends and I begin. BUT, having said that, my job is to create value for my clients so... Ember "Excels" at that, just like Wordpress would "Excel" at that.

The API Makes Me Feel Like It's 1982

This, again, is all me. I love APIs that are expressive and simple to grok. I fell in love with Rails for this exact reason - it's expressive because Ruby is expressive. C# and .NET are verbose but even then you could find out how to trim a string by exploring the System.String namespace.

With Ember, we have these things:

UserAdmin.UserChangerolesController = Ember.Controller.extend({
    needs: ["user"],
    user: Ember.computed.alias("controllers.user"),
    roles: function () {
        return this.store.find("role");
    }.property()
});

Now, if you know Ember this all makes sense to you. If you don't, it will take some time to understand what these things are and why they're there - which is what I'm about to explain.

In Ember a controller can use another controller and you need this quite often, usually with parent/child or master/detail setups (UsersController and UserController).

You specify this with needs and the name of the controller. This allows you to access that controller using an alias - which you can ask Ember to make for you. In the example above I'm saying "create a user property that aliases the user controller". This is just something you need to memorize.

Finally - the .property() thing means "return the result of this function as a property that I can use in my view".

The only way to describe this API, to me, is "wonky". There's a ton of magic going on here which is wonderful stuff - but the only way you'll get deft wid it is by memorizing the incantations.

Yeah yeah I know: programming is hard.

Summary: I Really, Really, Really Like Ember

I created two applications to try out Ember and once I came up to speed, I was thoroughly impressed. The first was a simple Github Explorer where I could see a list of my favorite users and drill into their projects, see the issues, change sets, etc.

I think that one came in at about 90 lines of code, total.

Then I created a User Admin Application for ASP.NET MVC 5 using Web API and the built-in OWIN security stuff.

Again, right around 100 lines of code.

And I recorded all of it - as well as code reviews with Robin Ward and Tom Dale in my typical style: some slides, a lot of "over the shoulder" stuff, and some light opinion. It should be out on May 29th.

Ember's power was palpable - and adding new features started to flow once I climbed the learning curve - which as I stated above means memorizing a few weird API things.

Ember is testable, fast, and the support you get online is remarkable in and of itself. The community is very helpful (for the most part) and overall I had a great experience developing these two apps.

I had a great time and yes, Ember no longer confuses me.