In this article I want to share my experience from Global Day of Code Retreat 2022.

The initiative

GDCR is an annual event organized on site and virtually all over the world. As the event page describes it:

Coderetreats are free day-long, intensive practice events, focusing on the fundamentals of software development and design. By providing developers the opportunity to take part in focused practice, away from the pressures of “getting things done”, the coderetreat format has proven itself to be a highly effective means of learning and nurturing software development skills.

This year I had the pleasure to co-organize the event in Ocado Technology office in Wroclaw together with Klose Brothers.

How it works?

At the beginning of the day we’d define the problem - usually it’s Conway’s Game of Life. We set the focus on Test Driven Development and 4 rules of simple design. After the introduction it’s all about iterations. Each goes like this:

  1. Define the limitations
  2. Form pairs or groups
  3. Build the solution for 45 minutes
  4. Delete your code
  5. Conduct a retrospection, see what you have learned, find pros and cons of your decisions
  6. Take a short break and start again

The workshop is described in details in the workshop section so you’re welcome to check it out.

Conway’s Game of Life

Very often the problem we’ll try to solve during code retreat would be Conway’s Game of Life. The rules are simple and are best described by the image

game of life rules

Image by Marco Emrich

In an infinite iteration, the game calculates the next state of the grid based on the previous one by applying the rules.

Depending on the initial set of active cells, the game will evolve differently. One of the possible outcomes is Gosper’s glider gun.

Gosper’s glider gun

Image from Wikipedia

2022 edition rewind

It was the first time I had a chance to take part in code retreat. This time it was around 20 participants from various backgrounds and experience varying from non-programmers to developers with years of experience.

Bubble sort

Each iteration had it’s own character. For the first one all participants stood in the line and were asked to perform a bubble sort by their experience. This way we were lined up from the least to most experienced person. For that iteration we’d built pairs by taking people from each end.

This was a great starter as the most experienced people had a chance to test their skill of knowledge sharing and the mid-experienced pairs were well balanced.

Ping Pong

On the other iteration we went with the ping-pong approach. In this scenario the participants in pairs are supposed to follow this steps:

  • One participant writes a failing test for a minimal part of the functionality and hands over the keyboard
  • The other person implements the function and a new failing test, the roles change

This is a great exercise for TDD approach where the participants learn to organize the code in smallest possible pieces to make as many keyboard handovers as possible.

FP Solution Mob

Since many participants expressed the interest in solution built with functional programming techniques, we have decided to host one iteration as a mob programming.

Considering not all participants were very experienced, we didn’t want to go with too advanced solutions.

You can find the full code in this gist: https://gist.github.com/majk-p/b944530e2b3e8cf00bf9313429bc66c8

To keep things simple we have modelled the grid using a 2D ArraySeq:

trait Grid {
  def value: ArraySeq[ArraySeq[Cell]]
}

Where the Cell is defined as

case class Cell(isActive: Boolean, neighbors: Seq[Boolean])

The neat part about the solution though is the extension method map that allows us to build a new grid by mapping each cell. The mapping function takes a Cell as an argument, meaning that it has access to both the current state and the neighborhood.

extension (grid: Grid) {

  def map(f: Cell => Boolean): Grid = new Grid {
    val mappedState: ArraySeq[ArraySeq[Boolean]] = grid.value.map(_.map(f))
    val value = mappedState.zipWithIndex.map { (row, i) => 
      row.zipWithIndex.map { (cellActivity, j) => 
        Cell(
          isActive = cellActivity,
          grid.neighborCoordinates(i, j).map((x, y) => mappedState(x)(y))
        )
      }
    }
  }

  def neighborCoordinates(x: Int, y: Int): Seq[Coordinates] = ??? // irrelevant
}

Thanks to that, we were able to keep the high level business code clean and elegant, implementing the iteration model using fs2.Stream

object Main extends IOApp.Simple {

  val initialState: Coordinates => Boolean =
    List((1, 1), (1, 2), (1, 3)).contains(_)

  val grid: Grid = Grid.instance(5, initialState)

  val gameLogic: Cell => Boolean = cell => {
    val activeNeighbors = cell.neighbors.count(_ == true)
    if (cell.isActive)
      activeNeighbors == 2 || activeNeighbors == 3
    else
      activeNeighbors == 3
  }

  def run: IO[Unit] =
    Stream
      .iterate(grid)(g => g.map(gameLogic))
      .evalTap(g => Render.render(g)("⬛", "⬜"))
      .metered(1.second)
      .compile
      .drain

}

As usual if you want to try the code you can launch it using scala-cli like this:

$ scala-cli https://gist.github.com/majk-p/b944530e2b3e8cf00bf9313429bc66c8
⬜⬜⬜⬜⬜
⬜⬛⬛⬛⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜

⬜⬜⬛⬜⬜
⬜⬜⬛⬜⬜
⬜⬜⬛⬜⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜

⬜⬜⬜⬜⬜
⬜⬛⬛⬛⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜

⬜⬜⬛⬜⬜
⬜⬜⬛⬜⬜
⬜⬜⬛⬜⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜
^C

Now by simply modifying the input state we can for example watch the Glider move diagonally towards the bottom right.

val glider = List(
  // format: off
  (1, 1), 
  (2, 2), 
  (0, 3), (1, 3), (2, 3)
)

val initialState: Coordinates => Boolean =
  List(glider).flatten.contains(_)

val grid: Grid = Grid.instance(10, initialState)

And here is the output:

$ scala-cli main.scala
⬜⬜⬜⬛⬜⬜⬜⬜⬜⬜
⬜⬛⬜⬛⬜⬜⬜⬜⬜⬜
⬜⬜⬛⬛⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜

⬜⬜⬛⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬛⬛⬜⬜⬜⬜⬜
⬜⬜⬛⬛⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜

⬜⬜⬜⬛⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬛⬜⬜⬜⬜⬜
⬜⬜⬛⬛⬛⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜

⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬛⬜⬛⬜⬜⬜⬜⬜
⬜⬜⬜⬛⬛⬜⬜⬜⬜⬜
⬜⬜⬜⬛⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜

I encourage you to play around with the initial state to see what other results you can get.

If you are looking for more advanced approach check out the solution prepared by 47 degrees for GDCR in this blog post https://www.47deg.com/blog/game-of-life-scala

Summary

Code retreat is a fantastic way to improve your professional skills, an opportunity to meet great people and gain a new perspective on software development. I definitely recommend taking part in this kind of event if you have an opportunity to do so. Make sure to check out https://www.coderetreat.org/events/ to find upcoming events.