Practice makes perfect
The only way to get good at something is to practice. The concept of doing a Code Kata is to practice the art of TDD and Red-Green-Refactor. By practising, it will become easier to do against real code in real scenarios. To re-iterate the Three Laws of TDD:
- You are not allowed to write any production code unless it is to make a failing unit test pass.
- You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
- You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
Which complement the steps Red, Green, Refactor:
- Red: Create a unit tests that fails (get to Red)
- Green: Write production code that makes that test pass. (get back to Green)
- Refactor: Clean up the mess you just made. (While Green, Refactor)
As a group exercise, this gives members of the team a chance to question these premises, gain an understanding from others who already Grok the concept, and by doing, they will reenforce the steps themselves, and come to their own understanding of the principles and why they should want to follow them. (It can also be a good chance to stop and reflect on code, techniques, and choices made by fellow team members in a mobbing-style scenario.)
The code is Wrong, and that is ok
After implementing the Spare Rule logic, we had the comment raised that one of the developers would have pre-emptively checked against the Strike Rule. This goes against the Red-Green-Refactor and TDD rules because you are writing more code than you need.
The interesting thing about this comment was that it raised an important aspect of performing Katas. Practising helps your brain absorb the habit, and tear down existing habits. In this case, the existing habit is writing code you know you will need later, but haven't written tests for, yet.
You need to break the habit of making sure your code is 100% bulletproof (which in reality except for the most trivial cases, it never will be, because you don't know what you don't know). Accept that it is incomplete and follow the rules.
As Uncle Bob puts it, the code isn't wrong, it passes all the tests so it does exactly what it should do (as documented), and no more, so it is technically right.
The only way to ensure it does what you expect on an edge case is to actually write the test for the edge case. This test does two things:
- Makes sure that you have documented it as a case (and automated a way to ensure it still does what is expected).
- Makes sure that the edge-case actually does what you expect it to do in the implementation (and that by implementing it, it doesn't break any existing tested cases).
We had the great idea raised that you should make a note somewhere as you think of edge cases, and use these notes as the basis for the next tests you write.
It can be hard for programmers to accept that something can be wrong and that it is ok, but without this, enlightenment may not be achieved.
“If I could define enlightenment briefly, I would say it is the quiet acceptance of what is.” Wayne Dyer
Don't refactor too heavily too early
Some refactoring may seem pertinent after every test. The temptation is to over-refactor. If you do this, you may find that the next test is harder to make pass, or that you end up reversing the refactor straight away. Try refactoring one or two test behind when you first notice the potential, in case the next test makes you change your mind. If in doubt, you will be back at the refactor step soon so just wait until the next cycle.
On the other hand, refactor too much and see what happens. That is the nice thing about Katas, you can practice techniques, see them fail, feel the pain and the only consequence is your own learning opportunity. Learn from what you experienced, and apply it next time you are following TDD on your software.
Some obvious examples are:
- If you have an if/else, maybe wait until you see an
else ifbefore refactoring to a switch, or strategy.
- If you see duplication, think about if factoring it out will help readability anyway (then go ahead) or is likely to be used again (seems reasonable).
- If removing duplication increases verbosity, and reduces readability, you may want to wait. There may be a larger chunk of duplication after a few more tests that make the refactoring more obvious and less verbose, easier to read.
But like I say, there is no right or wrong with Katas. Like physical exercise, if you feel it, it is working.
Uncle Bob says to write the simple cases first, before writing the complicated cases to help with managing the above. Also, think about writing the test that forces you to write the code that you want to write. And write specific tests to generalise the implementation.
More like guidelines
As Barbossa said it, "...the code is more what you'd call "guidelines" than actual rules."
TDD and Red-Green-Refactor and tools for the toolbelt. It is not a Silver Bullet and not a one size fits all. As you develop your software you may find that you move in and out of TDD at different stages.
You may be 'experimenting' to understand what the use-cases and requirements are. In that case, you don't know what the test cases are, so how could you write them.
Other times you may have very specific calculations, evaluations or decision trees. In these cases, writing each case as a test case and following TDD to implement them all makes great sense.
The main thing is to understand the tool, practice with it. Understand the limitations so that you can recognise the best times to use it or not use it, and use it well when you do.
For some practical resources to practice your Katas, here is a list of resources.