Saturday, December 17, 2011

Backbone.js is making client-side development fun (and maintainable)

I have been using Backbone.js to develop client-side web applications for a while now. I decided to write about my experiences in the hope that it will help others gauge whether it is something they should consider adding to their toolbox. This isn't a tutorial -- it's just my story as a web developer, and it describes some frustrations I had that Backbone.js smoothed over.

I had been using jQuery happily for a couple years when I came to the realization that something just wasn't right. I noticed that with each new JavaScript-enabled feature I added to a page, the difficulty in maintaining that page would rise disproportionately.

It wasn't problematic to add client-side sorting for a table, or form validation, or popups and tooltips here and there. But when I implemented Ajax-enabled CRUD or complex interactions things would quickly spiral out of control. Eventually a single page could have many different kinds of elements with primary keys from the database in their HTML id attributes. The HTML would become bloated and the line between styles and identifiers for use by my DOM selectors would get very blurry.

Meanwhile, my JavaScript code would be growing larger and larger without any kind of organization. Finding out where I set a particular event handler required me to wade through hundreds of lines of code. Browser consoles helped, but it's frustrating to routinely resort to setting breakpoints and stepping through code in the debugger just to comprehend what was happening where.

After repeating this scenario one too many times I realized (or at least hoped very strongly) that there had to be a better way. I looked for ways to reorganize my jQuery scripts, in the hope that it would at least solve that aspect of my troubles. What I discovered in my search is that I was going to have to finally learn the fundamentals of the JavaScript language before I could assess my options. With frameworks like jQuery it's fairly easy to learn the API and follow by example without truly understanding the underlying language itself.

I began relearning much of what I thought I knew about JavaScript. I started with the basics of the language and corrected a lot of my misunderstandings. Things that previously seemed mysterious to me about certain aspects of jQuery were explained. To this day I am still learning more about JavaScript/ECMAScript, and I feel that gaining a deep understanding of it is a worthwhile endeavor for anybody building web applications. Learning how prototypal inheritance works is the big hurdle, but it is key to unlocking the language's full potential.

As I learned more about JavaScript I applied techniques that helped me organize my code in ways that made it easier to read and maintain. I started using the module pattern and namespacing to organize my applications. I found these practices to be useful, but still far from my hope of a silver bullet. I kept experimenting with new organization techniques until a colleague of mine mentioned Backbone.js.

The Backbone.js site describes the project as follows:
Backbone supplies structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.
That's quite a mouthful. It sounded powerful, but also quite complex. I was intrigued, though unsure of what exactly I was getting myself into. I read through the rest of the site, which includes samples and descriptions of each of its features. They are concise and pretty easy to understand, but afterwards I felt that I still didn't understand the big picture. I moved on to the official example TODO application but found it to be somewhat difficult to digest.

I read over several introductory tutorials until I had a solid understanding of the core concepts of Backbone.js and how they relate to each other. My frustration at that point was that each example seemed very clear in isolation but many of them varied in the way they handled similar problems. This confusion seemed to be a common theme for people who were learning the framework at the time.

It took me a while to fully accept the extreme flexibility of the framework. Only after I accepted that did I begin to feel comfortable during the learning process. Another reason the initial digestion period can be frustrating is that using Backbone offers several features but forces you to use none of them. You could forgo routers, models and collections, and only use views if you wished. Most of these features are decoupled and can be added in one-by-one.

Backbone.js effectively solved all the frustrations that drove me to find a better way to develop client-side web applications. I no longer store primary keys in my HTML id attributes. Instead I use Backbone's views and models together to handle record-level events and render the record's current state. This helps me keep my styles and application code almost entirely separate.

Where I used to write procedural JavaScript in huge blocks, it's now object-oriented and modular. The code is easier to read and more organized. The other benefit is that my code is more reusable. As my applications grow larger this benefit is amplified.

In general, client-side development is a lot less frustrating using Backbone.js. I spend much less time tracking down the location of bugs. If something is not working properly I can almost always immediately isolate the model or view that is responsible for the feature that is not working as expected.

Something you may miss when considering Backbone is the value of its helper library Underscore.js. During the process of learning the core concepts of JavaScript I realized that it has some rough edges. Those rough edges can make seemingly simple tasks rather verbose (when done correctly) and prone to error. Underscore.js provides a series of functions that can be used to smooth out these rough edges and speed up general JavaScript development. I find myself using these functions more and more over time, and would absolutely use Underscore.js by itself in any sizable JavaScript application even if it wasn't using Backbone.

I used to struggle to decide if my server-side code should respond to Ajax requests with JSON or with HTML. JSON was a cleaner exchange, but the tradeoff is that I had to do ugly and messy string concatenation in my JavaScript callback function.  With Underscore's template function I am able to have the best of both worlds -- JSON data exchanges and HTML templates. While JavaScript templates are not a brand new concept, it's one that I adopted when I started using Backbone.js and now I can't imagine doing it any other way.

If you are interested in Backbone.js but are having trouble understanding how it is different than traditional jQuery-heavy web applications, here's the way I would describe the difference: While your application will still be event-driven, its state will reside in JavaScript objects rather than in the HTML/DOM. You won't have to push/pull data from/to the DOM in order to retrieve and store state between events. When your data changes, affected portions of your display can be notified and will update independently to reflect the current state.

Following are links to resources I found helpful:

No comments:

Post a Comment