Why do I need an IoC container as opposed to straightforward DI code? [closed]
I've been using Dependency Injection (DI) for a while, injecting either in a constructor, property, or method. I've never felt a need to use an Inversion of Control (IoC) container. However, the more I read, the more pressure I feel from the community to use an IoC container.
I played with .NET containers like StructureMap, NInject, Unity, and Funq. I still fail to see how an IoC container is going to benefit / improve my code.
I'm also afraid to start using a container at work because many of my co-workers will see code which they don't understand. Many of them may be reluctant to learn new technology.
Please, convince me that I need to use an IoC container. I'm going to use these arguments when I talk to my fellow developers at work.
Wow, can't believe that Joel would favor this:
var svc = new ShippingService(new ProductLocator(),
new PricingService(), new InventoryService(),
new TrackingRepository(new ConfigProvider()),
new Logger(new EmailLogger(new ConfigProvider())));
over this:
var svc = IoC.Resolve<IShippingService>();
Many folks don't realize that your dependencies chain can become nested, and it quickly becomes unwieldy to wire them up manually. Even with factories, the duplication of your code is just not worth it.
IoC containers can be complex, yes. But for this simple case I've shown it's incredibly easy.
Okay, let's justify this even more. Let's say you have some entities or model objects that you want to bind to a smart UI. This smart UI (we'll call it Shindows Morms) wants you to implement INotifyPropertyChanged so that it can do change tracking & update the UI accordingly.
"OK, that doesn't sound so hard" so you start writing.
You start with this:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime CustomerSince { get; set; }
public string Status { get; set; }
}
..and end up with this:
public class UglyCustomer : INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
string oldValue = _firstName;
_firstName = value;
if(oldValue != value)
OnPropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
string oldValue = _lastName;
_lastName = value;
if(oldValue != value)
OnPropertyChanged("LastName");
}
}
private DateTime _customerSince;
public DateTime CustomerSince
{
get { return _customerSince; }
set
{
DateTime oldValue = _customerSince;
_customerSince = value;
if(oldValue != value)
OnPropertyChanged("CustomerSince");
}
}
private string _status;
public string Status
{
get { return _status; }
set
{
string oldValue = _status;
_status = value;
if(oldValue != value)
OnPropertyChanged("Status");
}
}
protected virtual void OnPropertyChanged(string property)
{
var propertyChanged = PropertyChanged;
if(propertyChanged != null)
propertyChanged(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
That's disgusting plumbing code, and I maintain that if you're writing code like that by hand you're stealing from your client. There are better, smarter way of working.
Ever hear that term, work smarter, not harder?
Well imagine some smart guy on your team came up and said: "Here's an easier way"
If you make your properties virtual (calm down, it's not that big of a deal) then we can weave in that property behavior automatically. (This is called AOP, but don't worry about the name, focus on what it's going to do for you)
Depending on which IoC tool you're using, you could do something that looks like this:
var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper());
Poof! All of that manual INotifyPropertyChanged BS is now automatically generated for you, on every virtual property setter of the object in question.
Is this magic? YES! If you can trust the fact that this code does its job, then you can safely skip all of that property wrapping mumbo-jumbo. You've got business problems to solve.
Some other interesting uses of an IoC tool to do AOP:
- Declarative & nested database transactions
- Declarative & nested Unit of work
- Logging
- Pre/Post conditions (Design by Contract)
I'm with you, Vadim. IoC containers take a simple, elegant, and useful concept, and make it something you have to study for two days with a 200-page manual.
I personally am perplexed at how the IoC community took a beautiful, elegant article by Martin Fowler and turned it into a bunch of complex frameworks typically with 200-300 page manuals.
I try not to be judgemental (HAHA!), but I think that people who use IoC containers are (A) very smart and (B) lacking in empathy for people who aren't as smart as they are. Everything makes perfect sense to them, so they have trouble understanding that many ordinary programmers will find the concepts confusing. It's the curse of knowledge. The people who understand IoC containers have trouble believing that there are people who don't understand it.
The most valuable benefit of using an IoC container is that you can have a configuration switch in one place which lets you change between, say, test mode and production mode. For example, suppose you have two versions of your database access classes... one version which logged aggressively and did a lot of validation, which you used during development, and another version without logging or validation that was screamingly fast for production. It is nice to be able to switch between them in one place. On the other hand, this is a fairly trivial problem easily handled in a simpler way without the complexity of IoC containers.
I believe that if you use IoC containers, your code becomes, frankly, a lot harder to read. The number of places you have to look at to figure out what the code is trying to do goes up by at least one. And somewhere in heaven an angel cries out.
Presumably no one is forcing you to use a DI container framework. You're already using DI to decouple your classes and improve testability, so you're getting many of the benefits. In short, you're favoring simplicity, which is generally a good thing.
If your system reaches a level of complexity where manual DI becomes a chore (that is, increases maintenance), weigh that against the team learning curve of a DI container framework.
If you need more control over dependency lifetime management (that is, if you feel the need to implement the Singleton pattern), look at DI containers.
If you use a DI container, use only the features you need. Skip the XML configuration file and configure it in code if that is sufficient. Stick to constructor injection. The basics of Unity or StructureMap can be condensed down to a couple of pages.
There's a great blog post by Mark Seemann on this: When to use a DI Container