In this installment of the Architectural Atrocities series I’ll continue on the Cairngorm theme. This time it’s something that is truly an architectural atrocity if there ever was one, and one of the ugliest things I’ve seen in such a high profile piece of software that Cairngorm is (a fact that still baffles me): Cairngorm’s Service Locator.
The last post stirred up quite some debate and I’d like to thank everyone who commented on the post. I’m amazed that people still post comments (by coincidence to the day) seven months later.
The Cairngorm ServiceLocator is, at least on the surface, an example of the J2EE pattern of the same name. There is a debate whether ServiceLocator is just another form of global variable or if it is more like a factory. I’m on the side of global variable, but notable persons like Martin Fowler thinks that ServiceLocator has merit. On the subject of the pattern I will not judge, however I will say a few things on Cairngorm’s variant.
In short a Service Locator is a registry of named services and provides a global access point for these. The idea is that you can load up the service locator with references to specific services, but the code that asks for them only knows their interface.
The Cairngorm variant provides a globally accessible registry for storing references to
WebService objects. Only. If you have custom services of any kind ServiceLocator doesn’t help you. You can’t load the ServiceLocator with objects willy-nilly, instead you have to subclass it and create the service objects in the subclass. This provides some of the abstraction that the ServiceLocator pattern is meant for — you can declare another subclass when you test, for example — but it’s quite limiting in its design. On the upside it makes it possible to set credentials on all services at once, which can be handy.
The way you use the ServiceLocator is to subclass it in MXML and declare the services you have. When you need to access the services you call
ServiceLocator.getInstance() and use either
getWebService and pass the ID of the object you are interested in.
But wait a minute.
ServiceLocator.getInstance() you say? How does that give me a reference to the subclass where I declared my services?
The answer is, of course, bastardized object oriented black magic at it’s worst. When the subclass is instantiated, which it must be for this to work, it will run the superclass’ constructor which will set a global variable to
this — let’s repeat that: the constructor of
ServiceLocator sets a global variable to a reference to an instance of the subclass. This global variable is returned by
But what if I declare two subclasses of ServiceLocator? Oh, why, then an exception is thrown when the second is instantiated, of course!
It is mind boggling how anyone could come up with something so byzantine and have the audacity to use the words “best practice” in connection with it. Just the idea of subclassing a Singleton should start the alarm bells ringing as loud as they go, not to mention subclasses affecting the workings of their parents as a side effect of them being instantiated. I can’t find words to describe all that is wrong with this.
If you so badly want to be able to access your services globally, why not just use
Application.application.services or some something similar? (Not that I’m saying that it would be a good solution, it might just be a less insane solution.)
Why go to such lengths and create something so profoundly appalling as Cairngorm’s
ServiceLocator if all you want is global access to named objects? And why, when there’s a perfectly workable pattern that provides the same kind of solution, use the same name but invent something that uses none of the good parts, but all of the bad (and throw in some more bad things while you’re at it)?
I think that not only is the code atrocious, but the fact that the (new and updated) introductory articles on Cairngorm completely gloss over what is going on is disturbing. It doesn’t explain why you suddenly should use
ServiceLocator.getInstance(), when you just previously declared a class called
Services, how the things you declared in that class end up in
ServiceLocator, and it there’s no mention that it all hinges on the
Services class being instantiated exactly once.
Service Locator is surely the worst of Cairngorm and I would go so far as to say that if you think there’s nothing wrong with it, you shouldn’t be writing software.