Presenting By Proxy

06 Dec 2013by Parker Selbert

The mediator pattern is an essential technique for cleanly stratifying any
data-driven system into layers with distinct responsibilities. The concept is
simple, take an object and wrap it in another object. When methods are called on
the wrapping object it, selectively overrides the method to process the original
object’s data, or it just passes the method call through to the original object.
That description doesn’t do the pattern justice, and probably confused you if
you already implement mediator pattern style presenters. Let’s illustrate the
concept with some Ruby code:

Implementing the presenter pattern in Ruby is almost free because of the
Delegate module from the standard library. It is a fairly thin wrapper
around Ruby’s dynamic method dispatch, method_missing. Whenever an unknown
method is sent to a delegate it dynamically checks whether the object it is
delegating to has that method and calls that instead. In the instance above the
delegator is being elevated to a presenter by manipulating the data
slightly.

What about languages that don’t have method_missing? One such language is
JavaScript. There isn’t any standard tracked method for handling method
calls dynamically. Fortunately, JavaScript is highly malleable, allowing for
dynamic assignment instead. Let’s take a shot at a JavaScript presenter:

That was a bit more work wasn’t it? Not only that, it has some major pitfalls.

First, there is the issue of uniform access principal. In Ruby every
message sent to an object with . is a method call, whether that particular
method returns a static value or is a proper method definition. That isn’t the
case in JavaScript. Calling a method on an object with . will always yield the
value of that object. That means if the value of an object is a function you’ll
get a [Function] reference back, not the evaluated function. This is evident
in the call to presenter.slug() above—it required the trailing () to invoke
the function, whereas the call to presenter.title did not.

There is also the issue of duplicating all of the data from the model onto the
presenter. For trivial applications or models with only a few attributes
duplication isn’t much of an issue. When you have hundreds or thousands of
models with nested objects or sizable data the duplication is entirely wasteful.
In addition, as soon as the model’s data changes the presenter will be out of
sync. Referencing the example above:

It turns out that ES6 Harmony proposes a clean solution to our presenter
problem. As of Firefox 18.0, Chrome 24.0 there is a new Proxy API, allowing
objects to be created and have properties computed at runtime. This is an ideal
tool for a presenter. Here is a simple example of how the Proxy object
behaves:

Three objects are interacting together here: a data object, a handler, and the
proxy itself. There is a wealth of what are called traps available to the
handler object. The example above uses the get trap to determine how to
respond to property access. This is exactly what we need for a proper presenter!

This version holds all of the benefits of a presenter with none of the drawbacks
enumerated before.

The handler’s get trap uniformly handles values from the model and methods
from the presenter.

There is no data duplication.

The data will always be in sync, as it is dynamically retrieved during
runtime. There is no need to observe the original object or keep properties
synchronized with events.

Unfortunately, as with any new web technology, there is the adoption hurdle.
Proxy isn’t available in many browser’s, even in Chrome without explicitly
enabling javascript harmony. Until the shiny future where the vast majority
of browsers support Proxy you will need to provide a hybridized version using
feature flags. That is precisely what I’ll be doing for my MVP needs.