Joe Ray

Software and Infrastructure Development.

A little less magic

This is a draft post. Please do not share widely until this message has disappeared.

Lately I’ve been evaluating Javascript frameworks at the same time as I work on a REST API for a side project; eventually the plan is to use the API to back a fancy JS web app and so by looking at the functionality of the JS frameworks I hoped to identify some of the API’s requirements. Based on the work Jeff Atwood, Robin Wood and the rest did on Discourse, I was most taken with Ember.js (Robin explains why Discourse is using Ember.js and I was impressed by many aspects of the implementation of Discourse) and so the output of the API was being inspired by the Ember Data module.

However, as I delved into the Ember.js code to learn about how the Data module mapped API output to Ember models (the documentation isn’t too explicit about all the different cases) I came across a bit of code which made me wince:

classify: function(str) {
  var parts = str.split("."),
      out = [];

  for (var i=0, l=parts.length; i<l; i++) {
    var camelized = Ember.String.camelize(parts[i]);
    out.push(camelized.charAt(0).toUpperCase() + camelized.substr(1));
  }

  return out.join(".");
}

Now, given that Ember.js was inspired by Ruby on Rails, amongst other projects, this bit of code isn’t that surprising. It’s pretty simple code - it takes the lower case, dotted, underscored name of a class and converts it to a CamelCased, dotted version of the class. However, what made me wince was that it needed to exist at all.

Back when I first started getting into PHP for reals, I worked on a site that had its own custom framework. (The framework was partly a ‘because we can’ exercise - we were students at the time experimenting with design patterns etc.) Its model layer was inspired by Rails' ActiveRecord implementation. As such, it did magic mapping of table and field names to class and property names and used a bit of code very similar to the one above. For our project’s purpose, having the model layer dictate the database design was no big deal - we designed the database along with the model layer and we were the only ones using the framework anyway. The trouble was, all the magic that was required to get PHP to do all of this dynamic mapping kept on biting me when it came to designing other parts of the system.

Not long after, I wrote a couple of projects in Django. I really liked the way it didn’t dictate to you - you write the application you want to write. The model layer, for instance, requires you to explicitly specify each attribute on the model and how it relates to the database and you’re able to override the names of each field and table that the classes and properties map to on the database. Don’t get me wrong, Django has a lot of magic going on behind the scenes to hold it all together, and that magic has confused the hell out of me when I’ve needed to unpick it, but it hardly ever gets in the way of doing the things you need to do most frequently in the way you want to.

And so back to Ember.js. The classify function is used by the object store to map developer-friendly names to class names, including identifiers in API responses. When ‘sideloading’ related models to improve client-side performance, the expected response is something along the lines of:

{
    'blog': [{
        'id': 1,
        'title': 'Blog one',
        'author_profile': 1
    }],
    'author_profiles': [{
        'id': 1,
        'name': 'Jane Doe',
        'blogs': [1]
    }]
}

It’s fairly easy to override the expected field names, pluralisations etc. using customisations in the serializer but wouldn’t it save a lot of code if you just specified this manually for each model?

Framework authors, please do us developers a favour. Use a little less magic.

Contact Me

I love a good conversation! E-mail me (encrypted if you want) or find me on Twitter, LinkedIn and GitHub.