DEV Community

Cover image for Beyond TDD: breaking the rules
Daniel Irvine 🏳️‍🌈
Daniel Irvine 🏳️‍🌈

Posted on

Beyond TDD: breaking the rules

Cover image by Mark Duffel on Unsplash.

Rules are made to be broken, right? TDD is a strict set of rules that define a process for building software. But experienced practitioners have moved beyond the rules and work towards something else entirely.

Ron Jeffries wrote a tweet thread in which he discussed the notion of what he calls pure TDD (PTDD), and is sometimes called strict TDD. He talked about how he doesn’t like to subscribe to this purest approach.

But rule-breaking is an acceptable part of any skillful process.

The Dreyfus model of skill acquisition talks about skilled experts being intuitively aware of rules and can make decisions without conscious thought. That means they know not only how to apply rules but also when to ignore rules.

Then there’s the four stages of competence model which goes from unconscious incompetence—you don’t know what you don’t know—through conscious incompetence and conscious competence and finally to unconscious competence which, again, is saying that experts are intuitively aware of what they’re doing without having to think about it.

What does it mean to be intuitive?

In some sense, the word intuitive means you no longer need rules. Instead you understand the core values behind the rules, and work towards those values, not the rules.

Because you know the values behind the rules, you can understand the trade-offs involved. You can begin to see when the rules might not apply. You can begin to answer the question “when should I use TDD, and when should I not?”

Contrast this with TDD aficionados. Many of them will want to use TDD all the time, because TDD is just so amazingly great when you get the hang of it. (I’m not being sarcastic here; it really is great.) We have a phrase for this attitude: “If all you have is a hammer, everything looks like a nail.”

When is it okay to NOT use TDD? When can I cheat?

Assuming then that you agree with me that it’s okay to move beyond the rules, then on what occasions should we do so?

Here are some I can think of.

  • When you work with a team who aren’t versed in / don’t follow TDD. Now your choice is to accept that fact and try to win them over, which probably won’t happen very quickly.
  • When the risk is low. This is an interesting one, because the more experienced you get, all those functions and objects start to look the same. That means development becomes less risky because it’s familiar. Then again, your risk of mistake goes up if you’re tired, or working alone. There are many considerations. Knowing how to weigh them up can take considerable experience.
  • When the cost/benefit ratio is not in your favor. An example is React components which are often complicated to test. But you can make a design decision to move all business logic out of components and into Redux reducers, and by doing that the need to test the components at all becomes much less, since their size relative to the codebase has reduced. You can test the Redux functions instead. They’re just plain functions, so they should be easier.
  • When you’re experimenting. Many applications don’t need quality right away, but do need a period of discovery where features can be fluid. In this scenario TDD can slow you done, not speed you up.

But the rules are still VERY important.

A common belief in education is that experts make bad teachers. This follows naturally from the Dreyfus model if you think that being intuitive means losing sight of the rules.

This doesn’t mean that all experts are bad teachers. Actually they can make great teachers. They just have to put in extra effort to be great, otherwise they might very well suck.

If you’re involved with working with novices, which is typical for the industry today with mixed skill-level teams, then you must be able to switch back into “pure TDD” mode.

When MUST I use TDD?

So we can now start to see occasions when TDD is ultra-important and should not be skipped. Here are the two that come to my mind:

  • When you’re teaching TDD novices. In order to help them learn, you have to show them the rules. Not your cheats!
  • When you’re pairing with someone you’ve never worked with. Even if they’re an expert, they will have a different set of cheats and trade-offs from you. So you should fall back to strict TDD. Whenever a situation occurs where either of you are considering cheating, stop and discuss it. If you can’t reach agreement, then use TDD.

Oldest comments (1)

Collapse
 
_hs_ profile image
HS • Edited

There's a kind of business which will tell you we want best practices and all that, but they want to move too fast. They need prototyping which is basically write a lot, throw it away when you learned the structure and make it way better. Nowadays it's more or less any business you enter that didn't exists before. TDD is good idea implemented poorly because in it's roots it was too good to be true. Technical debt is made up thing which shouldn't spook you. You just need to THINK instead of follow the rules then you'll know TDD or not to TDD. TDD is about architecture as far as I understood it and I brought me only pain but it could be different depending on your product. Testing should be automated, which is NOT TDD but just automation of testing, to some point but if you're building software to be used by humans manual testing or exploratory testing however it is called is a must. If your building "middleware" to be used by machines to exchange data than I guess you could go with automation therefor TDD could make your architecture worth.