Mike's corner of the web.

Clean code

One of my favourite definitions of clean code comes from Michael Feathers:

Clean code always looks like it was written by someone who cares.

There are a bunch of rules that I try to follow when I write software. In no particular order:

Katas

A kata is a coding exercise where the goal is to learn about and practise programming, rather than to complete the task itself. As an example of what I consider to be clean code, I've put up my implementation of a ten pin bowling scorer on GitHub. I'm certainly not claiming it's perfect, but if you go through each commit in turn, hopefully you can spot lots of examples of particular techniques.

The first few commits, up to 1c788ea5f2, incrementally implement the algorithm. The code mostly works (aside from an unhandled case that I implement later). I'd like to think it's reasonably readable in this state. The Game class makes fetching the number of pins knocked down by each throw easier by defaulting the number of pins knocked down to zero. This means that the user of the Game can request any throw index, and not have to worry about walking off the end of the list.

Over the next few commits, I try to make the code as understandable as possible. The result in commit e43fc01 is longer overall, but the process has been split into several smaller functions. Whereas before you had to read and understand most of the code at once, now you can hopefully read and understand each function individually without having to know the details of the lower functions. To me, the code feels less clever and more obvious, which is definitely worth aspiring to.

Each function concentrates on doing just one thing. For instance, the _frames function focuses on iterating through each frame. It doesn't directly contain the logic for classifying frames (strike, spare, or neither), nor the code for scoring them. It has the bare minimum of code required to iterate through every frame.

Some functions might seem unnecessary. For instance, _is_strike is a one-liner that's used in one place. Although we could inline the function, I feel extracting it makes the intent of the calling function much clearer.