3 September 2021

Baby Steps Push Challenge

Earlier this year I met with fellow developers Roland Germ and Bastien David to discuss how we could make coding exercises more engaging and how participants would have more fun. The training formats we use, like Coding Dojo and Coderetreat, were designed for people to have fun (and engage in deliberate practice in order to improve their skills). Ideas like gamification came to mind and we worked on several constraint games to spice up our coding sessions. (A constraint is an artificial challenge during an exercise to make the exercise more interesting, challenging or fun. I like constraints, e.g. my recent Dice Namer Constraint. In this article I will describe another fun constraint: the Baby Steps Push Challenge.)

At the same time I was working with a client who was adopting Continuous Delivery. One of the issues the developers faced was that they were used to work in larger increments. We had worked through several exercises which encouraged smaller steps, e.g. Taking Baby Steps (revert the code if tests are failing after 2 minutes), Test Commit Revert (revert the code if tests are failing at any time) and even Limbo (revert the code if integration with other code fails). I was looking for more exercises to encourage small steps.

Let Slip the Tugs Of WarIdea of Push Championship
Following my discussion with Roland and Bastien I merged some of their ideas into a "Push Championship" - a challenge who would be able to deliver smaller increments.
  • For this exercise I would need some basic TDD or Refactoring exercise.
  • Pairs would work on the same task on their own using version control with branches.
  • While dealing with merge conflicts is part of trunk based development, there should be no artificial branching problems. Participants just try to make more commits.
  • All commits must be green which is tested by CI - actually it is much easier to count the number of successful build actions on each branch.
  • The facilitator ("referee") needs to grade commits afterwards to avoid cheating the game and awards bonus points for good commit messages.
  • Elements of gamification like coins for each commit/push would be nice.
I created some infrastructure to support the exercise. First there is a central server to count pushes and display the dashboard of positive and negative events during such a "championship": Push Counter Server. It has "Push" in its name but it is more general and can be used to count any form of positive (counting up) or negative (counting down) event. The server application is published on Docker Hub. You can run it with docker run -p4567:4567 codecop/push-counter and the dashboard will be available at http://localhost:4567. You can deploy it to Heroku, which I did. (scripts/heroku_deploy does the job - you need to change the Heroku application name.)

Counting Pushes
The server dashboard displays the current game statistics of all teams - that is the number of positive events - and plays a coin sound (if you allow your browser to do so) when someone scores a point. To notify the server I execute curl at the end of a GitHub build action, e.g. curl -X GET ${{secrets.PUSH_COUNTER_URL}}/​record/team-name?​build=green. Whenever someone pushes to the repository, GitHub runs its build action and the dashboard gets updated.

Distinguishing Pairs
The easiest way to distinguish participant pairs is to use branches. In a scenario where each pair works the same exercise, this works well. I figure out the branch name with some shell and Git commands:
export GIT_BRANCH_NAME=$(git symbolic-ref --short HEAD)
export GIT_BRANCH_NAME=$( echo "$GIT_BRANCH_NAME" | sed 's/ /%20/g' )
curl -X GET ${{ secrets.PUSH_COUNTER_URL }}/record/branch-$GIT_BRANCH_NAME?build=green
The Push Counter Sample Client contains samples with several ways to identify pushes:
  • Using the branch name as shown above. This is dynamic and can be used for pairs working on branches.
  • Hardcoding the branch name in the GitHub action also needs dedicated branches.
  • Reading a team name from a file, i.e. using a lookup file on each branch is also possible.
  • When working trunk based, the GitHub user who pushed can be used (i.e. $GITHUB_ACTOR). This works if pairs do not switch machines.
  • Using a team name lookup by the GitHub user works also when pairs switch machines. Setup of the user name to team name mapping is necessary before the challenge.
  • Using the GitHub user of the last commit is also possible.
  • See the GitHub workflow file.
Test Run
When I tested the setup, I used - you guessed it - my favourite Prime Factors kata. The final score on the dashboard was:
Prime Factors score Choice of Kata
Because of the competition, all participants should be able to finish coding, i.e. it should be possible to finish the exercise in one hour (as part of a workshop or learning hour). Refactoring exercises are a good choice because the given test suite makes sure only working changes/ pushes contribute to the total score. Unfortunately most refactoring exercises are larger than one hour. Then the goal of the refactoring needs to be more specific.

Emily Bache's Parrot Refactoring Kata is a suitable exercise: It is small. (I am able to finish it on my own in less than 20 minutes. In fact - with some practice - I can run through its steps in less than 10 minutes.) And it has many steps, especially if you aim for baby steps. I counted 48 individual changes you can make - and I even missed a few. The concrete task here is to fix the code smell of switch on type code and clean up the code using as many individual, working refactoring steps as possible. Each commit should be delivered (pushed). And then you can repeat the exercise and try to break the score.

Other suitable refactoring exercises might be Top Gear and Promotion Service from my own list of code katas.

Coding Dojo Run
Later I ran the exercise in our local Coding Dojo community. I showed some slides to motivate small increments and gave some hints how to make smaller steps. I prepared a branch of Parrot which reported to my Heroku dashboard. All went as planned and here is some of the feedback I got from participants in the retrospective:
  • The kata (parrot) was the right size, we had plenty of time to work carefully.
  • We had to perform the same change three times - for the three sub-types - and used different approaches for each of them and compared them in the end. That was a bonus.
  • We thought about "How small is small enough?"
  • It is always possible to go smaller - you can commit more often.
  • The constraint encouraged us to take much smaller steps than usually.
  • Very small steps require lots of communication.
  • Very small steps can become confusing due to the pause in between steps.
  • I liked the dashboard and its icons.
  • It would be nice to sit in the same room with the dashboard on a big screen.
  • This notion of scoring works well in teams which have a good relationship.
Your Turn
Now it is your turn to work the exercise. You do not need the server infrastructure if you are on your own. Just clone the parrot and see how many small steps you can make. Then try again and improve your score. Some participants were able to make 52 meaningful, tiny changes to the Parrot using Java. Try to break this high score. Everything above 40 is good and above 50 is very good. If you want to use the exercise for a Coding Dojo, fork the prepared branch of Parrot and set the repository secret PUSH_COUNTER_URL to your dashboard. Have fun!
Final score after review

No comments: