I have been following Jacob's series of posts from the
beginning, and I agree with most of what he has said. I
myself am fairly new to unit testing and I have been
using DI just to enable mock objects to test. Being a
newcomer, I of course start to wonder if it is worth
making design decisions that I otherwise would not have
made just to enable testing. If there will never be
another implementation of a given object, is it worth
creating an interface, injecting the dependency and
adding additional complexity and technical debt for the
sake of unit tests? This makes TypeMock.Net very
attractive.
That being said, I first implemented DI in a project
before I ever started unit testing. The requirements
called for a framework whose underlying data sources
will be changed in future releases and will come in
heterogeneous formats. I chose to use DI so that other
developers who use the framework would be shielded from
the future changes that we had requirements for. Almost
one year later, I am very happy with that decision. DI
was a great tool to use, and the key point is that it
was driven from actual requirements, not "Just in case."
"For example, is Dependency Injection really necessary
when you can write tests against your code without it?
Does good design necessarily involve DI? More
specifically, do you need DI all over the place, or just
in specific places where you know dependencies could be
a problem? (I'd recommend viewing this video BTW)"
This is a key point, there is no doubt IoC and the
related loose coupling can be useful. As with everything
else though if you overuse it you get klunky designs.
Ultimately in many cases you don't need to be able to
replace every part of your system and sometimes using
the concrete class directly is just fine.
As an example I'm happy to remove the dependency on the
e-mail gateway (and use Ioc/Service Locator and an
interface) but I won't change all my references to rules
in the domain so that they are injected. The first gives
me meaningful decoupling and fast tests and I believe it
does improve the design, the second one leaves me cold
unless it is driven by a requirement.
It’s funny but I learned about the Dependency-Inversion
Principle from Uncle Bob’s book before knowing anything
about testing. Later on I managed connect the dots DI +
Interfaces + Mocks + easy to test with the principle of
DIP and went happy to bed thinking that’s a wrap.
I know nothing about TypeMock but the little I’ve played
with DI has given me the feeling that I’m following a
good OO practice beyond unit testing.
I've responded to the point of this posting on
mockobjects.com but, in the meantime, I could do without
this sort of comment.
What do you do if you've spent all this time convincing
the powers that be that DI is absolutely essential and
now . . . it isn't? That's going to hurt. Much better to
just dismiss TypeMock as "too powerful" and move on.
I think DI is relevent outside of unit testing. I
refactored a class today using DI for reasons that had
nothing to do with testing.
I had a friend start to work on the code with me who
wanted to change how a class was loading some data into
a child object. The child object had been being getting
loaded in a constructor. We refactored so that it would
be passed in as an interface instead, as that was the
cleanest way to let us each prime the child object the
way we wanted to without needlessly impacting other
code.
Sure it will make things more testable, but I see that
as a positive side effect.
"It’s funny but I learned about the Dependency-Inversion
Principle from Uncle Bob’s book before knowing anything
about testing. Later on I managed connect the dots DI +
Interfaces + Mocks + easy to test with the principle of
DIP and went happy to bed thinking that’s a wrap."
Same, but like anything else it can be taken too far. To
me some coupling isn't a problem, as long as the
coupling isn't too strong and isn't on things that you
are worred about.
I keep using this sort of example, but if my domain
class is calling out to a DAO/repository then extract an
interface and use DI/Service Locator. I wouldn't do the
same if my domain class wanted to use a domain rule.