[Note: Originally drafted early last year]
One of the most enduring distinctions between how I work now, and how I did before adopting XP practices is how I view What 'Done' Means
Its particularly true when trying to practice Test Driven Development effectively. I think one of the harder things for some people to grok -- even professed TDD-proficient programmers -- is: it costs more time to stop and think for an hour about the right way to build something, than to simply code what you do know as simply as possible, then use the remaining part of the hour refactoring and adding to your initial idea until you achieve a solution that meets your needs. Its not necessary to see all the way through to the end before you start, and its not necessary that you capture the entire idea -- or even the right one -- in that first test.
Another way to say that: We get more feedback about a problem if we actualy try 10 different 'wrong' ideas in an hour, exploring the design space of the task via test/code/refactor, than if we spend that time simply thinking or discussing the right way to do it before writing anything. So, the sooner we get a test -- any test -- written and passing, the sooner we can zero in on what we really want.
Each test/code/refactor cycle (10 per hour is not even particularly extreme) gives us more information to work with. Each subsequent design session (the refactor step) has more code (and thus more examples of what the design needs to accomodate). Thus we start with an approximation of 'right' (based on what we know) and refine it to its desired quality (based on what we learn). Its not necessary to (although its ok to believe we do) know where the code will end up (and you're likely to be wrong regardless) all you really need is the ability to code what you do know, and the discipline to keep changing your design (i.e. your decision as to what's right) as you learn more.
So, if you find yourself at the beginning (or the middle) of a task to change your code, trying to guess what the design is going to look like at the end, and struggling with how to capture it in a test, try this: Review the existing code, remove obvious duplication (e.g. remove redunant conditionals ,loops, and code blocks with method/class extractions) , and clarify its intent (e.g. renaming, extracting obscure clauses to names, introducing interfaces, extracting classes, in fact, probably 3/4 of the Refactoring catalog applies here. Do this until you feel the refactoring steps becoming too big -- or too uncertain -- and then write another test and some code to make it pass. Thus providing you with more material clarification-adding and duplication-removing refactorings, until the task is complete.
Like most skills this takes practice before you'll feel (and actually be) more productive this way, but I find that developing this skill to be among the best investments of my career as a programmer.
I hope this helps you do the same.