I will be coaching at the Milan edition of the Global Day of Code Retreat on Saturday; the world-wide event, held in 100 cities, will be centered on 45-minute iterations of the development of a simulation of the Game of Life.
The event itself is not centered on the Game of Life, but on approaching the problem with multiple techniques (outside-in or unit-based TDD, CRC cards, no return statements). However, I delved into the whole problem and solved it as it's only honest for me to have seen all its extent before attempting to coach other people.
Note however that I have shaped my understanding of the work of a coach as someone that can help in approaching the problem and posing the right questions, not in giving answers. Even if I know a solution, I should never propose pieces of it to the developers being coached: going with Chinese proverb, a coach should teach give you a fish, but teaching you how to fish.
The Game of Life consists of a infinite grid of square cells, each in the alive or dead state. A discrete-time simulation takes place, where each generation is a function of the previous one:
- a dead cell becomes alive if exactly 3 of its neighbors are alive.
- An alive cell dies if less of 2 of its neighbors are alive (isolation) or more than 3 are (overcrowding).
Given an initial configuration, the game evolves without further intervention. The simulation is interesting because the game is not chaotic and even with these simple rules there are many stable configurations that remains fixed, rotate, cycle, or even move across the grid.
The game is a nice self-contained problem, and I spent a total of 4 hours in producing a full simulation, command-line visualization included:
X X X XX
with some interruptions for having lunch and voting.
In my particular case, I chose an mixed approach, that started from the Generation classes instead of from a Game one (outside-in) or Cell one (bottom-up). I had already some ideas on how to shape the code from my previous experience at last year's code retreat.
Test-Driven Development is of course the main technique to refine while solving katas of this kind.
Here are some random things I had to care for:
- Primitive Obsession: passing around x and y variables does not scale very well.
- Concept names: it's easy to get confused on Cell and Position, so if you use this concept give an exact definition on whether to include state to avoid misunderstanding.
- Representation: a data structure listing all cells cannot represent an infinite grid. Moreover, some data structures can be of help in reasoning on cells: sets and lists, for example.
- Functional approach: you can solve the problem with immutable data structures and the composition of operations over them (for example union and intersection of sets). However, you can develop the same approach with Value Objects in an OO language (PHP in my case) following much of the same logic.
It's not easy to print an infinite grid, and when choosing a part of it you have to make some assumptions that would need a Product Owner. :) The more esoterically storing the cells to make their infinite number fit into your finite RAM, the more difficult would be the job in translating this data structure back into a visual output.
If you're solving this problem, I suggest not to tackle the visualization unless you have a ready-made library or sufficient time to develop it after the simulation engine. It's fascinating for developers to actually see their code immediately working and experiment with seeds of active cells, but it may take an additional 50% of time with respect to the plain in-memory solution.
Moreover, TDD removes the need for many manual tests, and leaves just exploratory scripts as the point where you will need visualization.
I will try not to be primed by my own solution when people will start develop their own, different and equally valid ones. There are many different implementations of the Game of Life, and there's no right answer to a kata where there are no expresses non functional requirements (would you like easy-to-maintain code? Or high performance and scalability?)
I usually open source everything I write for exercise, but I won't publish my solution until after the GDCR. :)