Hey! You got your chocolate in my peanut butter! What kind of coupling was created when you got your chocolate in my peanut butter? Is the chocolate service-located or injected? Can you get your chocolate back without depriving me of any of my peanut butter? Would it have been easier if the peanut butter was in the chocolate rather than the chocolate in the peanut butter?
Disclaimer: I’m not a pattern hatchery and I don’t presume to have final say on these things, but I thought I’d throw out some stuff that doesn’t seem to be named – not for the purpose of staking a claim – but to try make communicating agile design a bit more effective.
Here are the dependency patterns that I often work with. There are likely more of them out in the wild and there are likely better names, but like I said, getting the names and attributions right at this point isn’t the point…
A dependency is created when one object has a reference to another object. For example: a business service object that has a reference to a data access object.
Two Kinds of Dependencies: Good, Evil, and Other
There are two kinds of dependency patterns: Opaque and Transparent. There are subtypes of these as well (and there are possibly more sibling types).
Opaque dependencies are the bad kind of dependencies… some would even say that they’re evil. Well, they’re not necessarily evil, and they’re not even necessarily bad. There’re just mostly bad… in some circumstances. In short… don’t use them… ever… unless you should
Opaque dependencies are the kind that you can’t assign using a class’s public API. The example of the business service using a data access (above) is an opaque dependency; you can’t assign the data access object from the outside of the business service class.
Here’s the same opaque dependency as the example above, except with the default constructor initializing the dependency:
This kind of design makes it hard to test any behavior on that service class that might need to use the data access layer. Testing behavior on objects should be doable without having to access an actual database even though the service code might make calls on the data access object.
In order to make a class more testable, a class’s dependencies should come in from the outside (this, by the way, is what Dependency Inversion and Inversion of Control is about).
Transparent dependencies (or inverted dependencies) are assigned from the outside. The BusinessService’s opaque dependency on the DataAccess class can be turned into a transparent dependency by making the data access a constructor argument:
This makes the business service class’s logic testable without having to deal with a live database. A fake data access object can be provided to the business service that allows you to get around actually talking to a database. You need to make some of the data access class’s methods virtual or part of an abstract interface, but that’s a story for later.
Transparent dependencies are preferred because they drive us (via TDD) toward greater and more explicit Separation of Concerns, which is NASA-speak for “make testing easier now,” among other things (NOTE: NASA-speak is the linguistic effluence of that aspect of programmer vanity that drives programmers to make programming sound like rocket science when in fact it’s just… programming. This phenomenon is closely related to Doctor Speak which is the predisposition to invert English grammar in code so that it reads like Latin as an effort by programmers to sooth their minds over not having had the cajones to get a medical degree).
Here’s a version of the BusinessService class that has been changed slightly to take advantage of the transparent dependency in testing:
You might have missed the small change in the above code: the DataAccess class now implments an IDataAccess interface. A fake version of the DataAccess class can be created, which gets the real data access class out of the way when testing the BusinessService’s business logic.
This is a test of the business service’s ApplyDiscount operation. It has logic that branches on the result of a query to the database via the data access class. We want to test both branches without having to setup the database with separate test data that would allow us to cover both branches. Here’s the implementation of that method:
Since the instance of IDataAccess in the test is a FakeDataAccess, the return value of GetTotalOfOrders() can be controlled without having to do any database setup.
Transparent Dependencies are a Pain in the Metacarpal
Transparent dependencies solve one problem, and create another. It was much easier to instantiate an instance of BusinessService when it had opaque dependencies because BusinessService had the smarts to instantiate the DataAccess class.
With an opaque dependency, the instantiation of BusinessService was simply:
With transparent dependencies, the instantiation is a bit more onerous:
NOTE: The dependency on ConfigurationManager is opaque!
Folks typically don’t like transparent dependencies because of the extra coding that it causes. This should make you wonder… are all these people who advocate TDD and IoC simply off their collective rocker for doing all this extra work? Of course not! We use dependency injection frameworks to do this stuff automatically.
Here’s how the above three lines of code would look when enabled by a dependency injection tool:
A dependency injection framework like Windsor, StructureMap, or Spring will handle the dependency wire-up automatically. A lot of people are already writing a lot of useful material about Dependency Injection and Inversion of Control. A blog search on any of these frameworks should reveal a lot of guidance. I’m not going to go into details.
Transitive dependencies are slightly less evil than opaque dependencies, but there are times when you might want to use them.
A dependency is transitive when it is assigned opaquely by a transparent factory. This is NASA Doctor speak for a constructor with a service locator:
In the above example, Container can create (a la Factory pattern) an instance of the DataAccess class, or it can provide one that it is already holding on to (how long it holds on depends of the configured lifestyle, eg: per web request, per thread, etc).
You could re-write the above test using a transitive dependency and achieve some of the same results:
This is really a pattern that you might avoid though, especially for testing. There’s no need to jump through the extra hoops when a constructor and a sprinkling of dependency injection will get you just as far, and with cleaner, more self-evident code.
Self-evident or self-documenting API’s are a side effect of transparent dependencies. A class’s dependencies are obvious to a reader when he can discover them from the class’s API.
For example, which of the following two lines of test code better document BusinessService’s dependency:
Also, consider the dependency discoverability that you get through IntelliSense. The first example will present you with a default constructor with no arguments, and the second will present you with a constructor that takes an IDataAccess. The second example leads to greater explicitness and self-documentation, which makes the code more learnable.
All this dependency injection stuff is about making something easier. Once you start recognizing the dependencies in your code, you start seeing all the little gotchas the make unit testing efforts more difficult. If you get rid of the unnecessary opaque dependencies, and the automate the dependency wire-up with a tool, then you’ve effectively crossed one of the tougher agile development chasms… which will ultimately lead you to yet another chasm
I find it helpful to contemplate and then devour as many Reese’ Peanut Butter Cups as possible as a warm up to dependency inversion programming exercises. Maybe you could benefit from this practice, too!