Yesterday, I wanted to setup a quick feedback loop for writing some production code. But, I wasn’t entirely sure what that code should look like. Further, I hadn’t worked in the code base for several months, so I wasn’t sure how the new code would need to interact with other objects.
This is a scenario that often gets me in trouble. I end up spending too much time contemplating how things might be without the feedback of what’s possible and plausible.
What I ended up doing:
- Start a new test case for the code. I hardly know what it should do, so I ended up with
it "should do things"
. - Write the kind of code I would run in a REPL to get started writing the production code. This was a service client, so I did things like setup a connection, invoke a request, and handle a response.
- Write a test assertion about what I think the side-effect or result of the production code should be. For this service client, I wanted to make sure a useful thing was returned.
- Run the test, see it fail, learn some things about the REPL-y code I wrote. Since I'm writing Ruby, my feedback rate goes way up here. Running a single test, which I can do with a keystroke in my editor, is way faster than switching over to an IRB, reloading code, and finding the right incantation to run again.
- Iterate on the code in the test case until I have something that passes. Think, type, feedback. Observe, orient, decide, act. Coding is fun.
- Once I have passing code, start rearranging so its closer to what I want as actual production code. Replace dummy values with real ones. Figure out how to remove any cheats I may have put in place for expediency.
- Once I know what the messages are, extract them into helper methods on the test case class. Now I'm starting to do actual design. After each change, I run the tests. If I break the test, I go back and fix it before I proceed. This is Legitimate Refactoring. Feels good.
- Once I know what the objects are, I go ahead and create their file in the production code, move the code out of the test and into the production code, and make sure the original test still passes. Now I switch back to a more typical test-driven design cycle; write a test case, watch it fail, make it pass, refactor, repeat.
Give this a try some time. It’s a great confidence booster.