Tuesday, February 25, 2014

Why you shouldn't choose Spine.JS

This is really for my own benefit... something to remind me of the reasons why I shouldn't ever choose Spine.JS over other client side MVC frameworks. Shoot me a comment if you'd like to add to this list.... In order of importance:

  1. Its Backbone's red headed stepchild. Just chose Backbone
  2. Their AJAX mixin to models sucks. It relies on events thrown from globally accessible objects, rather than callbacks and / or promises to complete async actions. This introduces a layer of indirection, and potentially messy code. In small apps, this could be acceptable, but not for larger apps. 
  3. Configuring URLs to retrieve model information is strongly opinionated, and difficult to override. REST principles are enforced, an any deviation from these are problematic. Should a model be loadable from multiple urls (i.e. Person model list loaded from http://my-app/friends, and http://my-app/friends/1/friends), there is no easy way to implement this contextual switching without implementing your own ajax module.
  4. Its collection helpers (i.e. find, all, fetch, select etc.) clone models before returning, which can be very cumbersome as the model you have retrieved is not the same as the one you set. Adding models to the cache is also annoying, as a call to save() is required. However, in calling this, a bunch of logic gets executed that you might not want to be executed, such as the assigning of an id, or throwing of 'create', 'save' events etc. Quite often you just want your models to be stored in an accessible collection in the state that they are in. Its probably better to do this in your own managed collection, rather than via Spine's cache. So really - whats the point of them?
  5. Due to this cloning, the models are cumbersome. Every property added to a model must be declared as an attribute or configured.
  6. It uses global collection helpers, and caches (i.e. MyModel.all). This sounds wonderful, and on small apps its handy. But for a sizeable app, this can get nasty as if the developer is not careful it implicitly introduces an unwanted level of state into your application.


4 comments:

scvs_rule said...

+1000

#2 - there is no concept of asynchronous operations outside of events.
item.save() doesn't take a callback. Doesn't return a promise. Your only hope is listening to events. This sounds nice, but beyond a few events creates such a spiderweb of code that'll leave you swearing.

You'll have the same problem with 'controllers' which assume the world is flat & information is instant. Want a dynamic route such as #/item/12 ? Ha! See how long it takes you to work out the workaround for that one.

Spine is nice for very small apps. Anything beyond that is a fail.

jelly said...

awesome function, thanks for this!

i had some jshint warnings so i modified it a bit to get rid of them:

https://gist.github.com/amnah/9656661#file-saferead-after-jshint

var safeRead = function() {

var current, obj, prop, props, val, _i, _len, read;

obj = arguments[0];

props = (2 <= arguments.length) ? [].slice.call(arguments, 1) : [];

read = function(obj, prop) {

if ((obj !== null ? obj[prop] : void 0) === null) {

return;

}

return obj[prop];

};

current = obj;

for (_i = 0, _len = props.length; _i < _len; _i++) {

prop = props[_i];

val = read(current, prop);

if (val) {

current = val;

} else {

return '';

}

}

return current;

};

jesalg said...

This is great, thanks!

Akash Kumar said...

any idea how to work with Gmail Api ?