views:

895

answers:

7

I see lots of articles saying how great IoC and DI are and none about why it isn't so great because it can make code more complex. I see also that IoC shouldn't be in the core part of your code but more for libraries and plug-ins. Articles usually a small reference to how the two patterns can make code more complicated but not much on the details of that. That is my question - where specifically should you not use these patterns?

This is a nice thread: http://stackoverflow.com/questions/3058/what-is-inversion-of-control. If you look further down, there is a post about the spell checker and another post about how IoC is probably not a good use there if it is only one spell checker. As a general guideline, should IoC not be used of I ever have only one concrete class for the interface? Meaning, I have IMyClass. And then have just the concrete MyClassA that implements IMyClass. Why would I want IoC there?

If I had MyClassA, MyClassB and MyClassC, that each implement IMyClass, those are probably good candidates for IoC correct?

From the same thread, does anyone know what this post means:

  • Inversion of Control = Marriage
  • IOC Container = Wife
+3  A: 

From the Castle Project:

Why would I not use it?

You should not use an Inversion of Control container if you are not familiar with the concepts and if you do not realize the problems they try to solve.

Also, depending on the size and complexity of the project, an IoC container might be overkill. Prefer to use it on medium to large projects.

Austin Salonen
-1 "You should not use ??? if you are not familiar with the concepts and if you do not realize the problems they try to solve." That is a tautology, as it applies to any ???.+1 the second reasons is good.
flybywire
#1 is really more common sense than anything else and yet a simple, earnest "do you know what you're doing?" query is the simplest code review you can do.
Austin Salonen
Small apps tend to become large ones. When you write your small app like a small one and it becomes a large one, you get a mess. When you write your small app like it's a large one and it becomes a large one, everything works fine. The only downside is having to listen to people whine about "overengineering".
jrockway
@jrockway -- That's been my experience as well. The nice part about a good IoC container is that a big project can appear small.
Austin Salonen
This is an aside question: Is there any need for IoC or ID with static classes?
4thSpace
@4thSpace -- I'd say no but you should be careful with static classes anyway. They become "convenient" and then a god object and then impossible to test and then a big source of problems.
Austin Salonen
+9  A: 

About your question about having only one interface implementation. When you use IoC, it is still useful to use an interface. It will be much easier to create real unit tests (that doesn't depend on the interface implementation to be working correctly) using mocks for these interfaces. The core of using IoC is making code easier to test. So, don't use IoC if you don't want to test, or already have a better plan on testing without it.

IMHO, DI and IoC increase in complexity comes is paid by having an easier to test and less coupled code. It's easier to isolate the problems and to make future changes. You can control its behavior better too.

I can see when not to use an IoC container (as it results in configuration overhead). This would happen on small projects, where you can do it manually, instead of using a container. But I can't see much loss from using DI, unless you're not planning to test your code...

Samuel Carrijo
Wouldn't an improved refactoring of design eliminate the need for IoC and DI? I ask because IoC and DI aren't at all expressive (i.e. readable). If the code can be refactored to create readability and the independence that IoC strives to achieve, I believe you end up with a better solution. It's possible you may still fall short on the mock testing part by not using IoC and DI though.
4thSpace
IMHO, IoC and DI increases readability, once I know what the object needs. If your constructor has too many params, you may be doing too much inside that class, and you should refactor
Samuel Carrijo
Also, most programming languages other than Java have "named initargs", further reducing any readability problems that DI-style would introduce.
jrockway
+3  A: 

The complaints about IoC are easy to understand: IoC turns something simple into something complicated. Let's say you wanted to do something to each element of a list (in pseudocode):

for each i in list:
    do_something(i)

IoC, essentially, is moving the responsibility for loop iteration to someone else. Thus, we end up with something more like this:

ioc = new IocContainer()
ioc.register_callback(do_something)
ioc.go()

Notice that even in this simple form, the code is longer than the original... and that's not counting the implementation of IocContainer.

Then, in its fanciest form, the IocContainer can get initialized statically or by a static Main() function or somewhere else hidden away, and the register_callback() functions get called automatically based on some other code that iterates through an XML file that lists all your do_something() functions and (sometimes) even the contents of the lists to iterate through.

Yay, the XML file has made your software more configurable! Right? You can change which somethings are done to your list just by changing a simple text file!

Except, ironically, your source code is now longer and harder to understand, it depends on all sorts of new, possibly buggy, libraries (including the IocContainer and an XML parser), and you've actually made it harder to maintain: XML code is harder to understand and edit than the original simple source code loop (no matter what language the loop is written in). You also have less control over exactly how you want to do the iterating (sorted or unsorted? depth-first or breadth-first?) since IocContainer is taking that responsibility away from you.

For things like plugins, it can make sense to use IoC, since it's logical for the main application to be in control of the execution process, and to just ask the plugin for help here and there. This is called "providing hooks" and has been around much longer than the IoC terminology.

For things like unit tests (which is where I've usually seen it thrown around), IoC usually turns out to be unhelpful, because your tests need to be able to simulate a wide variety of odd situations, and IoC just constantly gets in the way of this.

The fundamental assumption of IoC is that loading data and looping through is somehow difficult and needs to be abtracted away; this assumption just isn't true, because it was never more than a couple of lines anyway (or you could move it to a separate function), and even if it did save code, it reduces your flexibility.

apenwarr
I am not going to write a long essay to refute this, but basically, I disagree. Your first example is orthogonal; "for each i in list" should be rewritten to be a fmap over a Functor. This is not related to dependency injection. As for DI, I have found that it makes "major" changes to my app much easier. I don't have to restructure a bunch of code "in the middle" if something "further down" needs a new piece of data. It lets my object graph builder deal with the details, and it makes my code more modular. Both good!
jrockway
"...my object graph builder ..." Is there a good example of what an object graph is in .NET?
4thSpace
+6  A: 

Using an IoC container or not isn't a decision to make at the level of individual classes - in any project you'll have types that are and aren't created by the container.

The complexity tradeoff is this:

  • For a small number of components, an IoC container does add some overhead
  • As the number of components in an application increases:
    • Without an IoC container, adding new components or refactoring tends to get increasingly difficult
    • With an IoC container, adding new components or refactoring stays the same: you only ever need to worry about the immediate dependencies of the component you're adding or changing.

If you've ever experienced the phenomenon of even a well-designed and maintained codebase becoming unmanageable with size, you've experienced the problem that IoC containers solve.

Nicholas Blumhardt
+2  A: 

IoC/DI are not technologies, they are paradigms. Your question is akin to asking "When should I not use object-oriented programming?" It is a decision that is bigger than the individual units of your codebase.

To answer your specific question, if you have few enough classes where you can reasonably construct object graphs by hand, and you are not repeating the same object graph instantiations multiple times, you might not need an IoC container.

Bryan Watts
Can you explain object graph?
4thSpace
An object graph (en.wikipedia.org/wiki/Object_graph) describes the relationships between runtime instances. For example, let's say `FooService` has an `IBarRepository` as a constructor dependency, and you fulfill that with an instance of `BarRepository`. The object graph would then be `FooService0 -> BarRepository0`. Since an IoC container fulfills all the dependencies, you can say that it builds the object graph.
Bryan Watts
A: 

I guess I'd say the simple answer only use IoC on objects you wish to unit test.

If this seems flippant I'm sorry, it's out of frustration at code written with literally NO consideration given to unit testing. I don't really understand why there is added complexity--if I needed to know the actual object type for sure I can always print out the class at runtime.

Bill K
+3  A: 

Inversion of Control = Marriage

IOC Container = Wife

Marriage is the definition of a known pattern - Wife is the implementation of that pattern ;-)

Bernard.

Bernard