Dependency Injection – Keep your privates to yourself

Author Eli Lopian    Category .NET Tests, TDD     Tags

Jacob Proffitt has hit the nail on the head with his “I do wish that people would admit that DI doesn’t have compelling applicability outside of Unit Testing” post, the discussion continues with Nate Kohari response post and Jacobs counter post. Oren has also joined in with two posts.

Here a some ideas for you to think about.

DI as a Silver Bullet – You lose power

When you use DI as a ’Silver Bullet’ you are losing more then half the abilities of your programming language. You can not use static methods or the ‘new‘ keyword or sealed types. Oh, you have to make all your methods virtual too. This is going to be even harder once Extension Methods (and Linq) become main stream.

Code to Enable Change – Costs More

Creating Code that is there only to “Enable Change” has a big “YAGNI” written all over it. (Making the code more complex and thus wasting time in development and then in maintenance, for a chance that it will be used in the future). We have understood that this is the wrong plan ages ago. We now know that we can not predict the future and it is best to change our code only when we need to (a process called refactoring).

Keep your Privates to Yourself

Jacob, you are quite right about DI coming into fashion only because the tools where not good enough. DI does have other applications outside testing, but it is being overused in most application only to make the code testable.

One of the first issues that was discussed when TDD was starting was: “should we change our code to make it testable?”
Should we change the visibility of our code?
Should we change the design of our code?
This lead to a collision between testable code and OO encapsulation. Developers started to expose private parts of the code to enable testing. It started with private fields and methods and now it is the complete design. This collision still exists when using inadequate tools, but with the right tools, you can enjoy the best of both worlds.

Get the Best Tools to get the Job Done

Thousands of developers have understood this and have started testing there code without being forced to use a specific pattern required by some tools. Many development shops, didn’t test their code because of the testability/design collision. With the right tools they now understand and test their code.

As Joel Says: “Get the best tools

Bookmark and Share

4 Comments to “Dependency Injection – Keep your privates to yourself”

  • Dependency Injection - Good for more than just unit testing. : Mostly Progamming Stuff December 9, 2007 at 5:56 am

    [...] Eli Lopian entered the discussion on the negative side of DI but made some statements that I think are a little misleading: [...]

  • 依赖注入是否值得? - 自由、创新、研究、探索…… - 博客园 December 17, 2007 at 2:25 am

    [...] Eli Lopian是设计出TypeMock的公司的CTO也加入争论,他对争论的核心有不同的看法: 当你把DI当作是“银弹”来使用,你就丧失了所用编程语言的一大半能力。你不能用静态方法,不能用“new”关键字,不能用封闭类型。哦,你还要把所有的方法都变成虚拟的。 [...]

  • Poking Bears - Jacob Proffitt January 10, 2008 at 1:51 am

    [...] Poking Bears I can’t believe the potent response I’ve gotten on my posts about Dependency Injection. Ayende Rahien responded individually to each of my posts himself, which is more than a little bit intimidating all on its own and a couple of development heavyweights left comments directly. Nate describes Ayende’s posts as the cavalry arriving and links to a couple of other responses. All of these posts disagree with me, though a post by Aaron Jensen indicates that he’s at least willing to consider the possibilities. All of this should have been foreseeable, really, as soon as I decided to publicly post my skepticism of a technique in the midst of its ascendency just as mature tools are penetrating its development space. Surely something that popular must have some foundation in reality/fact and give measurable real-world benefit, right? The Benefit of Dependency Injection Its boosters see DI as assisting in loose coupling of objects. Anyone around when OOP came in and trounced all comers knows the benefits of loose coupling, right? Darn skippy. Benefits include ease of maintenance and being able to refactor elegantly. The thing is, DI itself doesn’t really do much for loose coupling as I pointed out in my posts. DI alone has little discernable benefit. DI aids loose coupling when you create container objects or a framework to make dependency management and injection easy. It’s essentially an additional layer of abstraction that allows you to create a dependency on the object or framework in place of the actual objects themselves. This is what Ayende means when he talks about a “powerful container”. This is also the key behind Google’s Guice framework for Java and Nate’s own Ninject project as well as the Windsor project mentioned by both Nate and Ayende. See a pattern there? I did. 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. The fact that the addition of a framework or container objects unlocks the benefit makes me wonder if there isn’t a different pattern effectively at work here. Theoretical Benefits Which leaves me where I started, really. You see, context is everything and the context of the vast majority of discussions around Dependency Injection involves using mock objects in unit testing. Bright young developers looking to do unit tests without hitting the database search for tools that will help them accomplish this task. They’ve heard of mock objects and figure that mocking is the key to solving their problem. The trouble is that everywhere they look, mock objects are telling them about “design for testability” and the importance of loose coupling. It’s such a litany that many of them have come to buy into the party line because hey, “it’s just good design.” I’m sorry, but that is bunk. You cannot separate good design from the context and resources of your individual project. 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. Or take a project like Subtext. I love that project even if it’s been a couple of months since I’ve done anything substantive for it. Telling me that the architecture of Subtext should be crammed into a dependency injection mold just to increase our ability to use mock objects in our unit testing makes me shudder (not that anybody has done anything of the sort, mind. I’m talking theoretically here). In the whole, that’s a lot of overkill in order to extend your test coverage. YAGNI Baby I don’t want to come across as too much of a shill, but I have to agree with Eli Lopian (CTO of TypeMock, so hardly a disinterested party) when he says this has YAGNI written all over it. Have I been involved with projects that took a hit because a dependency had to change? Absolutely. But I’ve also been with projects that took a serious architecture hit they never came even close to needing. Outside of major corporate infrastructure projects, stringent loose coupling just isn’t as much benefit as more naturally encapsulated OO techniques. 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? That’s his implication and he’s not alone. 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? Balance that against how often you really need to change dependency configuration. Add in how hard it would be to go from not using DI to using it and what kinds of triggers you’d use to identify when a project is big enough that the risks of architectural change justify the cost of wide-spread DI. All of these proponents are trying to claim that DI has little or no cost and/or that the benefits are incalculable. I’m sorry, but I’m not taking that bait. Resisting the Hard Sell Frankly, this whole thing puts me in mind of a classic hard sell technique. A customer comes to you wanting widgets. You tell him he can’t have widgets without blodgers but that’s okay because blodgers have so many additional benefits that really they should be coming to you for blodgers anyway. Indeed, all professionals are already using lots of blodgers and they all agree that it’s a good idea to have them and really you can buy yourself some widgets as well! And you’re in luck because we have plenty of the highest quality blodgers in stock right now! So it is with DI and mock objects. I want mock objects so that I can test code without actually traversing the wire and hitting a database. Loose coupling is so far down my project priorities that standard OO practices are more than sufficient. 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? Fortunately, I grew out of that kind of bullying before I got out of high school. 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, believe me, I’ll be looking into one of those magic DI containers. There’s some seriously cool mojo there. I just don’t have that need and since I can mock objects without it, I will. On Better Testing A lot of people talk about the benefits of TDD. I tend to agree with a lot of their tenets. I’m not entirely sold on “Test First” (the heart of TDD), but I’m to the point where I’m going to give it enough of a shot to see how much difference it makes and in what direction. Since TDD is such a big deal and considered by most to be extremely important, I wonder why they let themselves be hampered by the DI crowd trying to ride their coattails. The biggest roadblock to ubiquitous testing for me came when I ran into methods that had latent processes embedded in them. This was mostly the case with database access, but also web services or anything else that crossed the network or accessed important global resources. Mock objects were the obvious solution to the problems I ran into. I balked, however, at the degree of change needed to use any of the mock object frameworks I ran across. So I lived with gimped unit tests until I ran across a stronger mocking tool. I can’t be the only one to do this. How much have we set consistent unit testing back by insisting on selling DI as a prerequisite to using our mocking tools? Development Principles Enforcing purity tells people that you’re not as interested in solving their problems as you are in enforcing your code of conduct. “You can have mock objects, but only if you join our priesthood” they seem to say. 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. 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. Personally, I’m a fan of powerful tools that let me do things my way. If there’s something I’m doing wrong, please tell me. If there’s a principle or pattern that you think might be useful to me, I want to hear it. I want to hear the best case you can make and as much of the cost/benefit as you can include. But I’ve been around long enough to know that no principle or pattern is useful in every context so I’m just not going to buy arguments that claim that anything that needs X should also be using Y unless you can show me how Y is a fundamental and indivisible part of X. And I’m sorry but DI is not a fundamental and indivisible part of mock objects. Infinite Cost Arguments I had a post a couple of months ago on my personal blog about safety and infinite cost arguments. Summary: I don’t buy arguments that boil down to one side having an infinite cost any more than I buy arguments that claim one side is free of all cost. This tenet applies to the Dependency Injection equation—loose coupling is a beautiful thing, but the absence of DI isn’t a sign of sure disaster. 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. With DI containers and tool frameworks, I’ve come to see that DI can have benefits that aren’t solely mock object/unit testing related. I just don’t think that DI is a fit for every project because the cost is not zero and the alternative cost is not infinite. Frankly, I don’t see DI as a benefit for most projects but then, nobody has bothered to make that argument. As such, I’d appreciate more exploration in the middle and discussions that admit that mock objects that don’t require dependency injection would be a huge boon for widespread penetration of comprehensive unit tests. Or discussions that explain why I’m mistaken in my statements above. A Caution Most developers I know have been on projects where some dependency got spread throughout the code in such a way that any changes in that dependency created a nightmare. I’ve certainly been there. In those situations, the problem was improper encapsulation and the tight binding that brings. Comparisons between DI and those examples are like comparing a bag lady to Ms. America. Yeah, there’s a difference and all, but the fact Ms. America had a manicure isn’t it. If you’re going to make an argument I can buy using comparisons, you’ll need to compare the best of the alternatives to the best of DI. What I’m saying is that while you should put your best argument forward I’m going to balk at straw men put in place of my position. And the fact of the matter is that you can get pretty far achieving loosely coupled architecture before you get to DI. I’m not saying DI can’t do it better, I’m just saying that there are a lot of techniques out there that even medium-sized projects already routinely implement that provide perfectly adequate change protection. DI is on top of, not instead of, those techniques. Technorati tags: Dependency Injection, TypeMock, Mocking, Unit Tests, TDD, YAGNI Posted: Aug 20 2007, 09:10 PM by Jacob | with 7 comment(s) Filed under: Dependency Injection, YAGNI, TypeMock, TDD, Unit Tests, Mocking [...]

Post comment