Dependency InjectionApplicability, Benefits and Mocking

time to read 9 min | 1721 words

Jacob Proffitt continues the DI discussion, and he opens with this:

Ayende Rahien responded individually to each of my posts himself, which is more than a little bit intimidating all on its own

Despite rumors to the contrary, I want to mention that I abhor violence in all its forms. It always leads to having to fill forms in triplicate, and I got sick at that when they pulled form 34-C12 from the archives, just for me. Someone should remind me (on a non durable medium only) to demonstrate how you can get whatever you want, explicitly without violence in any form. It is both an interesting story, and it works.

Now, to Jacob's post, I will usually respond to things that I find interesting and rational, even if (or especially) if I do not agree.

All the heavyweight advocates of DI rely on powerful, relatively invasive tools to realize the benefits of Dependency Injection. Until you get those tools, the benefits of DI seem mainly theoretical.

Actually.... *drums roll* no.

Using DI with a container will certainly give you quite a few benefits, but you can get quite a bit from using DI directly. I met a guy in DevTeach which had done just that, with great success, using anonymous delegates and functional style. Nothing beyond a coding convention and what the language offered.

As an aside, I would accept the powerful, but I reject the invasive tools part. An good IoC can and should be invisible to anything but the Main() method. (There are shortcuts that are easier to take if you are explicitly aware of the container, but it is most often used on naked CLR objects).

The problem with DI, which is what the container want to solve, is that the moment you start injecting dependencies, you want some way to manage that, you can do that with a factory or a provider, but you get more benefits from using a container, since this allows you to centrally leverage some interesting concepts across the entire application.

If my client or company needs web pages that validate users against Active Directory and then allows them access to reports based on their group memberships, then telling me that I need some robust loose coupling framework in order to test my user maintenance library is flat out wrong.

Hm, let us see...

public interface IAuthorozationService
{
	bool Authenticate(string username, string password);
	bool AllowedTo(string action);
}

Simple, isn't it? That is what we used on our last project, and that is what enabled us to switch the implementation from hard coded (used on the staging site) to database back-end (staging site, when doing it hard coded started to take too long) and to active directory (production).

If it takes you more than a minute to write that, there is an issue here. If you consider direct coupling to the Active Directory classes, then there is an issue. If you tell me that you can get he same thing from:

public static class AuthorizationProvider
{
	public static bool Authenticate(string username, string password)
	{
		//...
	}

	public static bool AllowedTo(string action)
	{
		//...
	}

}

Then I argue that there really isn't any difference between the two, except that the interface based approach makes your collaborators easier to understand and work with. The second approach is a static Service Locator, which hides the dependency, but can do much the same as an IoC, but is more limited in terms of handling such things as life cycle.

Outside of major corporate infrastructure projects, stringent loose coupling just isn’t as much benefit as more naturally encapsulated OO techniques.

I strongly disagree, I find loose coupling to be an extremely useful idiom, important even in very small projects.image The ability to look at a piece of code in isolation is a key factor for maintainability.

So here we have a lot of architecture big wigs selling DI as best practices and not bothering to contextualize those statements at all. Again, Ayende is a good example of this. In Dependency Injection: More than a testing seam, he wraps up with "Dependency Injection isn’t (just) for testing, it is to Enable Change." Nice. So if I don’t use DI, my projects can’t change at all?

 And here I was hoping to avoid a wig for the next two years at least.

I am very bad in debate tactics (see first paragraph for why), but I do believe that reversing a sentence and then attacking the reverse conclusion is not a fair tactic.

The ability to change the code is strictly a matter of the quality of the code, the amount of tight coupling, the amount of separation of concerns that you have there. DI or lack of DI doesn't really into the equation on its own. You can certainly build DI-based projects that are impossible to change.

My argument is that DI is one of the tools that I use to make change possible. It is not the only one, naturally, and I am not saying it is the sole factor, but it is an important tool.

In addition to that, I don't think that I have ever said that DI is good for everything and you should use it the next time you want to build a hello world program. Most of the advice that I tend to give (or that given by the people I respect) usually has the "when applicable" part.

It all comes down to cost vs. benefit and that’s what I’m not seeing enough discussion of, here. What are the costs of using DI?

I think that the issues here are twofold, first, you see to significantly exaggerate the cost of using DI, out of proportion, I would say. The second is that you are trying to evaluate a part of the whole while refusing to consider the whole. DI is useful on its own, yes. It is much more useful when you have a container. There are different patterns for DI when you use a container and when you don't, and there are different usage scenarios.

Loose coupling is so far down my project priorities that standard OO practices are more than sufficient

Ookaaay.... so, according to you, this is a good approach?

public int GetCustomerCount()
{
	using(SqlConnection connection = new SqlConnection(Configuration.ConnectionString))
	{
		// ...
	}
}

To me such code suffers from a numerous major issues, ranging from flexibility of implementation to performance concerns to transaction semantics.

Only, everywhere I go for mock objects, I’m being told that all the best projects are loosely coupled so what kind of incompetent fool am I for not implementing DI even before I ever thought of needing a mock object framework?

Jacob, in this case, consider this an official invitation to the Rhino Mocks mailing list, and a promise to ban anyone calling anyone else a fool or an incompetent.

Yes, mocks objects goes hand in hand with DI, because you need to get the mock behavior there. Yes, you can use TypeMock, but as far as I am concerned, the moment that I am doing that, I am in the same boat as I am when I am trying to test private methods. There is no need to do that.

If I ever get into a project where loose coupling is a big enough concern that I have to consider seriously intrusive techniques in order to reduce the risks of dependency change,

Just to clarify, I find it hardly intrusive, and I am sadden to hear that you don't consider loose coupling (which also means SoC) is important to the code base.

Again, Ayende is an example of this attitude when he says, "The main weakness of Type Mock is its power, it allow me to take shortcuts that I don’t want to take, I want to get a system with low coupling and high cohesion." As a personal statement, I guess this is fine. If Ayende doesn’t trust himself to write code appropriate to his requirements and resources, then by all means, he’s free to handcuff himself with less powerful tools.

I appreciate your permission, but I think that you missed the point. My requirements are high cohesion and low coupling. In the end, I want code that I can read, understand and work with.

That’s not at all what he means, though. Too often this kind of statement isn’t intended to actually target the speaker. The speaker is perfectly confident in their own abilities - in this case to create low coupling and high cohesion. It’s the abilities of other developers they want to constrain. It’s another manifestation of the "programmers not doing things my way are idiots" meme used against Visual Basic for so long.

I take offence at this statement. Rhino Mocks is a project that I developed because I wanted to have a mocking framework that I could deal with. It is an OSS project because I feel that other people can also use this functionality. It has never been my intention to use Rhino Mocks to preach My Way to the masses.

Nevertheless, Rhino Mocks reflect the way that I use a mocking framework, and the best practices that I and the community that has grown around it have discovered. I am using the same Rhino Mocks build as anyone else, for the same reason that I quoted above. This is not the case where I am handing down architecture to the stupid programmers down the hall: "Thou Shall Have Loose Coupling, And That Will Be Enforced With Rhino Mocks".

Frankly, loose coupling isn’t an absolute value anyway, so arguments that every decrease in coupling is automatically worth the cost are absurd on their face

Loose coupling comes with the cost of needing to understand the interactions within the system as a whole from the individual parts. I find that the ability to look at a piece of code in isolation, and then look at its interactions much easier than trying to grok a system that has tight coupling, since I can't usually understand a piece of code is isolation. And, as always, it is entirely possible to have too much loose coupling.

To summarize this decidedly long post,

More posts in "Dependency Injection" series:

  1. (23 Aug 2007) Separating the Container
  2. (21 Aug 2007) Applicability, Benefits and Mocking
  3. (18 Aug 2007) IAmDonQuixote ?
  4. (18 Aug 2007) More than a testing seam