Distributed Events and the Browser-Server Dialogue
The third part of this series of articles dealing with browser-server information flow discussed submission throttling and explicit submission. This one covers distributed events. The fourth of a five-part series, this article is excerpted from chapter 10 of the book Ajax Design Patterns, written by Michael Mahemoff (O'Reilly, 2006; ISBN: 0596101805).
Devi's producing a web app for auditors at a financial institution, aiming to highlight substantial transactions. Relevant transactions are already published on the enterprise messaging system, and Devi transforms it into an RSS feed on the web server. The browser script then checks the feed every few seconds, and updates the view whenever it detects a substantial transaction occurred.
How do you decouple code in a complex application?
Ajax Apps involve at least two tiers: a browser tier and a web server tier. In practice, the web server tier is often dependent on further tiers and external systems.
Each tier can be quite complicated, containing many stateful entities (objects, HTML controls, or regular variables).
The state of all these entities must often be synchronized, in order to keep users and external systems up-to-date. The synchronization needs to occur within a tier as well as across tiers--for example, an HTML table needs to change whenever browser-side user preferences change, but also whenever the server-side database changes.
Keeping all these objects synchronized can become complex--there are about n2 possible message paths from one object to another.
Keep objects synchronized with an event mechanism. This is a classic software pattern applied to Ajax, related to the Observer (Gamma et al., 1995) and "Publisher-Subscribe" (Buschmann et al., 1995) patterns, and also a key feature in the classic "Model-View-Controller" architecture. The DOM already provides an mechanism for low-level events, but the events discussed here are more semantic in nature; i.e., related to business and application concepts such as "account deleted." Note that the term "event" is used in a broad manner to mean any subscription-based approach that alleviates the need for direct calls from source to destination. Any publish-subscribe messaging mechanism falls under this definition.
Here's a scenario to motivate the concept of events. Say you have 10 objects with interdependent states. That is, when one object changes, any number of the other nine must change accordingly. The naive implementation would endow each object with an understanding of the other nine objects. Each time it's changed, an object would then tell each other object how to update. Each object now knows the other nine intimately. When one changes, the other nine must be updated--a major blow to encapsulation.
As with many programming problems, you can create a better solution by adding another layer of indirection--in this case, an event mechanism. Let each object broadcast changes instead of directly telling others how to respond. The changes should generally occur in semantic terms--rather than saying "someone's clicked me," an object should say "counting module has begin," or, "transaction has successfully completed." And let any object register to be notified whenever a message like this occurs. For larger systems, thinking in terms of events is easier as it breaks down the synchronization logic. You have one simple task to make objects broadcast events whenever they occur. And you have a separate task to decide how objects should actually respond to events, if they care about them at all.
On the Web, this pattern can be applied in different ways:
Server-to-browser Page elements can be kept in sync with server objects.
Browser-to-browser Page elements can be kept in sync with each other.
Browser-to-server Server objects can be kept in sync with each other.
Server-to-server Server objects can be kept in sync with each other.
Browser-to-server and server-to-server are both feasible, but beyond the scope of the Ajax Patterns because they are more about server-side architecture.
addListener (eventType, listener)
removeListener (eventType, listener)
These listeners can be callback functions, like the callback function used by XMLHttpRequest. Or, they can be objects that contain a function with a standard callback name for the event type being registered, such as onUpdate().
With Browser-to-Browser propagation, you can also have a Central Server Manager to accept events and notifications. Alternatively, each object can be responsible for creating and propagating events specific to itself. That is, each object capable of generating events needs to allow other objects to register themselves for the events.
Observer is a special case of this pattern that arises frequently. The events are not user actions but change notifications. Event listeners are observing an object and responding to its state. Often, its used to keep state in sync. An HTML table, for example, can render the latest state of a timetable object on the server side.
Finally, note that this pattern is somewhat speculative and open-ended, but the main purpose should be clear: to add a layer of intermediation so that objects can encapsulate their own responses to system activity, rather than being told what to do by other objects.