Automagic Event Registration

Further to last night’s post on custom events, I’ve set things up now to use “magic event registration”. It’s a little like the auto-wiring facility of a dependency injection container. It’s quite simple really – the app’s initialisation sequence does this:

  • Register all components that might listen to something.
  • Register all events they might listen to.
  • For each listener method among the components, automatically bind the event to it.

In code:


  1. var components = [siteFrame, singleTrial, trialController, statsZone, tableView, analysis, rawView, graphView];
  2.   var eventTypes = ["trialCreate", "trialUpdate", "trialSuspend", "trialRun", "trialComplete"];
  3.   $.each(components, function(i,component) {
  4.     $.each(eventTypes, function(i,eventType) {
  5.       var handler = component[eventType];
  6.       if (handler) $(document).bind(eventType, handler);
  7.     });
  8.   })

A component looks like:


  1. statsZone = {
  2.   trialCreate: function(e, trial) {
  3.     ...
  4.   },
  5.   trialUpdate: function(e, trial) {
  6.     ...
  7.   }
  8. }

And elsewhere in the code, the events it listens to get triggered through the normal jQuery custom events mechanism:


  1. $(document).trigger("trialUpdate", trial);

Part of this is based on what I said last night, which is (a) I’m keeping things simple – hence everything happens at startup and all the instances are singleton classes; (b) consequently, events are global, rather than being attached to any particular component.

Stepping back, what were the alternatives to this design:

  • Components register themselves as listeners – this would be the purist OO answer, i.e. keeping objects autonomous. A perfectly cromulent solution, but a little more redundancy than it needs to be. If objects really do have consistently named listener methods, it’s just as easy to handle registration automagically.

  • The initialisation routine manually wires up components to events. It has a certain Python-like “explicit” feel to it, but again is quite pointless if we can instead do it automagically.

So where does the automagic model fall down? If we are doing things dynamically, it would get more complicated and would, for example, require objects to register upon their creation. So I think that’s still okay. Another problem could be if a single method was listening to more than one event type, since this technique assumes it’s one-to-one from event type to methods. But that’s okay too – I actually had this problem and it was simply solved by getting both handlers to delegate to a third, common, handler:


  1. var trialController = {
  2.   trialCompleteOrCreate: function() {
  3.     ...
  4.   }
  5. }
  6. trialController.trialCreate = trialController.trialComplete = trialController.trialCompleteOrCreate;

I realised while working on TiddlySpace there’s a lot to be said for dependency injection style patterns in Javascript, and it’s not happening yet.

Mocks, Stubs, Dependency Injection, and … XMLHttpRequest

“A Mock Is Not So Stupid After All!”

Dave Crane’s been talking about Mocking the Server-Side:

A Mock Object is a stand-in for the real thing. Few modern programs are really standalone, and enterprise apps require a very complex context in order to operate; containers, databases, directories, web services, etc. This can make testing difficult, because to set up the test and run it, one needs to provide all the necessary context. Mock objects can be thought of as really dumb implementations of a contextual element, one that would never be useful in production, but provides the predictability and ease of setup required for a test. A mock database might always return the same four rows of data, whatever the WHERE clause. A mock web service might always serve up the same XML document.

So the idea is to create a simulation XML document (or plain-text document) to be retrieved with XMLHttpRequest.

Dave’s followed up with some good tips to that end. All good timing as I’ve recently been working on a demo for the final lot of patterns – the process patterns – and one of the refactorings uses a canned plain-text document to illustrate The Pattern Currently Known As “Server-Side Simulation Stubs” (who said alliteration had no place in software writing?).

Worth noting the terminology used, and here I’ll be pedantic. Dave refers to a Mock what I call a Simulation Stub. In the past couple of years, the terms “Mock” and “Stub” have often been used interchangeably, but I think the distinction is worth keeping, because otherwise the original meaning of Mocks is lost. I don’t really care what things are called, but when two concepts become one name, at least one of those concepts is going to get hurt. It’s a testament to the creators of Mocks that they managed to produce a name so evocative that it’s come to consume a much older concept. (“Stub” and “Shunt” have always been pretty vague terms anyway.)

Under the original definition, a Mock is an object that verifies how it’s being used by a tested object, and by inference, how things like it will be used by the class being tested. Yes, it might spit out simulation data, and it might even have a fancy interface that lets you tell it how to respond. However, those functions are only there to help verify how it’s used. It’s what goes into the mock that counts, not what the mock pumps out. Corollary: a Mock is not stupid. It might not win a Nobel Prize anytime soon, but it’s smart enough to know what to expect and how to check if that expectation’s been met. The mixing of terms has carried over to some parts of the Ruby/Rails community, as Aslak recently observed during a RubyConf presentation. (Podcast on mocks, Fowler’s Mocks Aren’t Stubs.)

In a web context, what might the distinction mean?

  • A Simulation Web Service (or a “Stub Web Service”, but I prefer “Simulation”) is typically some XML or plain-text document that’s been written manually. It could also be a bit more sophisticated, offering a means for the server-side developer to tweak its output.
  • A Mock Web Service is a server-side script that’s been configured to expect a certain sequence of XMLHttpRequest messages, and will carp as soon as the sequence is broken.

As Dave’s articles explain, a Stub Web Service is certainly a useful thing, and I suspect quite a few developers follow that practice. (Please tell me about it if you do!)So how about Mock Web Services? That’s pure speculation!! I could see the benefit, but I’ve not done it, haven’t heard of anyone doing it, and I seriously doubt there are any frameworks that facilitate it.

A variation on Simulations and Mocks would be a completely browser-side approach, in which you adopt an XMLHttpRequest wrapper, and make it output a dummy document while in “testing” mode. This raises further questions:

  • How are mocks handled in Javascript? Well, William Taysom recently noted that you can approximate method_missing, and a Mock library like the awesomely useful JMock library is clearly feasible. There are a few JUnit equivalents out there, so why not a mock lib? (Would you use such a thing?) If you say that would be over-engineering, then the same charge could be made about JS testing in general, since mocks are really a natural consequence of unit testing and TDD … any time you find yourself testing an event mechanism, a mock might be a good idea.
  • How to switch context in Javascript? Okay, so mocks are a big reason for the rise of Dependency Injection and “lightweight” (( containers in Java/J2EE/JEEWhiz. Well then, doesn’t Javascript need the same thing? Again, I know, “you’re over-engineering it, Mahemoff”. So maybe I am. It’s been said that Dependency Injection doesn’t do much for Ruby, and maybe the same’s true for JS. So how then, do you make your browser app switch between a mock web service and a production service? The answer is not, “change the source code”, because to achieve continuous integration, you want to keep an automated test around that calls the mock service. Maybe the best thing to do is rely on DI – or some other context-switch mechanism – in the server, so that the Javascript that it spits out will differ according to the environment.