How to TDD the Unknown with a Spike Solution 

 January 12, 2015

by Jon Reid


So you want to try test-driven development (TDD)—great! But that requires expressing the intent of the code-to-be in automated tests. Where should you start if you don’t even know what the code should do? What should you do if you’re not confident about a particular approach?

You drive a spike through it!

Motivation: Unknowns

To start my “Marvel Browser” iOS TDD sample app, I want to begin by making a network call to the Marvel API. If I knew what I was doing, I would start the 3-step “TDD waltz” of writing a single failing test, then writing the simplest code that passes, then refactoring.

But two roadblocks keep me from writing my first test:

  1. It’s been a while since I wrote an NSURLSession call. What does it need? How does it call me back? I want to write tests that simulate the various ways the framework can call my code, including error conditions. But I don’t quite remember the flow of control.
  2. To call the Marvel API, I need to satisfy their authentication requirements. There’s some process of signing requests with an MD5 hash. I’m afraid if I try TDDing my way there, I’ll end up with something that “looks right to me” but doesn’t actually work end-to-end.

When you’re dealing with an unfamiliar framework call, or an unfamiliar sequence of calls that need to work end-to-end, TDD is not the place to start. Instead, you need a “spike solution.”

What’s a Spike Solution?

A spike solution is a code experiment. It’s called a “spike” because instead of carefully building things up layer by layer, we just brute-force something, driving through multiple layers.

A spike solution is dirty & quick. Don’t spend time making it right. Instead, code just enough to get the answer you need.

A spike solution is dirty and quick. Code just enough to get the answer you need.

Click to Tweet

Sometimes you can create a spike in a brand-new, throwaway project. But often, I find it easier to use my project’s existing infrastructure to set up the scenario I need. In that case, put the spike in a branch.

Throw It Away when You’re Done With It

You can tinker with your spike, hacking any way you please. You can study what you come up with. But you must resist the temptation to start copying the hack over to your production code. Resist!

In fact, once you’re done with a spike solution, throw it away. There are good reasons to do this:

  1. It frees you from any constraints to write clear code while you’re experimenting. Quick-and-dirty is the name of the game. Just hack.
  2. It avoids creating production code not covered by unit tests. Once we have the answers we need from our spike, we can start the TDD cycle back in the real code, using what we learned.
  3. It keeps you from writing tests that merely mimic the spiked code. As you build up tests and refactor, the production code may assume a radically different shape from the spike solution.

Disclosure: The book links below are affiliate links. If you buy anything, I earn a commission, at no extra cost to you.

Here’s how The Art of Agile Development by James Share and Shane Warden answers the question, “Should we really throw away the code from our spikes?”

Unless you think someone will refer to it later, toss it. Remember, the purpose of a spike solution is to give you the information and experience to know how to solve a problem, not to produce the code that solves it.

Let’s Spike a Call to the Marvel Comics API

As I explained in TDD Sample App: 20 Topics that May Spill Out, the main thing I want the Marvel Browser to do is to send a name prefix and get back comic book characters. Again, there are two things I’m uncertain about: how the NSURLSession works, and how Marvel does request authentication. So let’s spike it in part two: Spike Solutions: 7 Techniques You Can Use.

When have you used spike solutions? Did you throw them away? You can leave a comment by clicking here.

Jon Reid

About the author

Programming was fun when I was a kid. But working in Silicon Valley, I saw poor code lead to fear, with real human costs. Looking for ways to make my life better, I learned about Extreme Programming, including unit testing, test-driven development (TDD), and refactoring. Programming became fun again! I've now been doing TDD in Apple environments for 20 years. I'm committed to software crafting as a discipline, hoping we can all reach greater effectiveness and joy. Now a coach with Industrial Logic!

  • Your post could not be more timely, I just finished a project on a tight schedule that involved a challenging view hierarchy. So I used a spike to figure it out and then TDDed from scratch!

  • Hi, Jon!

    What do you think of other TDD approaches, like the one presented by Freeman and Pryce in their book Growing Object-Oriented Software, Guided by Tests, in which they start by creating an end-to-end test of the first feature that they need to program and TDD the system from there?

    My opinion is that it is more appropriate for big, complex transactional systems, but some iOS apps may be big and complex enough that they could benefit from writing end-to-end tests first. What do you think?

    • I’m embarrassed to say I haven’t read the GooS book yet, though the authors are the creators of the original Hamcrest. Then again, I don’t own a single book by Kent Beck! I have quite a backlog of books-not-read. :-P

      And I’ve never written a full end-to-end test, round-tripping through the UI — not yet. I have written acceptance tests for calling APIs, though. These have been for APIs which the company owns, and their value was primarily in detecting if the server side changed without the server developers informing us.

      So I don’t think we need UI to write acceptance tests. You’ve inspired me to take what I learned in my spike solution and apply it to creating a failing acceptance test, before TDDing the call to the Marvel API.

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}