The Hidden TDD Skill

The Hidden TDD Skill

"My setup code is five times longer than my production code."

"Every change I make requires rewriting a massive test."

"All of my code interacts with the database, so what's the point?"

"My UI library keeps me from being able to do it."

"I would need to mock my whole framework."

"I cannot write a test here when all the code around it is so poorly designed and untested."

In the last post, I proposed that many if not most attempts to adopt TDD fail. The problems that get in the way of learning and practicing TDD all have a common thread. It is not duplication, though that is a problem that also needs addressed aggressively. It is not the patterns used or unused, though the right pattern can sometimes solve the problem. It is not because there are no tests now, though writing those tests would have made the pain of the problem felt sooner. It is probably not because the last programmer was terrible, though no one loves cleaning up messes they did not make. It is very simply this.

We have been attacked by an ant swarm of angry dependencies, and we can not seem to swat them all away without getting eaten alive.

Testing units means isolating units to an extreme degree. When doing so is difficult, it tells us something that is already true, even if we didn't know it or maybe are not wanting to know it. If writing a test for my code is hard, then my code is hard to use. If my test is fragile, then the client using my code is fragile. If I cannot change my code of the impact on the test, then I cannot change my code of the impact on the client code. In short, if my tests are difficult to maintain or grow, then so is my system. That is because, blatantly or subtly, the pieces of my system are intertwined and that constrains all my efforts to grow, repair, reuse, or otherwise change the system.

I have never seen any other programming technique or habit that forces you to detangle your code to the degree that TDD does. That is one of the big reasons why tested code is often better designed code and why it has been equated with the necessity of a surgeon washing hands before a procedure.

We have known for decades that managing dependencies is an essential part of software. Yourdon, Page-Jones, Constantine, DeMarco, they were discussing “coupling” (the early term for dependency) more than 40 years ago. It was a fundamental challenge of software structure then and it still is. TDD brings the pain of that problem right up in the programmers’ face and then shoves their faces in it. If that does not sound fun, well, many programmers agree. Learning how to fix it is one of the biggest parts of maturing as a programmer.

I have not seen it addressed in a really systematic fashion, though I know of a few good sources. Michael Feathers addresses it to great effect in "Working Effectively with Legacy Code" though the focus is on the finding the safest, short-term fixes rather than the best ones. Robert Martin's presentation of SOLID offers some powerful help. The Pragmatic Programmers address it with valuable guidelines like the Law of Demeter. There is a good but outdated catalog way back in "The Practical Guide to Structured Systems Design." Other random truisms speak to it like "Prefer Composition over Inheritance" and "Tell, don't ask."

Breaking dependencies is central to successful Test Driven Development. A roughly systematic sketch of types of dependencies to learn to break might look like:

  • Geographic Dependency
  • Binary Dependency
  • Structural Dependency
  • Data Dependency
  • Temporal Dependency
  • Share Knowledge Dependency
  • Construction Dependency

When test driving code, we can break them a little at a time as they develop. We do so with the support of the tests we just wrote. However, if we do not know what we are looking for and how to address it, we end up with huge setups, convoluted tests, complex mocks, and tests that break unnecessarily. Worse yet, we end up with none at all.

In my experience, teaching TDD to a team without teaching them how to break dependencies is an exercise in futility, and teaching dependency design requires a lot more than a two day seminar. Some rare people get it over time by commitment, determination, and painful experience. Better and faster is working with people who have been there before.

To view or add a comment, sign in

More articles by Joseph Gee

  • Growing in TDD as a Programmer

    I first learned TDD when I learned Extreme Programming, back in 2000. At the time, it was so controversial that having…

    1 Comment
  • Why Adopting TDD Fails

    It is a common story, maybe you’ve seen it. Maybe you’ve lived it.

    4 Comments

Others also viewed

Explore content categories