Hacker News new | ask | show | jobs
by nahname 4883 days ago
IoC is automating the code required to wire up objects that are properly decomposed.

When you spend a long time learning how to effectively work with static languages, a few things come out. Dependency inversion and composition.

Where does this leave us? It often means we have classes that need one or more other objects when they are instantiated. This often results in chains of objects. For example,

  new Repository(new SessionFactory(new Configuration()))
Writing that code is pretty painful. Rather than dealing with long chains of dependencies, manually wiring everything up. You define mappings and let an IoC container do it for you.

Why not just wire everything up manually in static functions and be done with it? It is really hard to change static code and often impossible to test it in a language like Java/C#. There is almost nothing you can do to test a piece of code that calls out to User.find(1) in one of it's methods.

Why are there no IoC practices in ruby? Primarily because the second point is no longer true (you can test everything easily). I still think there is merit in knowing the dependency chain rather than just calling User.find(1) and hoping that something somewhere conjures up a database connection and configures everything correctly, at the correct time.

IoC is control and automation. Those are both powerful tools to any programmer.

2 comments

> new Repository(new SessionFactory(new Configuration())) > Writing that code is pretty painful.

If you think you are making things less painful by obfuscating the code snippet above I would challenge you to think about what you are doing. The above is incredibly clear. There is no doubt what is happening and if you screw up the compiler will yell at you.

If you obfuscate it through annotations and force readers of your code to try to reason about how the system will behave runtime, you have added exactly zero value. You have only degraded the readability and understandability of the system.

A little extra typing never killed anyone.

> If you obfuscate it through annotations and force readers of your code to try to reason about how the system will behave runtime, you have added exactly zero value. You have only degraded the readability and understandability of the system.

I'd argue a few things here:

1. An IoC container that relies on annotations or XML configuration is not an IoC container that you should be using. Unless you're using an IoC container to help with field configuration, component registration needs to be done through a fluent API so that it's strongly typed and right there in the code where everyone can see it. A well-crafted registration routine should be every bit as readable as the hand-coded factory it replaces, if not more so.

2. Code that's architected in such a way that you need to understand explicit details about the order or manner in which objects are instantiated is code that is not ready to be used with an IoC container. The SOLID principles are a non-negotiable prerequisite of any IoC container. If you haven't drank that Kool-Aid, an IoC container doesn't really have a lot to offer.[1]

3. It's not about making individual snippets of code less painful. It's about making the long-term maintenance of the application - or, for preference, an entire suite of applications - less painful.

1: http://kozmic.net/2012/10/23/ioc-container-solves-a-problem-...

You don't annotate anything. It simply becomes the following,

  ...
  public Repository(ISessionFactory factory)
  ...
The repository never knows about IoC or where things come from. Nor should it.
Oh yeah, because pure magic makes it so understandable.
Everything you're saying is true. But so is a lot of what the author said. Especially in the last section.

I've run into situations with Windsor along the lines of what he describes, and it really is a distressing situation to be in. You're happily coding along, whipping the project together, hacking decorators, auto-registering everything with a great set of conventions, and generally having a grand old time. And then something goes kachunk and suddenly it's damn near impossible to figure out how to tell the container exactly how everything needs to be wired up without creating a raft of custom dependency providers to deal with special cases that the container just wasn't designed to handle properly. And the configuration becomes increasingly diffuse, devolving into a mishmash of conventions, manual registrations, and registrations that are implied by custom implementations of IFooResolverProviderFactory, until eventually you realize that you're working with a modern-day edition of what Dijkstra was talking about when he wrote GOTO Considered Harmful. And at that point it might be time to tearfully say goodbye to the IoC container and hand code some abstract factories, because not only will they be less opaque but you'll soon discover to your own horror that they actually reduce the SLOC count.

But - butbutbutbutbut - where I depart with the author is in thinking that this means that IoC containers are bad. Quite the contrary. Avoiding an IoC container because your dependency graph might, just might turn out to be more complicated than what the container was designed to handle is a premature optimization. And will probably lead to worse code than what you'll get if you start out with an IoC container and are forced to give it up later, since using an IoC container really does encourage SOLID code.

I guess what I'm saying is, IoC containers are only "mostly amazingly great." It's still a young technology with some kinks to work out. Even venerable old Windsor is still experiencing significant API flux. They don't necessarily have an answer to every use case yet, even if they are getting damn close.

Oh, and writing libraries. If you're a library, you are not the composition root, by definition. And if you're not the composition root, you don't get to use an IoC container. Sorry. Have a facade.