You want to test-drive some code, but you’re stuck. Maybe you’re not totally sure what your object’s interface should look like. Maybe you’re distracted by another sunny summer day. You might not be sure you can test what you’re thinking of building. Or you could be procrastinating, because you just don’t feel like writing tests right now. How do you get the benefits of TDD when you don’t feel like TDDing?
Prototyping, or building one to throw away
“Where a new system concept or new technology is used, one has to build a system to throw away, for even the best planning is not so omniscient as to get it right the first time. Hence plan to throw one away; you will, anyhow.” — Fred Brooks
Sometimes, when I start a new feature, I’ll feel paralyzed when I think about writing my first tests. There are so many decisions to make about how the API should look, which patterns and practices will be most appropriate, and how it should all fit together.
I have a few ways I get started when I’m stuck like that. Building a prototype is another.
When you write a prototype, you should think of it like a sketch. Brainstorm and try things out. Don’t bother with tests or TDD yet. Instead, explore the decisions you’re having a hard time making, with code. Try out a few patterns, and see which of them fit the feature you’re trying to design. Figure out where the shaky parts of your app are, what needs more thought, and what you were worrying about for no real reason.
Then, throw it away and rebuild it. This time, using TDD and your newfound knowledge about how you can best build the feature.
You know when you accidentally run
git checkout -f after you wrote something, and you get that feeling like you just got kicked in the stomach? But then you figure, this has to be built, so I guess I’ll do it again, and it turns out much better than it did the first time? This is also true with rebuilding prototypes. Now that you have some solid ideas of how the feature could look, TDDing that feature will go a lot more easily.
Have you ever run into a situation where you know how to build something, but you don’t know how to write the tests for it first? Or maybe it’s a one-line change to a method, but it might need some tweaking, so you don’t want to lock it down with a test before you know what the change will actually look like?
There’s a simple process that helps a lot with these situations:
- Write the code, without tests.
- Write a test for the code. Make sure it passes.
- Comment out the code you wrote, or revert the file you made the code change in.
- Run the test again. Make sure it fails.
- Write the code again. Run your tests. Make sure they pass.
- Refactor the code, taking advantage of your new tests.
I think of this as Reverse TDD or Green-Red-Green-Refactor. You won’t get the “test-driven design” part of TDD, but you’ll still get to see your tests fail when your code is broken. That’s important, because you can’t trust tests that don’t fail at least once.
Reverse TDD usually works best with tiny changes that don’t need much design. Think bugfixes, or changes that are localized to a single line, method, or class. But I use this technique a lot, especially for small changes that I’m still playing with.
The Pairing Game
The Pairing Game is a great way to break out of your Red-Green-Refactor routine when you have another developer around. It works like this:
- Find a partner.
- You write a test that will break.
- Your partner tries to fix that test with the simplest code possible.
- You write another test that will fail on that code.
- Your partner writes code that will pass that test.
- At some point when the tests are green, you can choose to refactor some code instead of writing a test.
- After refactoring, swap tester and coder positions.
I’ll let you in on a secret: playing the Pairing Game on a bowling score calculator is how I originally learned TDD. It’ll help you practice writing simple code based on failing tests, and writing those tests to begin with. Both developers will learn a lot about each other’s coding style and favorite techniques. And you’ll hit flow almost immediately, which means you’ll feel great when you finish.
You might not produce code as quickly, but it’s a lot of fun, and a great learning experience.
Stay playful and experiment
TDD shouldn’t be dogma. There are ways you can play with the core TDD concepts that can lead you to some really interesting places. And you might end up with even better code.
So experiment. Try new approaches to writing code and TDD. See how they make you feel, and what kind of code you end up with. And keep rediscovering the fun and the flow in the work you do each day.
Don't miss out on my next essay
Sign up below to get my free weekly Ruby column. I'll send you original articles and advice every Friday to help make you a smarter, better Ruby developer.