Our take on Global Day of Coderetreat 2023

Mateusz Chrzonstowski,

Michał Rowicki

November 09, 2023

Coderetreat is a day-long workshop focused on sharpening software development skills. There are different forms and flavors, but usually you use Pair-Programming and Test Driven-Development to implement Conway’s Game of Life and delete your code at the end of each session.

Some benefits it can bring to your team:

How to organize it?

We had some experience with participating in Coderetreats, but we never organized one. Because of that, we decided to run an internal-only session, without much advertising and limited just to the Polish branch of our company and with just 4 sessions.

The Workshop, Hosting Guide, Facilitation Guide and Constraints articles all contain great hints on how to organize, prepare sessions, etc., but we started one step back by creating an online spreadsheet to allow anyone to put their name with some details on

Thanks to that, we could assess what kind of sessions we could run, how big of a room we needed, how much food, etc. Following the No Pizza Rule we ordered sandwiches and sushi according to the number of in-office participants.

We also created a simple starter pack to hint participants what to check before the workshop (IDE plugins, microphone, TDD starters, etc.).

How to run it?

Thanks to the small number of participants (4 in the office, 4 online with 5 and 3 planned initially), we created a more inclusive atmosphere. Literally, everyone said a couple of words of introduction, and each session ended up with a retrospective where we talked individually. With a bigger group, we could run in-pair retrospectives and end up with a summary or more open discussion, but it would be very limited in time.

In our case, pairs were chosen a day before, in order not to waste workshop time. We wanted everyone to code online at least once (as it’s close to the nature of our work), but we also wanted everyone to utilize office space and have first pairs sitting next to each other when possible. We also assigned based on preferred and secondary programming languages.

We used the following slides: mat3e.github.io/talks/coderetreat/en and the schedule as follows:

  1. Introduction [15m]
    1. Everyone said a couple of words about themselves.
    2. Goals of Coderetreat.
    3. Pair-Programming explained.
    4. TDD explanation and contrasted with higher-level tests.
    5. Game of Life explained.
  2. Session 1 [45m] - no restrictions, just giving it a try.
  3. Retrospective 1 [15m] - thoughts, especially on deleting the code.
  4. Session 2 [45m] - no mouse time, focusing on keyboard shortcuts.
  5. Retrospective 2 [15m] - thoughts, especially which keyboard shortcuts you learned.
  6. Lunch break [30m] - No Pizza Rule :)
  7. Session 3 [45m] - using secondary programming languages.
  8. Retrospective 3 [15m] - thoughts, especially if you plan to use the same language in the next session.
  9. Session 4 [45m] - developing within 5-min deadlines (called Baby Steps here).
  10. The Closing Circle [15m] - observations about the last session and 3 questions:
    1. What did you learn today?
    2. What surprised you today?
    3. What will you apply starting Monday?

Participant’s perspective

Each of the sessions provided me with valuable insights and learning experiences.

In our first session, my colleague, who works primarily with Kotlin daily, and I embarked on solving the Game of Life problem in Kotlin. Our initial focus was to create an elegant API based on multiline strings that could eventually support emojis and generate aesthetically pleasing output with each generation of the game. We began with input data validation, aiming to write idiomatic Kotlin code. Surprisingly, we got caught up in this aspect and didn’t even start implementing the algorithm during the session. Nevertheless, I had a great time recalling the syntax peculiarities of Kotlin, as I mainly work with Java in my daily tasks. On the other hand, we learned that it might be wiser to dive into the algorithm initially instead of refining the API. Towards the end, the decision to discard all the work was not mine alone, but it was a somewhat painful but necessary step to adhere to the egoless approach, as highlighted in Greg Young’s well-known presentation, ‘The art of destroying software’.

With this approach in mind, we entered the second session, revisiting the Java environment with the added challenge of not using a mouse. Fortunately, this was a minor challenge for me, as I had previously explored keyboard-centric work techniques with a colleague at a previous job. It resulted in numerous feature requests to JetBrains for missing keyboard shortcuts and installing the Vimium plugin in our web browsers. While I have become less dogmatic about such matters over time, it still bothers me that specific actions, like submitting a pull request to GitHub via a JetBrains plugin cannot be accomplished solely with the keyboard. Returning to the session, I realized that I had forgotten the keyboard shortcut for setting breakpoints (⌘ + F8) and for launching the debugger (⌃ + ⌥ + D). Code With Me, unfortunately, lacks shortcuts for switching between modes like follow or pair coding mode. We acknowledged that using the debugger is considered an antipattern, but we decided to explore it using only keyboard input since it’s a tool we rely on daily. Regrettably, we still couldn’t solve the exercise due to a simple mistake. Nonetheless, we had an enjoyable time. While practicing TDD in Ping-Pong style, we broke the convention by altering our approach during an extended implementation. This highlighted the importance of not letting iterations become overly prolonged. When making such changes, it’s beneficial to consult with your partner empathetically to ensure it aligns with their preferences, fostering mutual respect and trust. It’s essential to remain open to alternative approaches and not forcefully impose your own. During the implementation phase, we devised a more straightforward test case idea to test the entire algorithm behaviorally.

In the third session, we returned to Kotlin, and the knowledge gained in the previous two sessions proved valuable for both my new partner and me. We immediately approached the problem from an algorithmic perspective, leaving the polished API for the end. However, this time, it was more challenging, as neither of us primarily programmed in Kotlin. Everything was progressing well until we encountered an error. Instead of debugging, my partner convinced me to add logs, which proved invaluable in identifying the issue. I found this experience refreshing, as I seldom employ this technique daily. GitHub Copilot was a significant help when adding logs, making the process quick and efficient. Unfortunately, the primary issue remained elusive. We tried using the debugger but to no avail. After thorough code analysis, we discovered we were building a new state based on a shallow copy of the previous one. Unfortunately, Kotlin’s arrays only have a .copyOf() method and lack a .deepCopyOf() equivalent. Once we identified this error, the entire Game of Life algorithm worked as intended, though time constraints prevented us from refining the user-friendly API.

This set the stage for my plan in the fourth session. In this round, we aimed to elevate the standards of egoless coding. We followed a TDD pair-coding Ping-Pong approach, with each round limited to five minutes for writing tests, code, and refactoring before committing our changes. Exceeding the time limit meant erasing everything. The exciting part was that this was the final session, and drawing from our experience in the previous sessions, we had plenty of creative ideas to tackle the challenge. Despite this, we faltered while attempting to implement one of the simplest behavioral tests: 111. It’s a single row with three living cells that should transition to 010 in the next iteration. Achieving this in five minutes is not straightforward, and mistakes can easily creep in. Therefore, we bent the rules slightly, taking advantage of our Code With Me setup. We divided the tasks and independently implemented different parts of the algorithm simultaneously. This approach allowed us to meet the deadline. Without this approach, we would have introduced code smells. We would have exposed the implementation details in tests, which must be clarified for users. Consequently, we would have needed to return to behavioral tests covering all aspects of the algorithm, remove implementation detail tests, and ultimately close access to those details. This approach prevented us from cementing our code with unnecessary redundancy while maintaining a minimal set of tests. Thankfully, it worked. Unfortunately, time constraints once again prevented us from refining the API.

In summary, these sessions were a fantastic learning experience. Each one enabled me to acquire new knowledge and refresh my understanding of concepts I don’t encounter daily. Furthermore, they allowed me to collaborate with colleagues from different teams, fostering knowledge transfer and mutual support. My peers share a similar perspective on these sessions.

The Closing Circle of the article :)

Participants were happy with the workshop, and we got more positive feedback. Next time, we plan to run a full-day workshop and probably pair with other offices.

Furthermore, as we already cooperate with Warsaw Java User Group and WarsawJS (they run their meetups in our office), we are considering a public Coderetreat next year, perhaps in cooperation with both groups.