Click here to Skip to main content
Click here to Skip to main content

Service locator is not an anti pattern

By , 3 Oct 2012
 

(this article have been rewritten since it didn't seem like I managed to communicate my thoughts properly). 

There are several blog posts that states that service locator is an anti pattern. With this article I'll try to explain why it's not. Do understand that I'm not saying that it should be used for dependency management.

Let's start by examining where the pattern doesn't fit (which most blog entries uses as a "proof" for when it's an anti pattern). 

Here are two quotes from different blogs:

In short, the problem with Service Locator is that it hides a class’ dependencies, causing run-time errors instead of compile-time errors, as well as making the code more difficult to maintain because it becomes unclear when you would be introducing a breaking change. 

Another blog:

The problem with a Service Locator is that it hides dependencies in your code making them difficult to figure out and potentially leads to errors that only manifest themselves at runtime. If you use a Service Locator your code may compile but hide the fact that the Service Locator has been incorrectly configured. At runtime, when your code makes use of the Service Locator to resolve a dependency that hasn’t been configured, an error will occur. The compiler wasn’t able to help. Moreover, by using a Service Locator you can’t see from the API exactly what dependencies a given class may have.

So what they are saying is that the pattern can hide dependencies and force you to run your application to discover it. I fully agree. It can do that.

Here is the most common example to illustrate that:

public class SomeService
{
	public void DoSomething()
	{
		ServiceLocator.Resolve<ISomeRepository>().Save("kdd");
	}
}

I agree 100%. The service locator do not work very well in that case. I strongly discourage you from abusing the locator in that way. Dependencies/information which is required should always be injected through the constructor.

So a better solution would be: 

public class SomeService
{
	ISomeRepository _repos;
	
	public SomeService(ISomeRepository repos);
	{
		if (repos == null) throw new ArgumentNullException("repos");
		
		_repos = repos;
	}
	public void DoSomething()
	{
		_repos.Save("kdd");
	}
}

Is it an anti-pattern?

We have identified use cases where the pattern doesn't fit. Does that make it an anti pattern? Of course not. Let's examine when it's perfectly valid.

Let's start with the very definition of service locator (from wikipedia):

The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the "service locator" which on request returns the information necessary to perform a certain task.

What it's saying is that the service locator basically is something that abstracts away the mapping between the requested type and implementations of something. That is that when requesting a service we do not have to care about the actual implementation.

Doesn't that sound awfully a lot like a inversion of control container? It does. Because an IoC container is nothing more than a service locator with lifetime management when all registrations have been configured.

Let's start by taking an example from the SimpleInjector documentation:

public partial class User : BasePage
{
    private readonly IUserRepository repository;
    private readonly ILogger logger;

    public User()
    {
        // 5. Retrieve instances from the container (resolve)
        this.repository = Global.Container.GetInstance<IUserRepository>();
        this.logger = Global.Container.GetInstance<ILogger>();
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        // Use repository and logger here.
   }
}

He do warn about using the container as service locator. But the point is that every container can be used as a service locator. Why is that? Because it's the easiest way to allow others to take advantage of all services that the container manages.

So when you are using any framework that have IoC support (like ASP.NET MVC) you can safely assume that they use the service location features of your favorite container.

Summary

My point is that you can abuse any pattern, but that doesn't make it an anti pattern. The reason to why Singleton and Service Locator got such a bad reputation is that they are easy to understand, implement and use. The problem is that the implementors/users haven't fully understood the problem that the patterns are trying to solve.

Here is a challenge for all of you that claims that it's an anti pattern:

Pretend that you are developer at Microsoft working with ASP.NET MVC. You want to let your framework users inject dependencies into the Controllers. But since you've read that service location is an anti pattern you'll want to replace it with something else (which supports scoping).

Anyone of you that can present a solution which is cleaner than my defined interfaces above will get my eternal respect. 

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

About the Author

jgauffin
Founder Gauffin Interactive AB
Sweden Sweden
Member
Freelance developer/architect with a passion for code quality, architecture, refactoring, networking and threading.
 
Solid skills in .NET/C#/MVC3
 
Blog: http://blog.gauffin.org

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionArticle updatedmemberjgauffin3 Oct '12 - 2:48 
http://blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern/[^]
 
I hope that the changes gets consumed to this article too.
QuestionShines... or blinds...memberploeh2 Oct '12 - 9:38 
You don't need a Service Locator in order to do message dispatching - I covered the eventing scenario without Service Locator about a year ago.
 
The claim that when one is writing frameworks (as opposed to libraries) Service Locator is suddenly necessary is a claim I often see, but I've yet to see proof. Service Locator doesn't shine in that scenario either... I think it blinds.
 
ASP.NET MVC 1 and 2 were perfectly good examples of frameworks where DI was easily possible, yet there was no Service Locator in sight.
 
My original claim that Service Locator is an anti-pattern still stands. I've always challenged people to present to me a scenario where I couldn't come up with an equally elegant (or better) solution that didn't involve a Service Locator. So far, that challenge is holding up.
 
That makes my claim scientific according to the philosophy of Karl Popper because it's falsifiable. All you have to do is to prove that the claim is false... but you have to prove it; not just say it.
AnswerRe: Shines... or blinds...memberjgauffin2 Oct '12 - 20:41 
Your channel interface:
 
public interface IChannel
{
    void Send<T>(T message);
}
 
is great. kudos for that.
 
But it's also interesting to see that you mention inversion of control containers in that post, since the only way to retrieve services from a IoC container is through service location. So you have just moved the service location from the library interface to the adapter.
 
I know that you are saying that you don't use the container in the role of a SL. I humbly disagree. Let's look at the wikipedia definition:
 
The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the "service locator" which on request returns the information necessary to perform a certain task.

 
It's exactly what you do in your adapter.
GeneralRe: Shines... or blinds...memberMark Seemann2 Oct '12 - 21:53 
The DI Container and its Adapter belongs in the part of the article that sets up the scenario. It explicitly describes how most people think you can only do message dispatching with a Service Locator.
 
The next part of the post then refutes that claim by demonstrating an alternative without Service Locator.
GeneralRe: Shines... or blinds...memberjgauffin2 Oct '12 - 21:58 
Are you referring to the PoorMansChannel where every consumer have to be manually built (as would all of their dependencies)?
 
Come on, do you really believe that it's a better solution?
 
Update
 
You end that article with saying that we could scan the assembly to find all consumers. That also means that we have to build them and inject all of their dependencies. And then resolve them again. Hence we once again got ourselves a service locator, since we again have abstracted away the consumer lookup using a central registry.
GeneralRe: Shines... or blinds...memberMark Seemann4 Oct '12 - 6:59 
Service Locator: roles vs. mechanics
GeneralRe: Shines... or blinds... [modified]memberjgauffin4 Oct '12 - 7:17 
I humbly disagree. Factories are just that: Factories. Each method invocation should create a new instance.
 
IoC containers on the other hand: They can return the same instance (depending on how the service were configured upon registration in the container).
 
So an IoC is by definition not a factory but a service locator.
 
If we go back to my framework, I do not care if it's a new instance or an old one. I just want to invoke an method on the object. Hence my interfaces are not adapters for factories but for a service locator.
 
Edit: Rephrased the second paragraph

modified 4 Oct '12 - 13:27.

QuestionService Locater an anti patternmemberMartin Bohring2 Oct '12 - 5:59 
Well,
In my view view it really depends what you are developing.
 
If you develop infrastructure (like MVC, a component framework, a bootstrapper etc.) than in my view it is totally OK to use the service locator.
Especially if you don't want to take a dependency on a specific DI container.
 
For business components (entities or however you want to call them)I consider it an anti pattern.
 
There I want to be completely unaware of any infrastructure concerns. I want to extract the pure logic and be able to test that in an easy way (the more you buy into DDD the more you want it)
A conclusion is the place where you got tired of thinking.

AnswerRe: Service Locater an anti patternmemberjgauffin2 Oct '12 - 6:11 
Great comment.
 
Exactly my point. The pattern is not an anti-pattern just because the pattern doesn't fit into the average line of business application.
QuestionServiceLocators are not the same as IoC containersmemberJohn Brett2 Oct '12 - 2:12 
There is a difference between SL and IoCC, and it's about who drives the dependencies.
I think it's important to state up-front that both systems are workable. What matters is the level of risk and transparency you get with each model.
 
The key issue that swung my viewpoint is illustrated by your SomeService class examples.
 
If I, as a consumer of that class, want to know how to construct it, it's not at all obvious (without inspecting the code, in some detail) that it will (at some stage, possibly well into its lifespan) require an implementation of ISomeRepository.
 
So if I'm a dumb user of your library, I'll need to read the documentation and study the code to know that I'll need to register an implementation of ISomeRepository with the ServiceLocator in order for the code to work. I'll then have to test the (insert expletive here) out of the code to be sure that it's going to work, and that the documentation didn't omit any other interfaces I might need. Or call off to another piece of code that, itself, asks for new and interesting interfaces from the ServiceLocator that I forgot to register.
 
Look at the IoC version of the code, and the constructor will take an ISomeRepository parameter. I cannot construct the object without all of its required dependencies - the compiler sees to that. I'm back to compile-time error checking, and very much happier.
 
As far as your challenge goes, Mark has already written several articles on IoC within ASP.Net., which would be well worth reviewing.
See DependencyInjectionAndLifetimeManagementWithASPNETWebAPI[^] for example.
 
Testing is another area where the constructor-injection approach wins out over the ServiceLocator pattern.
It's much easier for a test to have total control over the construction of all dependencies through constructor-injection rather than at arms-length through the ServiceLocator. To say nothing of what happens if the ServiceLocator pattern is itself implemented as a Singleton.
 
As far as your article goes, it seems to argue against ServiceLocator, but with one specific use-case where you can't see how to solve it without the SL pattern - i.e. a generic subscription pattern in which you're using the SL to identify the listeners.
I'm not sure I see a real-world use-case for this, or whether associating listeners via IoC is a good idea, so it's difficult to discuss, but this use-case in itself is no justification to go off using the SL pattern elsewhere.
If you want an example of the generic subscription pattern implemented using IoC (i.e not SL), then see
Event Driven Architecture: Publishing Events using an IOC container[^]
 
John

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 3 Oct 2012
Article Copyright 2012 by jgauffin
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid