I’m building a job scheduling system where a Schedule contains many ScheduleItems. Each of these ScheduleItems as various dependencies that need to be resolved before the SchduleItem’s “job” is able to run. When a ScheduleItem’s dependencies are all resolved the ScheduleItem will trigger an event and let the parent Schedule know that the Item’s dependencies are resolved. The Schedule can then go about it’s business, saying the job is ready, etc.
The problem I faced in this setup was needing each ScheduleItem to trigger an event, with a potential for hundreds or thousands of ScheduleItems to be part of a Schedule. I saw a couple of options for this, tried them both, didn’t like either of them. I kept feeling like I was getting 1,000 paper cuts.
But, in the end, found a solution that I do like thanks to Dave Mosher.
Instance Members: Death By 1,000 Paper Cuts
My first solution was to have ScheduleItem inherit from EventEmitter.
In this setup, each ScheduleItem is an instance of an EventEmitter through the magic of
util.inherits. That’s cool. It works. I’ve used util.inherits a bunch of times and I like the way it works with EventEmitters, to give me events in my objects. But, this turned out to be bad idea #1. I had to loop through each of the ScheduleItems in my Schedule and have the Schedule attach to the same event on each of them.
That’s potentially 1,000+ event emitter instances with the same number of event handlers being set up. No thanks.
Dependency Injection: One Paper Cut 1,000 Times
The next trick I tried was injecting a single EventEmitter in to each of my ScheduleItem objects. Sure, I still have to loop through all of my ScheduleItems in order to inject the EventEmitter but that seemed like less of a problem since I would only have 1 EventEmitter.
This turned out to be bad idea #2 because the ScheduleItems are not created by the Schedule itself. They, themselves, are injected in to the Schedule from an external party (they ultimately come from a database). That meant the external party would then be responsible for injecting the EventEmitter in to both the Schedule and the ScheduleItems – far too much knowledge and responsibility leaking out of the Schedule / Item at that point. This totally breaks the encapsulation of the relationship between Schedule and ScheduleItem.
This is ultimately one paper cut… but it’s one paper cut on 1,000+ objects, being controlled by something that doesn’t feel the pain of those objects. Sounds like torture to me. No thanks.
Static (Type Level) Members: A Paper Cut That Will Never Heal
In C# we call static members “untestable static dependencies” because that’s what they are – a dependency that is “static” to a class somewhere, that cannot be properly tested because it’s static. It starts out looking good, but quickly devolves in to making sure each test resets the static thing properly or working around the left-over static value from the previous tests that ran.
“Static” members, then, are a bad idea in this case (though not in all cases). It’s like a paper cut that will never heals – you think you’ve covered it up and it’s healing, but the next time you look at it, it’s an open wound again, seeping blood. No thanks.
Prototypes: Neosporin For My Paper Cuts
Around this time, I’m annoyed and am looking something better than what I’ve got. So I do my usual thing and blast a question out to twitter, expecting 1,000 people to give me fresh new paper cuts by completely misunderstanding what I’m looking for. By some miracle, though, Dave Mosher manages to understand what I’m asking (in spite of twitter’s limitation on context in 140 characters) and sends me this little gem of a tweet:
@derickbailey few options, constructor dependency injection with the master emitter, or models inherit from object w/ emit function defined.
— Dave Mosher (@dmosher) April 10, 2014
My initial response is something along the lines of saying no I already tried those things. But then somewhere in the back of my mind “inheritance” clicks with “prototypes” and a thought crushed my mind like Obi-Want whispering from the ether: “Luke, use the prototype!”
So I take the best of static members and inheritance, super-collider them together and produce a boson that looks like it’s giving mass to each of my ScheduleItem instances when in reality, it’s just the prototype chain in action!
I now have a way for each ScheduleItem to call this.emit the way I originally wanted, while still allowing a single point of access for all of the ScheduleItem instances, from the Schedule itself.
So remember kids: eat your Wheaties, don’t do drugs, and use prototypal inheritance to your advantage. It’s a good way to get access to a single thing from every instance of your objects, and can prove itself useful in situations where static members, instance members and dependency injection all seem to have more problems than they are worth.
Granted, there is still potential for paper cuts in the prototypal setup. Each ScheduleItem looks like it is getting it’s own instance of an EventEmitter, but they are actually sharing the same instance. I have to make sure the events that any given ScheduleItem emits includes the ScheduleItem instance as the first parameter. That way the thing listening for the event can get a reference to the actual ScheduleItem that wanted to trigger the event.
Over-all, though, the potential for paper cuts from this setup seems less than the massive, hemorrhaging paper cuts of the previous ideas. But for now, prototypes are providing a soothing salve to heal the wounds I previously inflicted on my code.