This post originated from an RSS feed registered with Agile Buzz
by Martin Fowler.
Original Post: Bliki: SegregatedDOM
Feed Title: Martin Fowler's Bliki
Feed URL: http://martinfowler.com/feed.atom
Feed Description: A cross between a blog and wiki of my partly-formed ideas on software development
Single-page web applications often turn into jQuery soup, where
application logic, DOM manipulation, and server access are all mixed
together. This mixing of concerns makes such applications harder to
understand and test than they ought to be. Segregated DOM is a modularization
tactic that separates all manipulation of the DOM into dedicated
JavaScript objects.
For an example, consider the recent filter catalog page I
developed to discuss my favorite eurogames. A key behavior of
this page is your ability to click on the filter panel on the left
side to filter which games display in the entry list panel. All this
is done via JavaScript. I have JavaScript classes for the
filter panel and the entry list, each of which encapsulates the DOM
access for that part of the page. The logic of deciding which games
to show is kept in a controller class which talks to the DOM
manipulation classes using an interface that is independent of
the DOM. The controller class doesn't make any use of jQuery.
During initialization the controller passes its update function
to the Filter DOM to be called whenever a box in the filter changes
state, the Filter DOM sets this function to the click events of the
check boxes. So when anything changes in the filter display this
update function in the controller asks the Filter DOM class for its
active filters ➊. The Filter DOM class responds to this call by
using jQuery to find the appropriate HTML elements ➋, filtering out
those boxes that are checked, and responding to the controller with a
simple data structure that indicates which boxes in each group are
checked ➌.
The controller uses this information about the filter state to
decide which games should now be visible, divides them into the left
and right columns, and calls the Entry List DOM with the details of
which element ids should be displayed in the list ➍. The Entry List
DOM uses jQuery to shuffle the HTML items into the right divs to do
the job ➎.
The principal benefit of doing this is to make it easier to
reason about each class by keeping it focused on a single task. When
I'm working on the Filter DOM class, I concentrate on how to do the
DOM manipulations on the HTML elements. When I work on the
controller I can ignore the details of the HTML structure, css class
names, and the like.
In more abstract pattern terms, these DOM objects act as
Gateways, a passage between two BoundedContexts (the application
and the HTML DOM). Like any gateway the DOM object has an interface
that speaks the vocabulary of its client (the application) and an
implementation that translates this into the barbaric (HTML DOM) land
beyond. [1]
A good modular design tends to correlate to testability. Each
class can be tested in relative isolation. A particular advantage
with a Segregated DOM is that I can test the controller without
using a browser or mock browser such as PhantomJS. Since I don't
need a DOM to test the controller, I can test it in node and just
supply some simple test doubles for the DOM gateways. This makes it
quicker and easier to modify the controller. By shifting as much
logic out of the DOM gateway as possible, I can increase how much
testing I can do without resorting to PhantomJS and the like (an
application of the Humble Object
pattern).
Acknowledgements
Pete Hodgson gave me some useful ideas for improving this article.
Notes
1:
You can use a similar separation for server access - this is the
classic application of Gateway.