Over the past several months we’ve been developing a micro-framework to drive HealPay’s newest changes. The web is trending towards “rich internet applications” and we decided that in order to provide the best user experience, we’d jump on the bandwagon as well.
This has many implications for our architecture:
*Scale better as we “dog food” our API using the framework
*We will be faster as we’re pushing a lot of the logic to the client (browser) and time spent on the server side of the request cycle will speed up tremendously without having to rely on rails helpers to generate html.
*By saving state in the client, we can support offline and anonymous sessions with greater ease across the application.
In order to accomodate this architectural shift, we needed to either leverage a pre-existing client side micro-framework, or create our own. There are actually several pretty good contenders out there, but none of them quite met our requirements.
Backbone.js: This micro-framework was on the top of our list to evaluate. Of all the other frameworks, it came the closest to meeting our needs, but fell short for a few reasons.
*Lack of associations – We had a need to nest several objects into one request and associations seem to be the best solution for this. Backbone js has the concept of collections, but these collections have no way of managing nested object trees. We needed to manage a top level invoice, which had many contacts, many line items, possibly an attached deal which also had many options. Backbone had no way to save this sort of object in one request without overriding the default toJSON behavior of which we wanted this functionality to be native.
*No single object sync/save – We liked the idea of being able to call invoice.save() without having to save on the collection. Backbone’s philosophy is that you rarely need to call save() on an individual record, and that your syncing usually occurs on a collection. We beg to differ.
*Views are a bit overkill I think for what we need them to accomplish.
Sammy.js: Is missing a model layer which was pretty huge for us because of the reasons already mentioned previously.
Sproutcore: The framework is a bit overkill for what we wanted, which is why we liked backbone to begin with.
js model: Is actually a decent model abstraction layer and well thought out. We borrowed some ideas from js model for our model layer, and also borrowed some of the bits we liked from backbone. js model alone wasn’t sufficient for our needs because we weren’t entirely pleased with the API and each class only maintains one collection at a time. This makes it easy to do lazy collections enhancements but we wanted to be able to management more than one collection per model at a time.
Since none of these frameworks did quite what we wanted, we created our own and it has served as well so far. It is able to accomodate our new RESTful API, it has sped up some of the requests in our app considerably as we offload the server-side view logic to the client, and has given us the ability to store the entire state of our objects on the client which will enable us to pursue the cool features we intend to implement soon (like auto-save).
Much like backbone js, we let you define models and helper methods on those models for use in your views (almost like a display object), but we also included associations. Now, when a call to invoice.save() happens, it includes all of the nested objects like contacts, line items, etc.
We also provided the ability to save outside of a collection, and on an object by object basis. Additionally, we established a new convention for routing javascript logic and organizing view logic.
If you’d like to check out the project in more detail, visit the project home page!
~@healpay