What’s a code kata?
A code kata is an exercise in programming which helps hone your skills through practice and repetition. Usually at code retreats, you pair with a different partner for each kata and you try to solve them by applying different pair programming techniques. My favorite kata so far is “Use no conditional blocks in your code”.
Why are conditional statements “bad”?
Conditional structures in C# include the if and switch statements. Although they are essential to any complex application, an excess in using them might make the code unreadable, hard to maintain and extend with new functionality.
Conway’s Game of Life
Let’s take the classic code retreat problem, Conway’s Game of Life. Here are the basic rules:
- Any live cell with fewer than two live neighbours dies, as if caused by under-population.
- Any live cell with two or three live neighbours lives on to the next generation.
- Any live cell with more than three live neighbours dies, as if by overcrowding.
- Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
For now, let’s assume that for each cell in the game we know the number of its neighbours and if it’s dead or not.
public class InitialCell { public int Neighbours { get; set;} public bool IsDead { get; set;} }
Implementing the rules with conditional statements, we would write something like the following. You can image that if the game were to have more rules implemented, the chain on if statements would become very long and we’d run into the above mentioned problems. Same goes for a switch implementation.
public bool CellSurvives() { if (this.Neighbours < 2) { //Underpopulation return false; } else if (this.Neighbours > 4) { //Overpopulation return false; } else if(this.Neighbours == 3 && this.IsDead) { //Survives by reproduction to next iteration return true; } else { //Survives to next iteration return true; } }
An easier way with LINQ and Func
An easier way to implement this rules would be by using C# language features like LINQ and Func. A Func is a type of delegate that encapsulates a method that has one or more parameters and returns a value of the type specified by its last parameter. Basically, a Func is an Action that can return a value.
We can rewrite the game rules like so:
Func<Cell, bool> IsUnderpopulated = cell => cell.Neighbours < 2; Func<Cell, bool> IsOverpopulated = cell => cell.Neighbours > 4; Func<Cell, bool> CannotReproduce = cell => cell.IsDead ? (cell.Neighbours == 3 ? false : true) : false
Rules.Add(IsUnderpopulated, IsOverpopulated, CannotReproduce);
A cell will survive to the next iteration if all the rules we defined will return false: the cell will survived if it’s not under/overpopulated or it the reproduction condition is met. Using LINQ, we can verify them like so:
public bool CellSurvives() { return Rules.All (rule => rule(this) == false); }
Validating the two implementations with Unit Testing
We can verify that both ways of implementing The Game Of Life are valid by writing some unit tests. Using NUnitLite, here are some that I came up with:
[Test ()] public void CellWithTwoNeighboursSurvives () { Cell cell = new Cell (); cell.Neighbours = 2; Assert.IsTrue (cell.CellSurvives()); } [Test ()] public void DeadCellWithThreeNeighboursSurvives () { Cell cell = new Cell (); cell.Neighbours = 3; cell.IsDead = true; Assert.IsTrue (cell.CellSurvives()); }
More tests and all the code is available on GitHub. Of course, this is not the only way to avoid conditional statements and other methods are available. Whichever one you chose, the ultimate goal here is to improve skill and have that mindset which allows you to see that things can always be improved.