The Hated Service Locator (Anti-)Pattern

I was recently doing some reading about Spring and Dependency Injection in general when I came across a particularly harsh comment about the Service Locator pattern. The guy was so convinced that he’s right that he even linked to the famous Martin Fowler’s post about injection adding some other disrespectful comment. I was curious if that’s an isolated case or other people share this guy’s opinions, so I started “googling” the topic. To my surprise, a majority of the results I found yell from the very title: Antipattern! Don’t use! It’s bad for your health… Is it?

What the Haskell are you talkin’ bout?

Aside from some weird implementations using JNDI or reflection that you can find online, Service Locator can be a very simple way to resolve dependencies in your project. Instead of using a constructor or setters to provide the necessary dependencies for a class, the class takes whatever it requires from a central registry called Service Locator. The simplest implementation of the pattern and its usage could look like this:

Obviously, this is only a simplistic starting point. Depending on your needs you can go from there and provide more sophisticated implementations of the locator. The key characteristic is that we’re acquiring dependencies using the locator instead of Dependency Injection, Singletons, or the new keyword. Now, let’s look why the pattern is so “evil”.

“It makes testing difficult!”

If you’d like to write a unit test for class A, its constructor wouldn’t tell you anything about the dependencies it has. You can write a compiling unit test that will fail with a NullPointerException.

Whoa! How EVIL! Did you see that?

Come on! That’s laughable. How often do you write unit tests so much time after implementation that you don’t remember about loading some dependency inside the locator? Even if it happens to you sometimes, how hard is it to correct the mistake? It’s trivial!

Hola, hola, Mr. Smartass, what about integration tests?! I’m writing these long after the initial implementation and running the tests 20 times with 20 NPEs to finally load up all the dependencies is not really desired, is it?!

Two things. Firstly, the problem is not unique to the Service Locator pattern. Those still in the age of Spring XML configurations know that very well. Secondly, the problem is not really that hard to solve. I’ll give you two ideas and I’ll trust in your brainpower to explore further if needed.

  1. You could use the same code that configures the locator in production code for testing purposes. Since you’re already adding all new dependencies there, reuse might be a good option.
  2. You could prepare a test version of the locator that configures all “good” dependencies and stubs away the “bad” ones. After that, you can simply update both locators every time you add a new “service” to the application.

I know, I know. It requires a little thinking, but not that much, really.

“The dependencies are hidden!” – Version 1

Fact: you can’t see all of the class’ dependencies by merely looking at their fields and/or constructors in a typical Service Locator usage scenario. Not really a fact: the dependencies between the classes are therefore hidden.

Watch the magic happen:

WHOOAAA! Look at this guy! He highlighted all of the lines with dependencies with a single mouse click in the IDE. He has to be a magician! But that’s not everything! Two more clicks in my IDE and I’ve got this:

Noooo waaay! The IDE can unhide the hidden!

“The dependencies are hidden!” – Version 2

Fact: missing dependencies will cause runtime errors rather than compile times errors when using the Service Locator pattern.

Another fact: the same applies when using DI containers instead.

Magician advice: test your code, so that these errors never occur! I guess it does not require further commentary.

“You can easily introduce breaking changes!”

This one is my favorite. I guess it comes straight from the land of spaghetti monoliths and people’s silver bullet dreams.

Well, if you’re trying to use the Service Locator pattern to configure your public APIs, regardless of whether these are for the general public or just another team in your company, I guess you’re doing something wrong. It’s even worse than using the screwdriver like in the quote above. It’s like trying to get the nail in using your forehead. Leave your forehead safe and use the whole head to think instead. The fact that a pattern does not apply to every single use case does not make it an anti-pattern right away.

“So, what you’re trying to say, Magician?”

I’m trying to say that most of the arguments for Service Locator being an anti-pattern are laughable. Of course, the pattern is not a silver bullet. Of course, at first, it might not seem as easy to use as blindly spraying @Autowired or @Inject all over the place. At the same time, it’s not as evil as people try to describe it online. It’s different, but it has its strong sides e.g. you don’t have to use DI containers to construct the object graph for you or, God forbid, you don’t have to do it manually. The concept is very simple to understand and gives you endless possibilities of implementation. Given a bit of thought, it’s as testable as regular dependency injection or even more (tests without DI containers run faster). All in all, I think that the Service Locator pattern could work really well, especially in modern microservices architecture and deserves much more love than it currently gets.

About the Author Grzegorz Ziemoński

King of Tidy Java, nerd that thinks about producing perfect software all the time and proud owner of 2 cats.

follow me on:
  • sarnobat

    Well as the first poster here I’m in the camp of avoiding hidden dependencies at all costs (though I admit my experience with Service Locators specifically is minimal).