Last Updated: February 25, 2016
· kazark

Use TDD to pace your development

I often suffer from analysis paralysis. Other times, I get into the flow and suffer from an over-eagerness that causes me to rush out half-baked stuff. Odd, isn't it, given that those are kind of opposite problems. It's sad how often problems come in pairs like that.

I have noticed that test-driven development helps to alleviate both problems. Are you suffering from analysis paralysis? Write out the skeleton of a test for some minimum base behavior that you know needs to happen in one mode or another, regardless of the details. This is particularly nice if you have a testing framework which honors the place of natural language in tests (i.e. a spec- or BDD-style test framework).

describe('An HTTP POST request to api/projects', function() {
    it('should create a new project', function() {

Now you can fill in the test with a minimal implementation (brush aside all the details that are still up in the air for the moment) and then code the minimum to turn it green. You just overcame static friction. Welcome to the smoother world of kinetic friction!

I am not trying to give you TDD dogmatism here. I consider myself a TDDer, but I don't always do strictly the simplest possible thing to make a test go green. However, if you are trying to escape analysis paralysis, being purist is not dogmatism; it's flat out practical. Often analysis paralysis is a result of trying to solve an entire problem at once. If you force yourself to sit down and write a test, starting with the English should sentence—or however you prefer to phrase your specs, but it is extremely helpful to think in English first—and you recognize that this test is only to try the first bit of behavior, and then next one the next bit, you can break yourself out of your paralysis.

It's true the other way around, too. If you are are trying to do TDD, ask yourself, how often do you break your TDD cycle by just jumping in and starting to change things? And when you do, why? I do it semi-regularly. This can be a bad thing; as Micheal Feathers says in a very good article,

Quality is a function of thought and reflection - precise thought and reflection. That’s the magic. Techniques which reinforce that discipline invariably increase quality.

When I break out of my TDD cycle, it can be a sign of several things. Maybe I don't have a good grasp on the work I'm doing, so I feel the need to fiddle with it. This may be because I don't understand the problem well or because I don't understand the solution well. Perhaps I am simply rushing and being lazy or sloppy. Occasionally I do it deliberately because I am writing code that is trivial and shouldn't be unit tested or is glue code and will need to be integration tested instead (though in that case it would be good to have the failing integration test written).

Not starting with tests doesn't have to be bad even in the case of being sloppy or lost. You can turn even these into a good thing if you are willing to kick in some self-control. You can always slop things together in a general way first, without worrying about whether they are strictly correct or complete, get a feel for how things will go in, and then (this is important) throw it all away and do it over with TDD. As long as you catch yourself when you are diving in heedlessly, you can use haphazard coding as a way to learn and to remove fear. However, you should still always come back and do it fresh (as in git checkout . or even git branch -D sandbox fresh) with precise thought and reflection, and that's where TDD is your friend.

You may have heard that TDD is more about design than about bug-free code. (If you haven't heard this, well, do a Google search and start reading up on it or something. There is much to be said for this.) It can help you think about levels of abstraction and how to factor your code. To do TDD is to work in small chunks. It is to iterate. No more of the "one big linear rush-through" that we are so prone to.

So you can use TDD to get yourself moving, or you can use it to slow yourself down to an appropriate speed. While it is good to develop quickly, it is also possible to develop too quickly. It's like long-distance running. If you start at a breakneck speed your overall race will end up slower. That's right: for anyone reading this who has never run cross country, I am here to tell you that you can significantly improve your speed in race by slowing yourself down for the first couple miles even to the point where you feel like you are going too slow. The same thing holds in software development: you must pace yourself.

I'm sure there are any number of ways to pace yourself. As for me, I find TDD a helpful way to pace. If you haven't tried TDD, or you have tried it but are still in the "TDD is primarily about proving the correctness of your code" line of thought, I suggest you try TDD as a way of pacing yourself. If you are already an ardent practitioner of TDD, let it be one more reason to keep using an already valuable technique.

1 Response
Add your response

To me I think that biggest value TDD brings is confidence in my code. It forces me to understand the problem so that I could define exactly how the code behaves. This way when QA is testing my code I have confidence that as long as they hold the same expectations as I did my code works.

I see what you saying about TDD being a doubled edge sword for you in slowing you down and also giving a defined path to follow at the same time. I see tests as check points in the code saying that yes this particular thing works so I've made progress. I never thought of TDD as being a pacesetter before though. Interesting concept.

over 1 year ago ·