The problem was "The Game of Life". I'm pretty familiar with this problem having come across "Conway's Game of Life" early on in a magazine like Compute! or Byte.
However, if you walked away with a really awesome solution to "The Game of Life" you probably missed the point - most of the things that were being taught were hidden.
The solution was really beside the point. One of the main reasons is to repeat solving the problem from scratch based on an idea called kata (movements practiced by yourself or in pairs). This is something that I had come across in "The Pragmatic Programmer" which at the time reminded me of the time I had spent with projects at home - reimplementing the same thing over and over again.
Steve Yegge mentions the same thing in his article "Practicing Programming". He mentions that even as you program in your day job you may not actually be practicing programming. Repetition in solving the same problems seems to be about keeping the problem fixed and then changing how you approach it and freeing you from any time constraints. Most programming jobs involve solving the solution once (or if you're lucky doing a proof of concept and then implementing it again).
The first time around it was awful. I didn't know what I was doing, my environment was a little bit shaky, we couldn't agree on a language and I spent a lot of the time just setting it up.
It made me become aware that for the first time, practically ever, my personal computer had diverged from my work computer. Not in the "normal" Windows at work, Linux and OS X at home - but what I do at home and at work have diverged to the point where I'm learning stuff in many directions and there's almost no overlap between the two.
The second time was much better. There was less discussion on languages to use, how to approach the problem, how do you test drive it, whose computer to use and so on. There was still discussion but we both shared a bit more context this time which made the discussion flow. A big difference to the first time.
The third time around changed the format a little to where you couldn't talk to the person but you could only express requirements through tests. So this sorted out the people who were testing from those who weren't. But it also seemed to reduce the clutter around what needed to be done. Tests are much less ambiguous compared to talking through requirements and so once you setup a rhythm of tests it became much easier. Also, the whole room was very quiet. You could imagine that a team doing silent TDD and pair programming wouldn't be the noisiest group in the room (for once).
Each round thereafter changed the programming requirements: no loops, methods no more than 3 lines, and no if statements.
What did I learn? Heaps.
I ended up doing Ruby quite a bit and mostly the solution came out at about 30 lines of production code and 30 lines of tests and you could pretty much do it in the time allocated. I also did solutions C# and Haskell. The Haskell solution came out at about 30 lines total - both tests and production code - and met every constraint (no loops, small functions, no if statements).
Doing the same problem over and over again is surprisingly effective and nothing replaces sitting with a person to learn a new language or to be exposed to a variety of solutions. One of the tricks - and you find this frequently with pair programming - you have to be very good at communication - both by saying what you're doing but also getting the other person to explain themselves.
I also learnt:
- Even with something as well defined and familiar as "The Game of Life", the solutions were varied and some of the requirements (based on the rules on Wikipedia) were redundant.
- My brain is very weak compared to how well Google search works.
- Between each new attempt you tend to reflect on each previous solution and see the negatives and positives.
- By continually starting a new project setup time was greatly reduced - dependencies that get in the way were slowly reduced - editors, libraries, searching the web, etc.
- That it's good to throw code away. It frees you up by allowing you to try different approaches or learn something new (like a different language).
- Think before you hack.
- A functional approach seemed to be where the answers were converging - meeting all the programming constraints that were given.