Tuesday, June 5, 2007

Code Modularization and CSS Queries

On his personal blog, YAHOO! front-end engineer Nicholas Zakas takes on the prevalence of the CSS query engine in client-side JavaScript libraries. The flexibility of some other quick syntax shorthand for accessing HTML elements and describing structure without using the conventional DOM methods has always appealed to me, so I wasn't sure what he was missing.

Granted, the recent proliferation of JS libraries in general (and query engines in particular) has been rather excessive, no doubt tracking a boom and bust path. I'm a fan of all of these efforts, though I wouldn't use most of them myself - they represent attempts to impose order onto the chaotic soup of client-side code that we've been dealing with since 1996. Each one - Prototype's dubious extensions to native objects, jQuery's wrapping of DOM elements and telltale method chaining, Mochikit's Python-like syntax - represents a new experiment in turning the best approximation we've ever had to a cross-OS, open-source application platform - the web browser - into the full-fledged application framework it's destined to be. Even if not all of these attempts have been useful, they've at least been instructive.

After reading his replies to comments to his post, and after an informal conversation with Joel Webber at the recent Google Developer Day, I realized that client-side techniques vary widely across organizations.

At Zillow, for example, we go to great lengths to separate our HTML, CSS, and JavaScript. Since our site is fairly complex and design-heavy, and code iterations happen with such frequency, this modularization is key to keeping sane. So we have a set of rules we follow:

  1. All pieces of client-side code have a well-defined means for interacting with each other. For CSS -> HTML, it's CSS selectors. For JS -> HTML, it's the DOM. For JS -> CSS, it's classnames. For HTML -> JS, it's the DOM events model.
  2. Do not mix HTML, CSS, and JavaScript. No inline styles, no inline event handlers, no creating elements via JavaScript.

You see where I'm going with this - HTML, CSS, and JavaScript are to exist independently of one another and "flip switches" rather than assemble by hand. For the same reason you wouldn't write code like

function makeBoldRed(el) {
    el.style.fontWeight = 'bold';
    el.style.color = 'red';

but rather

Element.addClass(el, CSS.ERROR_MESSAGE);

I prefer to use CSS-style selectors to fix the gap, and allow JavaScript to refer to HTML using the same syntax that its presentation counterpart does.

However, it appears that some large companies are generating HTML through JavaScript. This can work too, but in this case your goals are going to be much different. Once you start working this way, you risk accessibility and graceful degradation. You also lose the ability to develop and test presentation-layer components independently of one another, and this can lead to a poorer design or, at the very least, longer development and testing time. Another problem is debugging; if you start permitting your script to tinker with your HTML, or if your script depends on a fixed HTML structure to function properly, design changes can lead to interminable headaches when a complex script's dynamic change to the DOM structure goes undetected.

Sure, CSS queries can be performance bottlenecks. But usually they aren't, at least not when you're using a throughly-tested engine such as are available in the major JS libraries. A minor performance hit - most query engines can perform the most complex queries in under 5 ms, depending on your machine - is a small price to pay for the flexibility of modular code.

On a side note, I was most intrigued by Joel Webber's description of the Google Web Toolkit's function: to add a compile-time step to optimize and inline JavaScript code. I can appreciate that. Certainly, a well-written compiler will be able to optimize code to a greater degree than a meticulous programmer. But why Java? Why apply this essentially alien style of programming to the client? This question remains outstanding for me.


Isaac said...

Generating HTML through Javascript *can* be a way to reduce the size of the Dom that needs to be loaded by non-JS users. Or, at times, it's just the simplest and fastest way to re-build a node's contents after an XHR call. Or it can simply be the easiest way to jimmy a hack into place late in the project. (I've done it for all three reasons. Only the third one made me feel dirty.) The question of where to draw the line of separation between layers is a judgment call based on a lot of factors. (Mostly, I agree with you.)

As for Google's generation of client-side code via Java, the only thing I can think of is that they just have a lot of Java engineers and not as many top-notch front-end developers. From the point of view of managing the chaos of software development, it kind of makes sense for them.

Carmel said...

Well said.