November 17, 2019

Delete Your Code and Other Reflections from Coderetreat Day

trefoil knot version of conway's game of life Trefoil Knot Conway's Game of Life, Source: Raphaelaugusto

I participated in the 2019 Global Coderetreat Day which was held on November, 16th, 2019, and attempted to solve "Conway's Game of Life" five times throughout the day. Each time I went through the problem with different people and focused on a different software development approach such as Test-Driven Development (TDD). TDD is a software development practice where individual unit tests are written before writing any functional logic and the specific tests dictate which functionality should be implemented next. By the end of the day, I had used various code editors including Visual Studio Code, CodeSandbox, Glitch, and Atom as well as different flavors of JavaScript and JavaScript testing.

What is Global Coderetreat Day?

Global Coderetreat Day is a specific day where volunteers across the world organize and facilitate Coderetreats. A Coderetreat is a day-long event where participants solve Conway's Game of Life multiple times throughout the day alongside another developer. The practice of solving a problem with another engineer is known as pair programming. The emphasis of a Coderetreat is on practicing fundamental software development practices without worrying about finishing a problem and events can either be language-agnostic or focus on a specific programming language. Traditionally, the problem solved is Conway's Game of Life but some Coderetreats may choose to focus on a different problem.

What is Conway's Game of Life?

Game of Life is a simulation in which there's a two-dimensional grid of cells where each cell is either alive or dead. The fate of each cell is dependent upon the state of its (up to 8) neighbors. Neighbors are considered to be cells that are horizontally, vertically, or diagonally adjacent.

The Simplified Rules of Conway's Game Of Life (source: Wikipedia)

  1. Any live cell with two or three neighbors survives.
  2. Any dead cell with three live neighbors becomes a live cell.
  3. All other live cells die in the next generation. Similarly, all other dead cells stay dead.

Below is an illustration from the Coderetreat facilitation guide that shows how the above Game of Life rules play out to determine what state a cell will transition to. In particular, we are looking at the center cell (which would have the index [1][1] if this grid were represented as a multi-dimensional array). In the illustration, the live cells have a smiley face whereas the dead cells have the absence of an emoji and the blue emoji with the tongue stuck out indicates that the smiley is transitioning into being dead based on its current state and the number of live neighbors that it has.

smiley representation of the game of life

Each time you attempt to solve Conway's Game of Life during a Coderetreat it is required that you start with a clean slate and get rid of all of your previous work and come ready to approach the problem from a different angle. Starting over can feel especially frustrating right after the first iteration in my opinion as a good amount of time can go into getting oriented with Conway's Game of Life, the premise of a Coderetreat and setting up the workspace to be productive. However, the beauty of having to completely delete the code in each round means that instead of relying on previous solutions (or mistakes) each iteration forces active recall vs passively referencing previous code. "Starting over" also leaves room for more innovation and exploration than just building on the same solution directly throughout the day would.

The Format of the Coderetreat

In the version of Coderetreat that I participated in, there were 5 iterations, which were ~40 mins. chunks of time to attempt to solve the problem. For each iteration, we were provided with different constraints, deleted all of our code and switched to pair with someone new. Each of these iterations provided me with the opportunity to address the problem from a different angle as I worked through the problem with someone different than in the previous iterations and with a new mental framework in mind. The format for each iteration varied as follows

  1. focus on getting familiar with Conway's Game of Life and attempt our first solution
  2. solve the problem with ping-pong pair programming
  3. solve the problem with red-green refactoring
  4. solve the problem focusing on very clear naming conventions
  5. solve the problem by writing out all of the tests first

After each iteration we also had a mini-retro to discuss how the previous iteration went and how we felt about a particular approach.

Getting familiar with Conway's Game of Life, Coderetreat and greenfield development

The first iteration of Coderetreat was a bit challenging for me as I needed to collaborate with people I hadn't worked with before to quickly figure out how to get an environment up and running in a language with a testing framework. There was a lot of grunt work that needed to be completed before even starting to focus on solving the problem with code. Some folks chose to spend the first iteration getting more familiar with Conway's Game of Life versus setting up their environment. However, having some challenges while setting up a testing library from scratch and configuring the project to allow ES6 syntax during the initial iteration helped make later iterations a lot more efficient. Although in each iteration I was "starting over" from a code-perspective, after the initial one I was able to spend more time focusing on writing code and tests for the problem at hand and less time setting up tools.

Ping-Pong Pair Programming Approach

In particular, I enjoyed the ping-pong pair programming iterations as it lent itself to being a very structured way to approach the task at hand in a focused way and everyone had a clear role throughout the iteration. The ping-pong part of this approach involved one person writing an initial unit test to satisfy a requirement of Conway's Game of Life and then the other person worked to write code that made the unit test pass. Then the person who wrote functioning code writes another unit test that should be solved by the other person and then going back and forth writing tests and solving them until the iteration was over.

Red, Green, Refactor and Mob Programming Approach

I also enjoyed the red, green, refactoring approach in which we went through solving Conway's Game of Life first by writing a failing test (red), then writing code that solved the failing test (green) and then refactoring to improve the initial working solution without making the initial tests fail. During the initial phase when trying to get the test to pass we were instructed to write the "dumbest" code that would allow the test to pass even if that involved hard-coding the functionality. Also, in this particular iteration where the emphasis was on red, green, refactoring I worked in a mob (a group of three developers) where we had three distinct roles. A driver, observer, and navigator. The driver was responsible for actually typing code based on the navigator's instructions while the observer had a less perscriptive role. We decided that every 20 mins. the driver would switch and every 10 mins. the observer and navigator switched off to allow everyone to serve various roles. Like the ping-pong programming iteration, I appreciated having discrete roles for everyone for a set duration.

Naming Conventions Approach

The iteration which focused on programming with more clear naming conventions allowed me and my partner to focus on communicating more to ensure we were on the same page regarding the purpose of particular variables and methods. The approach of focusing on naming conventions led to me breaking down my approach to writing Conway's Game of Life into into smaller pieces which ultimately led to us discussing when and how to consolidate these highly descriptive functions. In other iterations that did not take this approach I was more likey to write more ambiguous function that handled significantly more logic.

Writing Test Cases Upfront Approach

The last iteration of the day involved coming up with a list of various tests upfront (within a few minutes) which I think helped ensure the solution we implemented would satisfy a large amount of test coverage. This was a good starting point and I could see the approach of deciding test cases upfront being very helpful if more time is spent writing out meaningful tests.

Above were the approaches we focused on during this particular Coderetreat but countless approaches or constraints could have been introduced like attempting to solve the problem without using any loops or without using conditionals.

Takeaways

My takeaways from Coderetreat, despite working through Conway's Game of Life numerous times weren't how to program Conway's Game of Life from end to end or even the most efficient way to approach programming. The key takeaways for me were more-so centered around how there a various approaches that can be taken when developing software and how different approaches shift my thinking, leading to different solutions. I ended up using JavaScript for each iteration and was able to see various ways that the same problem could be approached within one programming language e.g., from a more class-based or functional approach. I do not doubt that I barely scratched the surface on the types of approaches that could've been taken but I enjoyed the exploration.

I learned to get more comfortable deleting my code (without committing to git) since we had to destroy all remnants of our code between each iteration. The intent of this was to force us to approach each iteration with fresher eyes,ready to try a completely different approach and reinforce learnings from one iteration to another through active recall. I may want to incorporate this into my workflow by spending more time exploring various solutions to a problem and being okay doing a git reset or git stash and then trying a different approach.

I was challenged throughout the day to embrace the TDD principle of writing the simplest thing to make a test pass even if that meant the solution was hard-coded. Eventually you will hit a wall if all of the logic to satisfy unit tests is hardcoded vs more dynamic however this approach tries to prevent people from adding premature logic before it is required. The idea with this approach to TDD is solutions should evolve to be more sophisticated, as additional tests are added and introduce new requirements that cause breaking changes to more simplistic logic.

A strict TDD approach where you write the "dumbest" thing possible to pass a particular test can lead to writing functioning code that looks like this:

# my_first_calculator.py by AceLewis modified by Monica Powell

print('Welcome to this calculator!')
print('It can add whole numbers from 0 to 10')
num1 = int(input('Please choose your first number: '))
num2 = int(input('Please choose your second number: '))

if num1 == 0 and num2 == 0:
    print("0+0 = 0")
if num1 == 0 and num2 == 1:
    print("0+1 = 1")
if num1 == 0 and num2 == 2:
    print("0+2 = 2")
if num1 == 0 and num2 == 3:
    print("0+3 = 3")
if num1 == 0 and num2 == 4:
    print("0+4 = 4")
if num1 == 0 and num2 == 5:
    print("0+5 = 5")
if num1 == 0 and num2 == 6:
    print("0+6 = 6")
if num1 == 0 and num2 == 7:
    print("0+7 = 7")
if num1 == 0 and num2 == 8:
    print("0+8 = 8")
if num1 == 0 and num2 == 9:
    print("0+9 = 9")
if num1 == 0 and num2 == 10:
    print("0+10 = 10")

The above code is calculator function written in Python that takes in two numbers and adds them. While this particular calculator would pass tests up until a limit because all of the logic is hard-coded it will not know how to add numbers that are outside of its scope. The full version of this code on GitHub can add, subtract, multiply and divide whole numbers from 0 to 50, and is written a similar fashion to the sample above, however the author indicated that handling higher numbers led to Python crashing as the program isn't written in an efficient way. Therefore an important part of TDD is deciding when it makes sense to spend time optimizing a solution to pass several tests versus just hard-coding one's way through the problem.

Thank you Stride Consulting and App Academy for hosting the 2019 New York City Global Coderetreat Day. I enjoyed learning more about various software development practices and having the opportunity to workly closely with a handful of different people!

If you're interested in organizing your own Coderetreat their official website has plenty of resources to help you get started and if you would like to learn more about some of the principles I wrote about above, Corey Haines, one of the founders of the Global Coderetreat Day wrote a book "Understanding the Four Rules of Simple Design" that details his observations and learnings from watching thousands of pairs work through solving Conway's Game of Life.

If you learned something from reading "Delete Your Code and Other Reflections from Coderetreat Day" consider sharing it.
LinkedIn

Hi, I'm Monica! I'm a Full Stack Engineer who is currently building technology to bring people together IRL at Meetup and focusing on growing the React Ladies community for women + non-binary React developers. I'm interested in discussing React, JAMStack, open-source, tech inclusion, automation and more. 🍿