On Javascript architecture

On Friday I spent some time reading through an article that Wayne sent me by Addy Osmani about how to organize non-trivial Javascript applications. This is a timely issue – it’s been really interesting to watch how a lot of my early architecture decisions in Neatline have panned out over the course of the last six months, and I’ve been trying to settle on an approach for the front end of Exquisite Haiku, which, to my delight, is becoming a more and more pressing issue as the server-side development rapidly approaches completion.

As I see it, there’s a fundamental (and to some extent indissoluble) tension in Javascript architecture between an impulse to modularize your code much as possible and an effort to make the various components of your code communicate with one another in a straightforward, low-overhead, and low-maintenance way. By modularization, I mean, essentially, classes, in the actual sense of the concept. Even though most server-side development frameworks can claim to be “object oriented” to the extent that application code is generally subclassing the framework-provided master classes for the various pieces of the puzzle (controller, database table, database row, etc.), the actual classes that you write as a developer are, in fact, singletons – they’re concrete pieces of code designed to do a single thing (to be an application, and no other), and can’t be reused in any kind of meaningful way.

In Javascript development, meanwhile, there’s a strong sense in which you can actually practice classically-imagined object oriented programming, even though, paradoxically, the Javascript object model is so peculiar and warty. Think of the whole jQuery “widget” pattern – you can write completely abstracted little chunks of code (usually, taking some permutation of options or parameters) which then graft a functionality onto some minimally-patterned markup structure. Custom scrollbars, drop-down menus, form widgets, etc. There are really significant advantages to this development pattern – when written well, the widgets can be completely isolated from any surrounding application code while still being configurable enough blend into the design and interaction patterns of the application. They can also be unit tested, although that almost never happens.

This pattern has been abstracted upwards to form a general development philosophy for Javascript applications – large programs are written as an assemblage of modularized chunks. Intuitively, this makes sense. When you look at a web application (or even just a wireframe of an application), it’s easy to slice and dice things into tidy little buckets. With Exquisite Haiku, there’s the poem, the rank stack, the churn stack, the word search box, and the countdown timer across the top of the screen. Each of these things begs to be broken out and written as modular code.

The problem with this, though, is that even though these chunks are conceptually modular, in practice they have to communicate with one another, often in really high-volume, complex, and functionality-critical ways. When a user mouseenters on one of the words in the rank or churn stacks, the word should appear, grayed out, in the blank space at the end of the poem that represents the position of the currently-being-selected word. So, when the mouseenter event gets triggered inside of the modularized code for the word stack, the stack needs to dial out and make the poem rendering module aware that a word has been highlighted, and needs to be rendered on the poem.

As a rule of thumb, the mode modular and silo-ed up your code is, the more complex and tangled the “wiring” code that handles the web of crosswalks that needed to glue everything together. Neatline is a good example of this. The Neatline front-end application is engineered as a series of jQuery widgets that are instantiated in a series of hierarchical “stacks.” The “item browser” widget manages the vertical pane of records in the editor; it, in turn instantiates and manages an “item form” widget, that takes care of the display, data loading, and data saving functionality of the form itself (which in turn instantiates and manages about 15 small, UX-focused widgets that add functionality onto the form – text editors, integer draggers, color pickers, the date ambiguity slider, etc.). This whole stack of nested modularization is kicked off in the constructor script for the editor, which acts as the base-level piece of code that turns the ignition key and gets everything started. This code also instantiates the Neatline exhibit itself that sits next to the data entry interface in the editor – the “neatline” widget instantiates separate component widgets for the map, timeline, and records browser pane, and each of these widgets in turn runs a series of still-smaller modules that manage editing interfaces, zoom controls, ad infinitum.

There’s a good reason for all of this – the Neatline exhibit application needs to work both inside and outside the context of the editor. It has to be totally cordoned off – but still accessible by – the code that handles the editing functionality. What this means, though, is that the process of passing messages from, say, the item form widget to the map widget is excessively complex – the item form widget issues a _trigger('eventname') call, which trips a callback in the parent widget, the item browser; the item browser then immediately (re-)issues a _trigger('eventname') call, which trips “bottom-level” callback in the constructor script. This callback then issues a chain of method class that ascends back “up” the exhibit module stack – a “piping” method is called in the neatline widget, which immediately calls a terminal method in the map widget, which actually manifests the necessary change. This is chaos – mountains of callback code is necessary to pass messages through the system when the sender and receiver are both very “high” up in different module stacks.

At the same time, this decoupling comes along with enormous advantages – it means that the Neatline exhibit application is extremely flexible, and can be wired up for use in a huge range of environments. The challenge, as I see it, is to find a way of preserving this flexibility and meaningful modularity while still being able to pass messages along the structural “hypotenuses” in applications – from peak to peak, as it were, without having to descend into the valley. I’ve been playing with some ideas for how to go about this, and I plan to use the Exquisite Haiku front end as a sandbox to try them out.