DOM = Frame buffer

If you’re writing a large-scale AJAX application, is it okay to write code like this?

if (jQuery("#file_menu").is(":visible")) { ... }

No, it’s not okay at all. The problem is relying on the DOM to store your program’s state. We want to argue that, despite its tree structure, the DOM only encodes your application’s output — and not its semantics.

Desktop Metaphor

Think about programming a desktop application. Your program keeps track of state using objects in memory. If you want to know whether your program is currently displaying a certain UI element, you don’t check if Screen.getPixelColor(519, 872) == "#000000" . Instead, you rely on objects in memory with the proper semantic structure, writing something like Menus.activeMenu == Menus.FILE .

The most fundamental principle of elegant code is to write what you mean. Do you ever really mean to know the value of a pixel on the screen? No, what you really mean to do is know which UI element is displayed. That’s why you build levels of abstraction into your programs, like the Menus object in the example. If the programmer has intentions about menus, then the line of code should talk about menus. This kind of proper abstraction is what separates the master programmers from the simple-minded “get ‘er done” hackers.

Applying it to AJAX applications

Everyone understands why you shouldn’t rely on pixel values to store your program state. But almost no one understands the analogous rule for AJAX applications: Don’t use the DOM to store your program state.

People are confused because the DOM’s significance has done a 180 since the days of static web pages. In the old days of static HTML and CSS, you would “separate style from semantics” by writing your HTML to manifest the semantic structure of your layout. You would use nested tags to encode parent-child relationships between parts of your layout. Then you would use style sheets to control the display logic — the non-semantic attributes of your layout.

In a modern AJAX application, your HTML and CSS have been demoted one level of abstraction. What used to encode semantic structure + display logic, now only encodes display logic. The structure that manifests your application’s semantics is no longer the DOM, but rather, your JavaScript program and its state.

And that’s why we say, DOM = Frame buffer. It’s just a location in memory that you output into.

Crimes against abstraction

Let’s go back to the original crime against abstraction:

jQuery("#file_menu").is(":visible")

It should be rewritten as something like:

Menus.activeMenu == Menus.FILE

See? You should talk about the abstract concept of an active menu, regardless of whether your display logic deals with pixels or the DOM.

Just because your grandfather’s static pages used DOM trees to model layout semantics, it doesn’t mean your AJAX application has to model its state by dumpster-diving into the display layer