views:

460

answers:

6

I have been reading up on Dependency Injection frameworks. I really fell in love with the idea of separating the concerns and letting the objects do their core work - which is undoubtedly an excellent and long-standing design principle!

However the more I read on DI frameworks, the more I get worried: 1) In the way they "automagically" resolve dependencies 2) About the extreme complexities being introduced in the configuration files

On just the point #2, I have seen my customers spend millions of dollars to train the people on products of which the significant part was how "not" to touch config files. The administrators are now dreading these config files.

Nevertheless, I see another pattern called Service Locators where I could nicely assemble all the "global" services that I want at the start of my application (may be an application host or app context or whatever). Make this service locator globally available and voila!

However I see that there will be less flexibility when using the Service Locator approach when I need more than one type of "global" service based on some criterion (known to whom?)!

So, here I am more confused than before on which direction to take. Though I like the design principle very much, the complexity in the existing frameworks are throwing me off!

Are my concerns genuine? Anybody else feel the same? If so, is there any good alternative for such massively overwhelming "frameworks"?

EDIT: Thanks everyone for excellent set of answers. I am now more convinced that DI is not that problematic and you can contain the mayhem of configuring the DI containers. I'd prefer to go the route of Autofac and see if I would stumble upon any issues.

Thanks StackOverflow!

A: 

Depending on the language you use there are some DI frameworks that aren't as scary, though you will have some config files, but they shouldn't be scary, but useful.

For example, I have one config file for development, one for testing and one for production.

So, depending on the one I use, the database connections can be changed, and I can swap out the database layer for tests, and use mock tests.

The sysadmins should control the production config files, as the developers shouldn't push anything to production, ideally.

Spring has a nice setup for DI, though it isn't lightweight.

I have found that the Unity Framework isn't trivial to learn, but once you are using it it is pretty easy to add new classes for injection.

So, anything new may be scary, initially, but as you get comfortable with the concept you can see advantages, such as I explained about the three config files.

James Black
Though my question was in light of seeking a good design practice, I am particularly concerned with .NET framework and C# language, so we can scope the discussion.The kind of config files that are dreading are the ones that you would see that come with the Enterprise Library Logging for instance. The logging component after all is most concerned for admins, and alas they can't change the log target so easily without having to understand what a listener is, what a log source is, what a log level is and what filters are ... and on and on !
Charles Prakash Dasari
So why not just use a simpler DI framework and inject in the logging that you need, to simplify the config files?
James Black
A: 

My situation may be different than yours in that we already have a system designed for very flexible configuration so adding dependency injection to that configuration was almost trivial, but it seems to me that using the service locator pattern will not save you much configuration as you must still specify how to locate the services. Being able to flexibly inject mock objects for testing is an almost invaluable benefit to using dependency injection, so I would say that configuration overhead may just be a cost of doing business you need to accept to gain the benefits.

Aneurysm9
I totally get the point about being able to use a different set of mock objects for testing in such a pattern. However, that needn't be tied up with a config file that is shipped and (almost) never touched by admins as they dread it... May be the app host should initialize all the services in the code (and the app hosts could be different in different scenarios, test host, production host etc)
Charles Prakash Dasari
Yes, our config system has a default configuration inline in the code that can be overridden at any number of deployment levels in a fine-grained manner. If the default configuration is correct and usable, there is no need for additional configuration, but the option is always there.
Aneurysm9
That option is the one that is dreading and makes the configuration less useful for the end-user admins that I was dealing with. May be your situation is different.
Charles Prakash Dasari
In many cases, an IoC configuration file isn't for 'configuration' so much as it is building your object graph...
kyoryu
+1  A: 

Neither of these are "required" for DI - they are options supplied by some DI frameworks. Personally, I dislike the "automagic" injection too - I can see it working for really small projects, but causing problems on larger projects. For point #2 - I'm not sure I get the point - I've mostly used Spring. Spring provides both XML and Java configuration options. It provides nested configurations. If there's a part of the configuration that you don't want anyone to change and there's a part that you do - separate them into separate configuration files - or make the "changeable" one XML and the other Java. Spring also supports using values from property files - see an example here - which is all that I'd expect administrators to change - administrators aren't programmers - they shouldn't be "re-wiring" your app - just providing appropriate options.

Nate
Thanks for your answer. The config example that you showed is complex enough for most of the IT people I dealt with for a large customer, which ended up in us writing a big manual about configuration options. It is definitely much better than other configs I saw with other frameworks.
Charles Prakash Dasari
+2  A: 

As Nate mentioned, the "magic" is optional; you can configure everything by hand if you want.

I'd avoid the configuration files initially (or forever!) and configure the container in code. That tends to be much easier to read and maintain. Much of the time you don't need on-the-fly changes to configuration. Customers can't touch the configuration files because they don't exist.

Service locators have downsides; for one, they tend to couple your classes to the locator class/framework. A good DI framework will let you use Plain Old Objects; you may only have a single class in your project that actually uses the DI/IoC framework.

StructureMap and Unity are both pretty simple; give them a try. Start small.

Here's a really simple example with Unity (including inline configuration):

using Microsoft.Practices.Unity;

static void Main()
{
    using (IUnityContainer container = new UnityContainer())
    {
        container.RegisterType<IRobot, MrRoboto>();

        Console.WriteLine("Asking Unity container to give us a Model...");

        Model model = container.Resolve<Model>();
        model.MoveRobot();
    }
}

// class Model

public Model(IRobot robot)
{
    // Unity will hand the constructor an instance of MrRoboto!
}
TrueWill
Thanks for your answer and example.To fully appreciate your example and compare it with SL, I need to understand how such a configured container(IUnityContainer) object is passed around in the code wherever I need to resolve an object that would be dependent on other objects. My framework/app has around 15 such dependencies (persistent layers, security mechanisms, error handlers, loggers etc).None of the examples I have seen so far have clearly addressed this fact without having a "complex" configuration file.If you have any examples, please point me to them and I will review.
Charles Prakash Dasari
For the most part you don't need to pass around the container. You've probably got one class that's the "start" of your application (Main method, WebMethod, etc.), right? And that creates objects, which in turn create other objects, and so forth. So say in the above example that Model needs a Foo class which needs a logger. Constructors might be public Model(IRobot robot, IFoo foo) and public Foo(ILogger). You'd RegisterType<IFoo, Foo>() and RegisterType<ILogger, Logger>(). Done. The container creates everything and wires it up.
TrueWill
I guess that is what I am missing to see, an example could help. Say, I have a webmethod, that is doing some parameter validation and handing off the call to business logic, which does some business validations, triggers a workflow and somewhere inside the workflow I hand off to the persistence layer to save the object. Now as you can imagine there are several dependent objects I would need along the way. How would they get them? Do I need any singletons?
Charles Prakash Dasari
I have been missing to see the core point about not many places will we need to configure the containers. I guess I will have to muddy the waters a little bit to lay off my fears.Marking this as the answer as I got most of my questions answered.
Charles Prakash Dasari
You should only need to declare a dependency on the container for classes that will need to dynamically create new objects. And to do so, normally you simply add the container to itself, and declare it as a dependency just like any other dependency.
kyoryu
The only way to truly learn it is to take one or more of the frameworks/libraries and try it. Go with the examples in the documentation. Keep it simple. Don't use it on a production project at first; create a small learning project and try different scenarios. That's what I did with several of the frameworks.And to kyoryu, another way to do that is to inject a dependency on a class factory. Whatever works best.
TrueWill
+2  A: 

If you're really thinking about going the Dependency Injection route, I highly recommend giving Martin Fowler's excellent dependency injection article a quick read:

http://martinfowler.com/articles/injection.html

I'm working on a Java project right now with lots of configuration files. We opted up-front for a Singleton pattern to represent our configuration (somewhat analagous to a global solution). Here's the things that drive me insane and make me wish we had a Dependency Injection pattern instead:

  1. Unit testing with globalized patterns sucks. Dependency Injection patterns lend themselves readily to easier unit testing and especially mock object testing. In the singleton-type case, you now have all these unit tests that still need a global state available in order to run. With dependency injection, you can make test-specific mock configuration objects that you pass into your tests. I can't overstate how much easier this makes unit testing. Another excellent paper entitled "Endo-Testing: Unit Testing with Mock Objects": http://connextra.com/aboutUs/mockobjects.pdf

  2. Using a globalized sort of approach works better in smaller systems, but as your numbers of threads grows, they all begin to compete for the configuration resources. You can run into synchronization issues and your configuration accesses can even start to become a bottleneck. This hasn't been a huge problem for us yet, but it's beginning to annoy us all.

  3. Once you go a little ways down a non-dependency injection route, there's no real going back. Going from dependency injection to some sort of globalized pattern is annoying, but doable on a sort of step-by-step basis. Trying to go from a globalized pattern back to dependency injection is a nightmare. I keep wanting to do it on our project and I just can't. It would take an entire development cycle.

Anyway, hope the article and the experience help you make a decision. I'm a long ways down the path you're thinking about heading down and I kinda wish we would've taken the dependency injection route instead :-D

Brent Nash
I already read Martin Fowler's article before posting here and then I went the route of considering Service Locators and hence the nightmare of the configuration of so many frameworks available out there! Nevertheless, I am now convinced that pure DI is the way to go! Thanks for the pointers to the articles anyway!
Charles Prakash Dasari
+2  A: 

I personally quite enjoy using Autofac. The container configuration is done through code, at the same time eliminating verbose XML and enabling refactoring support.

One of the best features, though, is modules. They are units of container configuration, allowing you to manage the complexity of the many different components which comprise your application.

I am currently working on a very large project, and the experience is roughly the same as when it was small, meaning this approach scales very well.

A main tenet of DI-enabled classes is that they do not reference infrastructure code. This is the antithesis of the Service Locator pattern. The main downfall of Service Locator is that, in addition to adding complexity to classes which reference the container, there is no ability to change which version of a dependency is resolved.

With "pure" classes that don't reference a container, the resolved version of any given dependency is external to the class being injected.

Bryan Watts
+1 for Autofac and modules.
Charles Prakash Dasari
With most IoC containers, *most* classes shouldn't even know about the container... that's (one of) the advantages of an IoC container vs. a Service Locator
kyoryu
You're right, only top-level application classes know about the container. This really comes in handy when unit testing - you don't have to set up a container or any context to use "pure" classes, you as the test writer just play the part of "composer".
Bryan Watts