blog.mikro2nd.net

Why is TDD Hard to Learn?

There's an interesting thread over in fedi on "Why is TDD hard to learn?" and, as ever in the internet, I Have A Take On That!

There are a lot of responses along the lines of "It's difficult changing ingrained habits," and that's certainly true. But if an Old Fart like me can do it, then I don't see that as a fundamental obstacle.

There are responses along the lines of "Well it requires you to know what you're trying to do up front," and that's certainly true. And now we're getting a little closer to what makes a test-driven approach to programming "hard".

One of the things I find difficult (with or without a test-first mindset) is figuring out the smallest thing I can do as my next step: What's the smallest set of changes I can make to the code to go from "working" to "working" while adding value — GeePawHill's MMMSS. And value is not necessarily visible to the customer; many times it's preparing the ground for something larger that awaits me. Quite often it's cleaning up the shite I wrote sometime in the past — this morning, say. But figuring out the clean and crisp edges of that move is difficult.

We're taking our code from "working" to "broken" before we get it back to "working", and my view is that the purpose of Test Driven Development is to prepare the path so that we can do that safely, remaining in control of our codebase at all times. And we do that preparation while the code is still working so that when we come to do the breakage, we're kept safe by having our seatbelts locked in place. If the breakage slips out of our grasp and begins to run wild... time to deploy the airbag, baby: git reset --hard is the usual way to get us back to the place we were when everything was (working + prepared-for-the-next-move). Sometimes that process makes us realise that our preparations were not adequate to the move we're trying to make, and we need to change our (failing) tests, write some more (failing) tests or go back a step to refactor things into a better state in order to make the change easier. Often it means that the step we're trying to take is too large and we need to figure out how to slice it smaller. C'est la vie.

I also saw quite a lot of responses along the lines of "I don't know where I'm going, I just need to explore a bit to find out," and that's certainly a legitimate desire! I probably write more exploratory code than any other kind. It's a sort of mutually recursive pair of steps in the process of discovery, isn't it? We have some hazy notion of what the finished software ought possibly/probably to do, so we take a step, explore some corner of the solution space to move our software toward that light. In doing so we uncover some things the software might/should do, illuminating the problem space a little better, inviting further explorations, and round and round we go.

I happen to think that one of the best places to write that code is in our test suite. Do your exploratory work — and it's important stuff, that — in your tests. Move it into the main body of code later if that's appropriate, though frequently you'll want to treat it as spike code and toss it in favour of a better-thought-out artefact.


None of what I've written so far answers the question, though: Why is TDD hard to learn?

I suspect it's because TDD is usually misrepresented.

Programmers get told (or they just creatively misunderstand) that TDD is about writing better code (and "better" is usually a proxy for "bug free" or "correct" code).

While test-first programming certainly does tend to keep us from writing bugs (at least in the small) its most important primary purpose is as a design tool. It requires us to think more about the shape of behaviour we want to write, and then think some more about how to achieve that.

After a decade or more of creatively misinterpreting "No BDUF[1]" as "no design at all", and creatively coding ourselves into the unholy mess of accidental complexity that is the "cloud", we now have two generations of programmers who were raised to believe that "all design is evil". And here we are, telling them they ought to do some design up-front.

No wonder they find it hard to learn — they've never been taught how to do design at all.


Post Script: As ever, Kent Beck seems to have got to this place long before I did.

[1] Big Design Up Front