# Wednesday, February 03, 2010

Service Locator is a well-known pattern, and since it was described by Martin Fowler, it must be good, right?

No, it’s actually an anti-pattern and should be avoided.

Let’s examine why this is so. 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.

OrderProcessor example

As an example, let’s pick a hot topic in DI these days: an OrderProcessor. To process an order, the OrderProcessor must validate the order and ship it if valid. Here’s an example using a static Service Locator:

public class OrderProcessor : IOrderProcessor
{
    public void Process(Order order)
    {
        var validator = Locator.Resolve<IOrderValidator>();
        if (validator.Validate(order))
        {
            var shipper = Locator.Resolve<IOrderShipper>();
            shipper.Ship(order);
        }
    }
}

The Service Locator is used as a replacement for the new operator. It looks like this:

public static class Locator
{
    private readonly static Dictionary<Type, Func<object>>
        services = new Dictionary<Type, Func<object>>();
 
    public static void Register<T>(Func<T> resolver)
    {
        Locator.services[typeof(T)] = () => resolver();
    }
 
    public static T Resolve<T>()
    {
        return (T)Locator.services[typeof(T)]();
    }
 
    public static void Reset()
    {
        Locator.services.Clear();
    }
}

We can configure the Locator using the Register method. A ‘real’ Service Locator implementation would be much more advanced than this, but this example captures the gist of it.

This is flexible and extensible, and it even supports replacing services with Test Doubles, as we will see shortly.

Given that, then what could be the problem?

API usage issues

Let’s assume for a moment that we are simply consumers of the OrderProcessor class. We didn’t write it ourselves, it was given to us in an assembly by a third party, and we have yet to look at it in Reflector.

This is what we get from IntelliSense in Visual Studio:

image

Okay, so the class has a default constructor. That means I can simply create a new instance of it and invoke the Process method right away:

var order = new Order();
var sut = new OrderProcessor();
sut.Process(order);

Alas, running this code surprisingly throws a KeyNotFoundException because the IOrderValidator was never registered with Locator. This is not only surprising, it may be quite baffling if we don’t have access to the source code.

By perusing the source code (or using Reflector) or consulting the documentation (ick!) we may finally discover that we need to register an IOrderValidator instance with Locator (a completely unrelated static class) before this will work.

In a unit test test, this can be done like this:

var validatorStub = new Mock<IOrderValidator>();
validatorStub.Setup(v => v.Validate(order)).Returns(false);
Locator.Register(() => validatorStub.Object);

What is even more annoying is that because the Locator’s internal store is static, we need to invoke the Reset method after each unit test, but granted: that is mainly a unit testing issue.

All in all, however, we can’t reasonably claim that this sort of API provides a positive developer experience.

Maintenance issues

While this use of Service Locator is problematic from the consumer’s point of view, what seems easy soon becomes an issue for the maintenance developer as well.

Let’s say that we need to expand the behavior of OrderProcessor to also invoke the IOrderCollector.Collect method. This is easily done, or is it?

public void Process(Order order)
{
    var validator = Locator.Resolve<IOrderValidator>();
    if (validator.Validate(order))
    {
        var collector = Locator.Resolve<IOrderCollector>();
        collector.Collect(order);
        var shipper = Locator.Resolve<IOrderShipper>();
        shipper.Ship(order);
    }
}

From a pure mechanistic point of view, that was easy – we simply added a new call to Locator.Resolve and invoke IOrderCollector.Collect.

Was this a breaking change?

This can be surprisingly hard to answer. It certainly compiled fine, but broke one of my unit tests. What happens in a production application? The IOrderCollector interface may already be registered with the Service Locator because it is already in use by other components, in which case it will work without a hitch. On the other hand, this may not be the case.

The bottom line is that it becomes a lot harder to tell whether you are introducing a breaking change or not. You need to understand the entire application in which the Service Locator is being used, and the compiler is not going to help you.

Variation: Concrete Service Locator

Can we fix these issues in some way?

One variation commonly encountered is to make the Service Locator a concrete class, used like this:

public void Process(Order order)
{
    var locator = new Locator();
    var validator = locator.Resolve<IOrderValidator>();
    if (validator.Validate(order))
    {
        var shipper = locator.Resolve<IOrderShipper>();
        shipper.Ship(order);
    }
}

However, to be configured, it still needs a static in-memory store:

public class Locator
{
    private readonly static Dictionary<Type, Func<object>>
        services = new Dictionary<Type, Func<object>>();
 
    public static void Register<T>(Func<T> resolver)
    {
        Locator.services[typeof(T)] = () => resolver();
    }
 
    public T Resolve<T>()
    {
        return (T)Locator.services[typeof(T)]();
    }
 
    public static void Reset()
    {
        Locator.services.Clear();
    }
}

In other words: there’s no structural difference between the concrete Service Locator and the static Service Locator we already reviewed. It has the same issues and solves nothing.

Variation: Abstract Service Locator

A different variation seems more in line with true DI: the Service Locator is a concrete class implementing an interface.

public interface IServiceLocator
{
    T Resolve<T>();
}
 
public class Locator : IServiceLocator
{
    private readonly Dictionary<Type, Func<object>> services;
 
    public Locator()
    {
        this.services = new Dictionary<Type, Func<object>>();
    }
 
    public void Register<T>(Func<T> resolver)
    {
        this.services[typeof(T)] = () => resolver();
    }
 
    public T Resolve<T>()
    {
        return (T)this.services[typeof(T)]();
    }
}

With this variation it becomes necessary to inject the Service Locator into the consumer. Constructor Injection is always a good choice for injecting dependencies, so OrderProcessor morphs into this implementation:

public class OrderProcessor : IOrderProcessor
{
    private readonly IServiceLocator locator;
 
    public OrderProcessor(IServiceLocator locator)
    {
        if (locator == null)
        {
            throw new ArgumentNullException("locator");
        }
 
        this.locator = locator;
    }
 
    public void Process(Order order)
    {
        var validator = 
            this.locator.Resolve<IOrderValidator>();
        if (validator.Validate(order))
        {
            var shipper =
                this.locator.Resolve<IOrderShipper>();
            shipper.Ship(order);
        }
    }
}

Is this good, then?

From a developer perspective, we now get a bit of help from IntelliSense:

image

What does this tell us? Nothing much, really. Okay, so OrderProcessor needs a ServiceLocator – that’s a bit more information than before, but it still doesn’t tell us which services are needed. The following code compiles, but crashes with the same KeyNotFoundException as before:

var order = new Order();
var locator = new Locator();
var sut = new OrderProcessor(locator);
sut.Process(order);

From the maintenance developer’s point of view, things don’t improve much either. We still get no help if we need to add a new dependency: is it a breaking change or not? Just as hard to tell as before.

Summary

The problem with using a Service Locator isn’t that you take a dependency on a particular Service Locator implementation (although that may be a problem as well), but that it’s a bona-fide anti-pattern. It will give consumers of your API a horrible developer experience, and it will make your life as a maintenance developer worse because you will need to use considerable amounts of brain power to grasp the implications of every change you make.

The compiler can offer both consumers and producers so much help when Constructor Injection is used, but none of that assistance is available for APIs that rely on Service Locator.

You can read more about DI patterns and anti-patterns in my upcoming book.

Thursday, February 04, 2010 12:17:26 AM (Romance Standard Time, UTC+01:00)
I couldn't agree more on this :), thank you for different examples.

I would like to hear your opinion, what do you think about a service locator that operates with dependency injection? So when you call the service locator it returns the requested type that was specified in the di wiring?
For instance.. many DI framework have trouble working without constructors as in .aspx, .asmx, .svc, how would you solve such scenario?
Thursday, February 04, 2010 10:54:32 AM (Romance Standard Time, UTC+01:00)
Sure, if you don't understand how something was meant to be used you can missuse everything.
A hammer is only aprobiate when you need to hit on something.

Servicelocator is only useable if you need to create dynamic objects inside your class,
otherwise it really is an antipattern.

The right thing to do is use Injection where the dependency tree is fixed and ServiceLocator
where you are sure you need to dynamicaly create something new ( in a factory for ex. ).
FZelle
Thursday, February 04, 2010 11:00:38 AM (Romance Standard Time, UTC+01:00)
I always struggle to do IoC without service locator for the exact reasons you stated, how do you get rid of all pesky little new operators. Much of the advice I've read is that passing around a container is a bad idea.

Lately, I've been using AutoFac more and more which, I feel, helps with these type of problems by using delegate factories. Be interested to hear your thoughts on if this is a good compromise?

BTW, nice pimp of your book, I might buy it if it's all this thought provoking :)

Thursday, February 04, 2010 11:18:41 AM (Romance Standard Time, UTC+01:00)
It's true that frameworks such as ASP.NET, PowerShell and the MMC SDK (but not WCF) are inherently DI-unfriendly because they insist on managing the lifetime of important objects. ASP.NET Page objects are the most well-known example.

In such cases you really have no recourse but to move the Composition Root into each object (e.g. Page) and let your DI Container wire up your dependencies from there. This may look like the Service Locator anti-pattern, but it isn't because you still keep container usage at an absolute minimum. The difference is that the 'absolute minimum' in this case is inside the constructor or Initialize method of each and every object (e.g. Page) created by the framework (e.g. ASP.NET).

At that point, we need to ask our DI Container to wire up the entire object graph for further use. This also means that we should treat the object where we do this as a Humble Object whose only responsibility is to act as an Adapter between the framework and our own code that uses proper DI patterns.

In ASP.NET, we can pull the container from the Application object so that we can have a single, shared container that can track long-lived (i.e. Singleton-scoped) dependencies without having to resort to a static container. This is by far the best option because there will be no 'virtual new operator' available further down the call stack - you can't call Locator.Resolve<IMyDependency>() because there will be no static container.

The Hollywood principle still applies to the rest of the application: Don't call the container, it'll call you. Instead of bootsrapping the application in one go from its entry point (as we can do in ASP.NET MVC) we need to bootstrap each created object individually, but from there on down, there will be no Service Locator available.
Thursday, February 04, 2010 11:32:56 AM (Romance Standard Time, UTC+01:00)
@FZelle: I don't agree that Service Locator is ever appropriate. The standard solution if you need short-lived or dynamically created objects is to use an injected Abstract Factory.
Thursday, February 04, 2010 11:46:45 AM (Romance Standard Time, UTC+01:00)
@Will: Autofac is just one among several DI Containers. I'm not yet that familiar with it, but if Delegate Factories are comparable to Windsor's Typed Factory Facility, it sounds like a good approach. In general Constructor Injection is preferrable, but there are many cases where you need a short-lived object.

This is where Abstract Factories bridge the gap. What is better about an Abstract Factory compared to a Service Locator is that it is strongly typed: you can't just ask it for any dependency, but only for instances of specific types.
Friday, February 05, 2010 5:03:54 AM (Romance Standard Time, UTC+01:00)
I just cannot agree. The problem with IntelliSense or Compiler doesn't make sense to reject the use of service locator. IMHO, the only problem for the misuse here is that the developer (or maintenance developer) does not know what service locator is and how it works. What about using Convention Over Configuration that we don't need to include the configuration file but specifying all the contracts and default implementations then initialize them at bootstrapper. Also, if you think the error is only found at runtime, we can do unit test to make sure all the dependencies are configured correctly before the component is delivered.
Huy Nguyen
Friday, February 05, 2010 11:13:48 AM (Romance Standard Time, UTC+01:00)
Huy Nguyen

Thank you for your comment.

Missing IntelliSense and compiler support are just two symptoms of a poorly modeled object model. You are in your right to disagree, but I consider good API design to be as explicit as possible and adhere to the Principle of Least Astonishment. It really has nothing to do with whether I, as a developer, understand the Service Locator (anti-)pattern or not.

A good API should follow design principles for reusable libraries. It doesn't really matter whether you are building a true reusable library, or just a single application for internal use. If you want it to be maintainable, it must behave in a non-surprising and consistent manner, and not require you to have intimate knowledge of the inner workings of each class. This is one of the driving forces behind Domain-Driven Design, as well as such principles as Command-Query Separation.

Any class that internally uses a Service Locator isn't Clean Code because it doesn't communicate its intent or requirements.

Unit tests may help, but it would be symptomatic treatment instead of driving to the core of the problem. The benefit of unit testing is that it provides us with faster feedback than integration testing or systems testing would do. That's all fine, but the compiler provides even faster feedback, so why should I resort to unit testing if the compiler can give me feedback sooner?
Saturday, February 06, 2010 10:19:12 PM (Romance Standard Time, UTC+01:00)
It's not an anti-pattern.

Actually - `anti-pattern` is not an antonym to `pattern`. Pattern does NOT say that something is cool and good per se in every imaginable situation.

Conclusion:

while these are definitely correct and good points you make and everyone should be aware of them, we return back to those boring phrases like =>

"use right tool for the job"

and

"it depends..."
Arnis L.
Saturday, February 06, 2010 10:45:04 PM (Romance Standard Time, UTC+01:00)
Arnis L.

Thank you for writing.

At the risk of taking the discussion in the wrong direction, "AntiPatterns" [Brown et al., Wiley, 1998] define an anti-pattern as a "commonly ocurring solution to a problem that generates decidedly negative consequences" (p. 7). According to that definition, Service Locator is an anti-pattern.

The reason I insist on protracting this semantic debate is that I have yet to see a valid case for Service Locator. There may be occasions where we need to invoke container.Resolve from deeper in the application than we would ideally have liked (the ASP.NET case described above in point), but that isn't the Service Locator anti-pattern in play, but rather a set of distributed Composition Roots.

To me, Service Locator is when you use the Resolve method as a sort of 'virtual new operator', and that is just never the right tool for the job.
Sunday, February 07, 2010 12:11:41 AM (Romance Standard Time, UTC+01:00)
People don't act accordingly to mentioned definition. That's their nature. Anyway - direction is surely wrong.
What's interesting - i started to feel like you - can't find reason for service locator.
Good thing is - you gave a great push. At least - for me. Currently - clearing out confusion about IoC in my head.
Bad thing is - learning process is still in progress and i haven't found feeling that 'i know' to wholeheartedly agree with you.
Must confess that I've used related tools and techniques without necessary knowledge. :)
Arnis L.
Sunday, February 07, 2010 12:25:52 AM (Romance Standard Time, UTC+01:00)
To be fair, I must admit that I'm puposefully being rigid and unrelenting in my tone to get the point across :)

Here's an interesting confession: There are a few places in Safewhere's production code where we call Resolve() pretty deep within the bowels of the application. You could well argue that we apply Service Locator there. The point, however, is that I still don't consider those few applications valid, but rather as failures on my part to correctly model our abstractions. One day, I still hope to get them right so I can get rid of those last pieces, and I actually managed to remove one dirty part of that particular API just this week.

We are all only fallible humans, but that doesn't stop me from striving towards perfection :)
Monday, February 08, 2010 10:27:54 AM (Romance Standard Time, UTC+01:00)
@Mark:
And that abstract Factory is useing new xyz()?
No that Factory than needs the Servicelocator.
FZelle
Monday, February 08, 2010 3:25:36 PM (Romance Standard Time, UTC+01:00)
@FZelle: The Abstract Factory needs no dependencies since it's an abstraction (interface/abstract base class).

Concrete implementations of an Abstract Factory may very well need specific dependencies, which it can request via Constructor Injection - just like any other service.

The DI Container will then wire up the concrete factory with its dependencies just like it wires up any other service. No Service Locator is ever needed.

Here's just one example demonstrating what I mean.
Tuesday, May 11, 2010 4:14:21 PM (Romance Daylight Time, UTC+02:00)
In some advanced usage scenarios, dependencies are not always set in stone and known at design time, or even at application startup time. They could even change several times throughout the run-time of the application, so, having a service locator which can manage this reconfiguration aspect from a single place can be preferred.

This is similar to an abstract factory pattern, but it's much more feasible to implement when you have a ton of dependencies.

Additionally, if you consider a service oriented architecture where the services are well known and are always guaranteed to exist, but you just don't know where (could be on a separate server via WCF), then the service locator pattern solves a lot of problems.

Passing a ton of dependencies through dependency injection every time leads to unreadable code in my opinion. If by convention, the service is guaranteed to always exist, then Service Locator is a valuable pattern.

I would consider this to be an application of the Convention over Configuration paradigm.

However, it is a pattern that should only be used where it makes sense, I can see how abusing it would create more problems than it solves.
Andrei Alecu
Friday, June 11, 2010 5:52:33 AM (Romance Daylight Time, UTC+02:00)
@Andrei Alecu

Modern IoC containers let you resolve dependencies at runtime without using service locator. Windsor for example has several places where you can plug in to provide the dependencies, DynamicParameters method or OnCreated are just two examples from the top of my head. More generic solutions like handler selectors or subdependencyresolvers also exist.

In cases where you do need to trigger resolution of a dependency from the call site many containers provide autogenerated abstract factories (Windsor has TypedFactoryFacility which creates interface based factories and in trunk (v2.5) also delegate based factories).

So in my opinion using SL is just an excuse for being lazy. The only place where I'd use it (temporarily) is when migrating old, legacy code that can't be easily changed, as an intermediate step.
Thursday, July 22, 2010 1:54:25 AM (Romance Daylight Time, UTC+02:00)
Just came across this discussion. My opinion is whether you use ServiceLocator or not depends on your application requirements. What if you have to run inside or outside of a container environment? A service locator does make that situation much easier. What about SOA [implementation, not theory :) ]? SOA generally involves some service registry and service lookup. You can definitely look at that as a ServiceLocator implementation. There are good SOA design that have great merit, especially in a distributed environment where services are not guaranteed to be local.

The strength or weakness of your choice and use of patterns depends on how they meet your requirements. There is no one golden way. Dependency Injections is not a cure all nor was service locator when it became widely used. I use both and many others.

And how many patterns can you fit into the definition of "Anti-Pattern" if it is misused / abused?
Iran Hutchinson
Saturday, July 24, 2010 2:29:17 PM (Romance Daylight Time, UTC+02:00)
What do you mean by running "inside or outside of a container environment"? If you design your software appropriately, the presence of a DI container has no impact on the overall dependency usage. A DI container should resolve the appropriate object graph and get out of the way. This is what I call the Hollywood Principle for DI Containers: Don't call the container - it will call you.

In my opinion the SOA discussion is completely orthogonal to the discussion about the Service Locator (anti-)pattern. We shouldn't be misled by the similarity of names. The services located by a Service Locator are object services that may or may not encapsulate or represent an external resource. That external resource may be a web service, but could be something entirely different. When we discuss the Service Locator (anti-)pattern, we discuss it in the context of object-oriented design. Whether or not the underlying implementation is a web service is irrelevant at that level.

That said, I'm fully aware that many SOA environments work with a service registry. UDDI was the past attempt at making this work, while today we have protocols such as WS-Discovery. These can still be considered implementations of 'design patterns', but they certainly operate on a different architectural level. They have nothing to do with the Service Locator (anti-)pattern.

Nothing prevents us from combining proper Dependency Injection with service registries. They are unrelated because they operate at different levels, so they can be combined with exact the same flexibility as data access and UI technologies.

If we go back to the (original?) definition of the term anti-pattern from the book, an anti-pattern is characterized by a "commonly occurring solution to a problem that generates decidedly negative consequences". By that definition, Service Locator is an anti-pattern - even if you can come up with niche scenarios where it makes sense. So far, I've never been presented with a case for Service Locator where I haven't been able to come up with a better design that uses proper DI.
Saturday, July 31, 2010 7:04:02 PM (Romance Daylight Time, UTC+02:00)
Sauce béarnaise is a great way to start the book.

I first learned how to prepare sauce béarnaise when I started making Sole Wellington.

Reading book now, nice.

Cheers,

Karl
Sunday, August 01, 2010 2:42:21 AM (Romance Daylight Time, UTC+02:00)
I have multi-language / platform responsibilities which include .NET and Java Prior to DI being popular in Java many of us had requirements to run inside container (EJB, Spring, Pico, etc.) and outside of containers (just what was in the Virtual Machine libraries [prior to JDK version 1.5]). There was no DI available for free (unless you wrote it yourself). This is true still today in a number of environments.

If I go directly the posted definition of anti-pattern, which most can agree with, I can put a number of patterns that are not always anti-patterns in this category. I tend to emphasize proper pattern usage. Patterns are just tools that can be correctly or incorrectly. I have seen design-by-contract (interface pattern) used in a manner that fits the anti-pattern definition but I don't consider it an anti-pattern. I consider the use of pattern poor or inappropriate for that situation.

I consider SOA != Web services + UDDI + etc,. Web services and its relative technology stack can be used to implement an SOA. Therefore, from my perspective it is relative to this discussion and not orthogonal. In fact we had a discussion relative to these to these concepts last week in one of my current projects. The goal of that discussion was the abstraction of service implementation + location in a high-performance low-latency SOA design.

I am not a proponent of Service Locator or any other pattern. I us it and others with/without DI where appropriate. The perceived / actual negative impact of a pattern usage in one scenario does not apply to all scenarios. There are definitely patterns where one can get a majority agreement on them being anti-patterns. I just don't think Service Locator is one. However, the pursuit of try to qualify the validity of a pattern's usage or existence does generally lead to other solutions or ideas. Which I am a proponent of.

Cheers,

Iran
Iran Hutchinson
Friday, September 10, 2010 10:57:03 AM (Romance Daylight Time, UTC+02:00)
You have missed totally the point with service locator pattern. Probably you have done this intentionally, just to gain attention to try to sell a bunch of books. All you complaints can be equally applied to most DI implementations. In fact, many DI frameworks (Spring and Seam came into my mind), use a service locator internally and even let you to use it directly.

Service locator and DI, have essentially the same main downsides, and the only real difference is whether you prefer to retrieve the component from your code of to have it injected externally. In fact, and at least in the Java implementations i have worked with, you get less compiler support with DI variants, and also have a harder time to debug because of faulty injections. I am still amazed to see people arguing about how you get a dependency with a particular service locator implementation, when you a) can have a light wrapper to decouple from it and b) you get the same dependency with your particular DI implementation, you still have to tell de container what, how and when you need the injection, and thats a change too.

With you service locator example, you have only proved that it is also possible to write a crappy service locator implementation. And your moans are about that, not the pattern.
Al
Monday, May 09, 2011 6:01:54 PM (Romance Daylight Time, UTC+02:00)
Sure, Service locator is not the best way to implement kind of IoC. Your argument about hidden dependencies is certainly a good point.

Though, how many developers with good will and at least, average knowledge are trying to use IoC just to fail to understand how to set up their root components and bootstrap correctly their dependencies?

Now, imagine those who understand well those principles and techniques, trying to explain, guide, support an entire team of developers about those concepts...I guess you see (or have seen) like me those astonished developers faces trying to understand and not mess this magic behind dependency injection.

Ok, I'll admit it is not so hard. But still, my point is it is much harder to understand how those dependencies are injected and how not to mess and miss the point than using a simple Service locator instead of a "new" keyword.

And as someone else mention before, it is mandatory to use a Service locator with good convention-over-configuration to have fun with it. But it is the same with Dependency injection.

I see service locator as a first step for a team into IoC. After the concept and benefits are known by the team, I think it is much easier to turn the ship towards the Dependency injection final destination.

Good article and back and forth discussions here
Thanks
Phil
Phil
Saturday, May 28, 2011 3:03:55 AM (Romance Daylight Time, UTC+02:00)
What every article I read fail to show is how to use DI without some sort of container, or factory or locator or whatever is the name of the "thing" responsible for objects instantiation. It's no big deal moving all "new" keywords out of my "OrderProcessor" class, preparing them for injection via constructor or setter methods, but what about the calling object? Is it now responsible for "injecting" the dependencies? Should it instantiate them and pass to "OrderProcessor"? where is the value of this thing I may call "Inversion of Dependency"? Please show me where dependencies come from? Should the calling object call the DIC to instantiate "OrderProcessor" fulfilling its dependencies based on some configuration? No, because it is masking its dependency on "OrderProcessor", your calling object should have received the "OrderProcessor" beforehand. Allright, but now it's the calling object of the object who's responsible for passing all this chain of dependencies. I just don't get it, and I would love to understand this DI without "Container" thing!
Alex Brina
Saturday, May 28, 2011 11:20:34 PM (Romance Daylight Time, UTC+02:00)
With DI, all "new" keywords are being pushed to the entry point of the application. This is what is called the Composition Root. In this example I use Poor Man's DI towards the end of the post.

FWIW the first nine chapters of my book discuss DI mainly in the context of Poor Man's DI (that is, without containers).
Wednesday, June 01, 2011 5:35:52 PM (Romance Daylight Time, UTC+02:00)
Hello Mark,

thanks for you answer, I was subconsciously avoiding this concept of Composition Root, although I didn't know why. But today I came to some code that shed some light on it, and the driving force against using the entry point for dependecies instantiation was my understanding of "encapsulation". As I see it, some dependencies should not be known outside the object. The code I mentioned, for instance, is a class named "Syncronizer" which defines a sequency of "Steps" (each step is an object), the sequence and steps are defined internally and it is the Syncronizer's sole responsibility, chosen steps are "instantiated" internally (say 10 of 30 available), The entry point isn't aware of which Steps would be needed. AS I see, there is something in DI that goes against "encapsulation". Would love to know your thoughts about it.

Alex Brina
Alex Brina
Wednesday, June 01, 2011 8:49:49 PM (Romance Daylight Time, UTC+02:00)
DI doesn't go against encapsulation, which is one of the most misunderstood concepts in OOP.
Monday, July 11, 2011 10:14:36 AM (Romance Daylight Time, UTC+02:00)
Mark - I love this post. I'm diving into IoC and planning to use the Unity framework and one of the first and immediate problems I ran into was the need to resolve types deep within the object hierarchy. So of course, first thing I did was search for common ways to do this.

1. Passing around the container was obviously the wrong approach
2. A global, static container also "felt" like the wrong approach... the business code shouldn't need to know that much about the application domain.
3. A very common solution around the web is the ServiceLocator pattern, but - the reason I continued looking is that pattern just "felt" wrong to me in an intuitive sense - it's essentially no better than (2) and as you say, the container begins to invade the business logic. Now, the entire architecture has to know about the container - which completely defeats the purpose of DI and IoC.

So then I stumbled upon your post and it summed up EXACTLY why those approaches "felt" wrong - and also helped me re-orient my thinking with regard to where to create the containers.

I don't NEED a single container for the whole application, I only need them within the scope where they're required. If I have a type that is only ever instantiated 4 levels deep in the object hierarchy, it makes no difference whether I register the type at the root of the application or scoped to the code where that type is relevant. Thus, in order to prevent the container from invading the application in the ways you describe, it makes perfect sense to create the container at a lower level (what you call the Composition Root?).

Really like your blog. I appreciate the dedication to design principles that seem so easily thrown away when pragmatism requires.
Patrick Sears
Wednesday, July 13, 2011 10:03:58 AM (Romance Daylight Time, UTC+02:00)
I constantly get this when attempting to post a comment:

An error has been encountered while processing the page. We have logged the error condition and are working to correct the problem. We apologize for any inconvenience.

Page rendered at Wednesday, July 13, 2011 8:02:11 AM (Romance Daylight Time, UTC+02:00)
Danil
Wednesday, July 13, 2011 11:44:26 AM (Romance Daylight Time, UTC+02:00)
Yes, the software hosting this blog is crap, and migration is on my to-do list. The error usually has something to do with the use of angle brackets.

Sorry about the inconvenience.
Wednesday, October 05, 2011 2:20:20 AM (Romance Daylight Time, UTC+02:00)
Hi Mark,

Apologies for the necromancy, but I googled for 'Service Locator anti pattern' and this post is one of the top-five hits.

I totally agree that Service Locator is an anti-pattern. It's the use of the static class/property that makes it so insidious. It's an example of a Skyhook (http://garymcleanhall.wordpress.com/2011/07/24/skyhooks-vs-cranes/) as opposed to DI, which is a Crane.

Service Locator seems to be preferred because the alternative is sometimes to write a constructor to inject half a dozen (or more) dependencies, ie: it smells like the class has too many responsibilities.
Wednesday, October 05, 2011 11:39:30 AM (Romance Daylight Time, UTC+02:00)
Saturday, October 08, 2011 6:19:33 PM (Romance Daylight Time, UTC+02:00)
A google Tech Talk that addressed pretty much the same issue in 2008 can be seen here:
http://googletesting.blogspot.com/2008/11/clean-code-talks-dependency-injection.html

Mohammed
Monday, October 17, 2011 9:00:52 PM (Romance Daylight Time, UTC+02:00)
I actually don't see a problem with the user of the service locator. In the case of both IOC and the service locator, you have the same problems. The only question is how much indirection you want shown the client of the service.

API Usage Issue:
In the case of both IOC and Service locator, there is an independent class that is responsible for making sure that the appopriate service (IOrderValidator or IOrderShipper) is found by the client. The only difference is whether the client automatically receives the information or if the client makes an explicit call to a 3rd party class (Locator) to find it. It is more a semantic argument than anything else.

If the configuration of the IOC is done incorrectly, you will also receive an exception. The problem is with the management of the configuration as opposed to the service locator itself.

Maintenance Issues:
Same problem as above. This is a problem with configuration of the service as opposed to the way in which IOC or service locator is used.

With both service locator and IOC, someone is going to have to understand all the dependencies in order to configure the services correctly and ensure that the correct service is returned when called upon. This configuration is part of the setup of the service contract. Whether or not this configuration is done through an IOC container or through a service locator seems immaterial.
KT
Friday, October 28, 2011 11:47:07 AM (Romance Daylight Time, UTC+02:00)
=== Service Locator is NOT an anti-pattern ===

Sorry, I cannot agree with author’s statements from practical standpoint. If you discuss pure theory and your team has unlimited resources for your projects - you can use all kind of nice patterns that require more work and give some advantage.

Let's compare advantages and disadvantages and not just talk about pros on one side.

I talk from practical large scale software Dev experience when your product is not one-man show but you have mature product with a lot of components, several teams, and engineers coming and leaving. Is it what we all try to get to? If you are talking about one-man show project or small-highly-skilled team project and you work on v1 or v1.1 of your product - sure you can use any pattern and dependency injection through constructor parameters would probably work for you.

===========================

== Service Locator advantages ==

1. Much smaller production code. No need to declare variables, parameters to pass dependencies, properties for stateful objects, etc.

Every line of code/symbol has associated Dev/QA/support cost. Smaller code is easier to understand and update.

2. Much smaller unit test code. No need to instantiate and pass dependencies - you can set all common dependencies in TestSetup and reset them in TestCleanup. Again, every line of code/symbol has associated cost.

3. Much easier to introduce dependencies. Yes, this is an advantage, because you need to write much less code for this if you use Service Locator. And again every line of code....

Imagine you need to add SQL performance logger deep in the code and of course you want all your DB access methods use the same logger instance no matter how you get there from business logic layer. You have to change all stack of callers if you do not use Service Locator.

And if you have to change any caller because of your method change -this can be a huge problem in mature product. There will be no way you can justify expenses for a new release of the calling component to you management.

== Service Locator disadvantages ==

1. Introduced dependencies are not captured at compile time.

How to fix this? The answer is - test your product (with automatic integration or manual tests). But you have to test only changed functionality to make sure that feature that uses new introduced dependency works correctly. You need this anyway and this is already in the plan/budget for your project/change anyway.

Did I miss anything?

===========================

We’ve tried to use dependency injection and switch to Service Locator turned out to be such a huge relief
that we would never even consider switching back.

== My conclusion ==

If you are working on long-term project and you have to implement cost-efficient solution, maintainable by the team with various skill levels - Service Locator is significant cost saver for you with small to none down sides.

If quality is your first priority and budget/time-to-market is not an issue and you have skilled team - do not use Service Locator and rely as much as possible on compile time checks.
Vlad
Thursday, November 24, 2011 2:59:27 PM (Romance Standard Time, UTC+01:00)
I couldn't agree more.

We could say the container itself should not be a dependency, and hance should not be passed around, as stated in this StackOverflow question.
http://stackoverflow.com/questions/4806918/should-i-be-passing-a-unity-container-in-to-my-dependencies

To me, Service Locator is the exact opposite of Inversion of Control.

http://stackoverflow.com/questions/2386487/is-it-better-to-create-a-singleton-to-access-unity-container-or-pass-it-through is another great StackOverflow question about this topic (no surpsise the correct answer is by Mark Seemann himself.
Thursday, December 15, 2011 11:02:34 PM (Romance Standard Time, UTC+01:00)
The problem with your argument is that you state "I don't agree that Service Locator is ever appropriate", then provide one contrived example where Service Locator is implemented poorly. All you have proven is Service Locator might not be the best pattern to solve this problem (although you don't prove that either by defining a better solution). It seems that you started with the conclusion and derived the premise.
Barley N. Hopps
Tuesday, January 31, 2012 2:54:49 PM (Romance Standard Time, UTC+01:00)
I vehemently disagree with your premise that service locator itself is an anti-pattern. The service locator is an invaluable pattern when it is needed, and it fulfills roles that there are no other solutions to, other than poor implementations of the service locator pattern.

Do people apply it in less then optimal scenarios? Absolutely. Does that make a pattern, an anti-pattern? Absolutely not.
All comments require the approval of the site owner before being displayed.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, b, em, i, strike, strong) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview