Subverting TDD as a design tool
So TypeMock can now mock DateTime.Now. Replacing the functionality of DateTime.Now, which is an external dependency, was one of the first issues that taught me the value of TDD. With TypeMock replacing DateTime.Now, I get all the benefits of unit testing, but none of the benefits of TDD. Yes, my code is now “testable” in the sense that I can now write a unit test against my code, but I’m using Jedi mind-tricks to do so.
TDD combines example-driven, client-first development with the icing of providing a safety net of providing executable specifications to lock down existing behavior. For me, the real benefit of TDD is the former, much more than the latter. TDD tells me exactly where my design is bad, as tests that are hard to write belie a design that is hard to work with.
When I first hit the “DateTime.Now” problem, TDD led me down a path that forced me to invert dependencies. Instead of an opaque dependency on DateTime.Now, I had an explicit relationship between that class and its dependency through an IClock interface:
public PunchClock(ISystemClock clock)
From the standard external system dependencies such as clock, files, configuration and so on, I’ve used the dependency inversion principle everywhere inside my codebase. Why? TDD and DIP tell me if my class is doing too much. If my class is doing too much, it will be hard to understand, change and maintain. In my experience, TDD is by far the most efficient tool at showing me deficiencies in my design. It shows me not only problems in design of individual members and even type and member names, but problems of my overall architecture.
If I have a legacy system I need to change, there’s a whole book on techniques for doing so in a safe, responsible manner. Changing legacy code is like camping – you always leave your campsite cleaner than when you found it. But I still can’t understand why I would need a tool that subverts all of the indicators in a unit test of bad design.