Wednesday, April 23, 2014

Spike and Extract

Sometimes I have an idea about how I want my code to turn out. In that case, I can use TDD in the conventional way: write a test, fill in the implementation to make it pass, refactor.

But a common situation is that I have only a vague understanding of where we're headed. I don't know how my dependencies work. I don't know how it should all fit together. So:
  1. Write a spike in the form of a "unit" test.
It's not really a unit test, because it's not testing a unit. But I'll still use a unit testing framework to write it. And I'll use FluentAssertions and ApprovalTests if they're useful

Like any good spike, it should hit the tricky parts, like an API that is poorly documented.

It may take a while to write. I'll try lots of different things until I get it to work.
  1. Extract 'till you drop
Use Extract Method, Extract Class, Move Method repeatedly.

Look at any primitives as potential new classes (Whole Value).

Keep refactoring until things read really cleanly. Avoid generality that you don't already need, though.
  1. Keep testing.
Write tiny tests for each new method.

If a method is hard to test, refactor.

If a method is hit by more than 4 tests, refactor.
  1. RGR
You now have code that works, passes tests, and has an appropriate structure.

Add new functionality with the standard Red-Green-Refactor cycle.

This is not new.

I'm basically describing "TDD as if you meant it" by Keith Braithwaite, but trying to be gentler.

Tuesday, April 8, 2014

Five ways to know when you're done refactoring & testing

  1. Test until bored. Ask "is there any chance this is wrong?" If so, write a test for it. If not, you're done.
  2. If the test and the system-under-test would look the same, skip the test, because of DRY.
  3. If the code reads like a spec, test by inspection: read it and confirm that it says the right stuff.
  4. If a function has a side-effect-free query, followed by an action based on the results of the query, split them and test separately.
  5. I'm not very good at figuring out how to design code well, but I can tell when code is hard to test. making code easy to test usually works out well for me. If I have to mock A to test B, that's harder than factoring out B and testing it directly. So, I refactor.

These are all different ways of saying pretty much the same thing.