Wednesday, October 5, 2016

Guarding Ember's computed properties

Sometimes you hunt a bug that just won't show. It just literally won't allow itself to be found. Recently I've had one of those cases. This time it was just unimaginable what has actually happened. Someone, possibly by mistake, has overridden an Ember.ComputedProperty thus breaking the chain of updates. On top of that the app did updates to the model using websockets changing other properties of that model. This resulted in very strange flickering of values in an edit field. Very hard to diagnose.

After the bug was fixed I started looking at possible ways to guard it in the future and possibly to find other places where the same happens. There are 2 cases where this might happend:

  • using this.set('property', 'value');
  • using Handlebars template

One possible solution would be to reopen the Ember.Object class and to override the Ember.Object.set method. Unfortunately it only guards you from explicit calls to this.set(...) and all the overrides from Handlebars template remain silent.

But there is hope!

There is another class, Ember.ComputedProperty that is actually used as the tool to get and set computed properties. It also features a set method that can be monkey-patched to do our check:

(function() {
  var orgSet = Ember.ComputedProperty.prototype.set;

  Ember.ComputedProperty.prototype.set = function(obj, key) {
    if (obj[key] && obj[key]._getter && !obj[key]._setter) {
      console.error("Overriding computed property " +
        key + " on " + obj._debugContainerKey);
    return orgSet.apply(this, arguments);

In this way if you override the computed property in a handlebars template or in the code you'll know about it. I only wish this would be part of the core framework. It would shave about 10 mandays of my project...

Here is an example project with the fix applied.

Have fun!

Edit on October 6th, 2016

I have been made aware of an Ember addon by Stefan Penner that addresses the same issue called ember-improved-cp. Although the idea of not using private API of the Ember.ComputedProperty is nice using that plugin is invasive and means using addon-provided macros instead of those that are provided straight from the framework which adds to the already high complexity of Ember-based projects. If you have a small enough project with few developers and you can afford that inconvenience you should probably go with the addon. If you need a plug-play-unplug solution you're going to get where you need to be with the monkey-patched version of Ember.ComputedProperty.prototype.set much faster.

No comments: