Sondheim Meets MooTools A Look at Company
A couple of weeks ago I released Company, a implicitly-mediated component system for MooTools. As mentioned in the official site, Company was created a more complete alternative to the simple event-based module systems described in my surprisingly popular Modules and Callbacks article.
Based on the feedback, I would say that Company was quite well received by many, although it did seem apparent that many more weren’t quite sure what exactly makes Company any better from the models described in the Modules article. Even more interesting are the comments from some detractors who not only seem to have missed the entire point of Company, but have also failed to grasp the whole background behind it’s existence by forgoing to skim through the Modules article (more on this in a bit).
I decided then that a blog post is in order, not just to shed light on some areas of Company but also to explain some design decisions I took while developing the library.
Classes, What of Them?
Before I move on to explaning some of the design decisions behind Company, I have to address the issue of classes. One of the biggest questions about Company is what it mean for Class
. Some critics have assumed that I’m trying to create a replacement for the class system, and that Company is a futile attempt at introducing yet another “class” abstraction into MooTools.
Anyone who took the time to read the Modules and Callbacks article will, of course, know that the assumption above is erroneous. Units and classes are orthogonal for the most part, and their uses are independent. Company does not aim to replace classes, which should be apparent by the fact that Company provides explicit ways to integrate classes into the system.
Classes and the Company system deal with two very different problem sets. Classes are for defining blueprints for objects, a way to share properties and methods among multiple object instances. The end product of classes are instances or, to be more generic, objects. Classes therefore deal with the problem of object composition, inheritance and definition.
Company, on the other hand, deals with the problem of how those objects interact–specifically how they interact without tight coupling. Almost any object can be a unit, regardless of whether it was created by a class or not, because there’s no direct functional overlap between units and classes per se. Company therefore deals with the problem of object-to-object communication, decoupling and application composition.
And with that said, let’s move on to some juicier stuff.
New Old Stuff
Company–or at least the base-code from which it evolved–actually predated the Modules and Callbacks article by almost a full year. The earliest version of it was a simple class called Module
that I used for some projects in 2009, and which eventually got refined and rewritten into the released version of Company.
In fact, Company wasn’t written in response to the Modules and Callbacks article, but rather the other way around. Around Fall of 2010, I was thinking of releasing Company publicly, but I was unsure whether people would understand what it is or why should they use it. I realized that a background of sorts had to be laid out, so I wrote the Modules and Callbacks article in order to lay some groundwork regarding the ideas and concepts that were important in understanding the library.
It’s All In The Terms
About a few weeks after I’ve published the Modules article though, it became apparent to me that the use of the term “module” in the article can be quite confusing for some. The term means different things depending on the situation and–when talking about modular programming–its meaning in one context can easily be confused for another.
After some conversations, I realized that the term I was aiming for was “component” rather than “module.” In my defense these two words can indeed be used interchangeably in some contexts (particularly the context that I used it for in the article), although I should have really used the proper word in the original article.
Unfortunately, this became quite a blocking issue of sorts. The original working name for the library was Mood–a silly play on “MooTools Modules”–but it was clear that I had to drop that name as well as rename the Module
constructor. This was needed to mitigate the possible confusion about the library’s purpose and use, and to make it clear that I’m using a very specific meaning of “module.”
The obvious choice was, of course, to rename the constructor to Component
. However, I wasn’t so hot about the idea for the reason of length: for something I expect to type more than a few times, I’d like the library’s main constructor identifier to be short and sweet.
After some debates on an IRC channel and consultations with the thesaurus, I settled for a more generic yet non-overloaded word “unit.” The choice was appropriate: it conveyed the idea of self-coherence and independence like “module,” as well as retaining the idea of higher-composition like “component”–and it’s only four letters.
Why then is the project named “Company” instead of something more descriptive, like “MooTools Units”? As you might have already guessed from the title of this post, the name is actually a nod to Stephen Sondheim’s “Company”. Since I believe that most readers of this blog have never encountered the play, let me just say that there’s an underlying thread between the theme of Sondheim’s play and the philosophy of the JavaScript library and leave it at that.
Oblivious Objects
A big idea that affect a lot of the design decisions in Company is the egocentricity of components. In Company, units are meant to be self-centered bastards that only care about themselves.
I liked the idea of unit egocentricity because it’s very compatible with the idea of highly decoupled components. Highly-coupled objects are very “social” in nature: they form strong attachments to other objects. Decoupled objects, on the other hand, don’t really care that much about other objects but instead focus on themselves.
One big example of unit egocentricity is the fact that units can be anonymous, in the sense that you don’t have to store them in variables. Units can “talk” to one another without having to explicitly call on each other, because all messages are done via a mediator.
Another good example is with the defaults of the subscribe
method of units. Unlike the MooTools addEvent
, the callback function passed to subscribe
doesn’t get its this
keyword bound to the origin of the event, but rather to the unit where subscribe
was called from.
// redundant
this.subscribe('event', this.method.bind(this));
// better
this.subscribe('event', this.method);
PubSub + Mediator
The description for Company says that it’s a “mediated system,” which simply means that it uses a Mediator. Like in the Modules and Callbacks article, the Mediator in Company is largely event-driven. The language of the system, however, is more PubSub than Mediator, with method names like subscribe
and publish
.
This decision to use PubSub terminology was done for two reasons. The first is because the PubSub verbs like publish
and subscribe
convey more active actions than addEvent
and fireEvent
.
The second is to distinguish the act of publishing and subscribing from any event-related actions the unit might do. This distinction is important because Company allows decorating non-unit objects to give them unit-like functionality while still retaining their original event-based behaviour. By using PubSub-based method names rather than Event-based ones, the separation of the functionality is more apparent: use publish
and subscribe
to pass messages between units, use fireEvent
and addEvent
for events.
Implicit Mediation
The merging of an events-based mediator system and PubSub-based API is largely possible due to Company’s use of implicit mediation.
In the Mediator section of the Modules and Callbacks article, we used an explicit mediator in the form of the window
object. We say that the window
is an “explicit” mediator because we specifically call on it directly in our code: window.addEvent
and window.fireEvent
.
An implicit mediator, on the other hand, is a mediator that doesn’t appear directly in our code. In fact, it’s abstracted from the code. We know that a mediator is used in operations and we know that it exists–we just don’t work with it directly.
An explicitly mediated system can be transformed into an implicitly mediated one simply by abstracting the calls to the Mediator. Instead of directly calling window.addEvent
inside components, for instance, we can provide components with a special method called subscribe
, which wraps the calls to window.addEvent
, as well as publish
for window.fireEvent
.
An implicit mediator therefore gives us another level of decoupling: because we abstract calls to the mediator, our units don’t have to explicitly know about the mediator itself. If we craft the abstraction well enough–perhaps in the form of a class mixin or, in the case of Company, an object constructor–we can add a level of flexibility to the system by allowing us to switch mediators without the knowledge of the objects. The objects will still be able to use the abstractions, even if they don’t know how these abstractions work internally.
These techniques make Company different from explicitly mediated systems. While units are mediated by a separate Mediator object, the communication is done using the subscribe
and publish
methods which actually abstract the calls to the Mediator.
Not Just Events
Company’s mediator is called the Dispatcher. It is implicitly used for all unit messaging methods, and it was created to be private by default.
The Dispatcher itself is the one feature of Company that separates it from the basic techniques. The main reason the Dispatcher is so powerful is because it’s built from a hybrid of techniques unavailable from simple mediators like an Events
instance or window
.
At its core the Dispatcher is simply a new Events
class instance. All of the Events
class methods are retained except for two: removeEvent
and fireEvent
. The removeEvent
method is overriden for the Dispatcher because of a bug that was not fixed until MooTools 1.3.1, so it was necessary to override it for the Library. The decision to override fireEvent
, though, is what makes the Dispatcher a fantastic mediator.
As Dean Edwards explains, JavaScript callback systems tend to be brittle. In the DOM Events system, DOM event handlers are dispatched in their own execution contexts, which basically means that they are executed separately in a different “sandbox.” This sandboxing prevents the errors of one event handler from stopping the execution of another event handler–something that’s necessary for modularity.
Most callback systems, however, are simply implemented as function queues that dispatch each event in the same context using a loop. If one of those callbacks fail, all the other callbacks after that aren’t executed, which is what makes them brittle.
The core of the MooTools Element Event system is smart enough to bypass this problem by using proxy event handler. MooTools attaches a proxy event handler for all native events attached via addEvent
, so each event handler is dispatched in its own execution context.
Unfortunately, the fireEvent
method from the Element Events system (as well as that from the Events
mixin class), is still affected by the problem. This is because fireEvent
was implemented as simple looping dispatcher: it takes the callbacks from a particular event type, loops through them and dispatches each of them inside the same context. Thus, the original chain-stopping-on-errors problem is still there.
Company demands a better implementation. As I mentioned earlier, one of the guiding ideas in the library is component egocentricity. Why should an error from a unit affect another? It wouldn’t make sense, since each unit should only be concerned about itself. In order to circumvent this, I needed to make Company’s Dispatcher not as brittle as the regular implementation–and the only way to do this was to change how the Dispatcher’s fireEvent
method works.
I took Dean’s advice and went with the real element dispatcher route, and decided that I’ll use a <script>
element to dispatch the events. What happens is that every time the Dispatcher needs to dispatch callbacks, it uses the <script>
element and dispatches a true native event to execute the callback. This means that each callback is indeed fired on its own execution context. Errors from one unit’s callback do not affect the others.
The choice of using the <script>
element in particular is also something to consider. For all browsers that support the DOM2 Event API, Company uses the normal dispatchEvent
method to perform the callback execution. This method works regardless of whether the element is inside or outside of the DOM tree, so we could use any kind of element. In fact, a <div>
element was used in an earlier version of Company instead of <script>
.
Meanwhile, Internet Explorer versions prior to version 9 do not natively support the DOM2 Event API. As detailed in Dean’s article, a simple technique for IE would be to use the proprietary onpropertychange
event in IE to trigger the callbacks. This event, however, has two main issues: first is that it’s only fired for a subset of all possible object (the normal element set, to be precise), and second is that the element must be inside the DOM Tree.
What I needed then was an element that I could stick in the DOM Tree to support IE. At first I toyed with the idea of sticking a transparent <div>
into document.body
–or even document.head
–but that idea was scrapped because a <div>
can be rendered and can thus cause havoc on the page itself. Fortunately, Simo suggested in a converstation that I use a <script>
element instead. This was a perfect solution, since this element isn’t rendered nor is it obtrusive.
Names, Names, Names
A lot of people will agree that coming up with appropriate names is one of the hardest parts of coding. With Company, it was even harder because of how units are created.
Company units are created using the Unit
constructor, which take a single object argument called the descriptor. Just like in classes, the descriptor object is used to define the structure of the generated unit object by providing the properties and methods of the unit.
Unlike classes though, units are decorated pretty heavily with special methods. This gives rise to a collision problem: if I make the method names generic enough, they might get overridden by stuff from the descriptor. Using a method name like start
, for instance, is a big no-no, since that name crops up a lot of times.
In the earlier versions of Company, I toyed with the idea of using aliases. What I did was to use generic method names like extend
, and provide an “aliased” copy of that method but with a prefixed name: _extend
. That way if the descriptor overrides the default extend
method, you’ll still be able to call it via _extend
.
But I quickly shot down this idea because it makes extending Unit itself hard. The only way to create aliases in JavaScript would be to store the function twice with separate keys, since there’s no way to reference a reference in the language. This becomes problematic once you start extending the Unit
prototype: you’ll have to replace two methods instead of one.
Eventually, I came to the conclusion that using suffixes would be better in the long run. Thus, method names like extendUnit
and setupUnit
are used. The verbosity, I hope, would count that much, since most of these methods are utility ones that won’t be used that much.
Three methods, however, aren’t suffixed: subscribe
, publish
and unsubscribe
. These were kept intact because I expected them to be used heavily, so I wanted them to be as short as possible.
Classy Types
Finally, there’s the question of the Unit
constructor itself: why is Unit
implemented as a Type
and not as a Class
?
The first reason is a semantic one: units are specialized object types, so I want them treated separately by the MooTools type system. Since units are of a different type, doing typeOf(new Unit)
should produce 'unit'
rather than 'object'
. This enables any weird behaviour that might occur when a unit object is passed to any function that requires a regular object.
The second reason is more subtle: due to their probable frequency of use, unit methods need to be as fast as possible. This means that decoration of these methods must be kept to a bare minimum. The MooTools class system actually uses decoration pretty heavily in order to facilitate several important features. Since these features aren’t needed by units, I forwent implementing Unit
as a class.
A unique feature of Unit
, however, is that it’s a “class-like” type object. Unike most other type objects, Unit
can be subclassed by regular classes and even used as a mixin. This is possible because Unit
is implemented the same way as regular class constructors, and therefore allow for subclassing and mixin functionality. This, I guess, is one of the perks of being familiar with the internals of MooTools wink.
Keeping Company
I hope this post answers some if not all of your questions regarding Company. If there’s something else that you’d like to know, feel free to post them in the comments below. I’ll try to answer all of them.
If you still haven’t played with Company, I urge you to do so. You can visit the official project website or view the source code from github. I cannot guarantee that Company will change the way you code, but maybe you’ll learn a thing or two from it.
And don’t forget to subscribe to the RSS Feed or follow me on Twitter.
Comments
Post a Comment
You can no longer comment on this post. If you have something important to say, reach out via Twitter or via email (remove the nospm part).