While everyone was sleeping out last saturday, groups of software developers worldwide assembled to participate in this cool event called global day of coderetreat. The concept of a coderetreat is simple: whereas the only way for other professions like musicians to get better is to train their skills by regular practice -just for the sake of practice-, software developers never seem to really “train” their skills. They get dropped in one deadline-prone project after another, but never really take the time to perfect their skills (or as Corey Haines likes to call this, get industry best practices under their fingers). Software developers can train their skills individually by performing code katas, or they can do so in group by attending a coderetreat.
Just as musicians get better by practicing scales and jamming with other people, developers can improve their skills by performing code katas and attending coderetreats.
A coderetreat has a simple formula:
- Take a well-understood problem (in this case, Conway’s Game of Life)
- Have pairs of programmers tackle the problem in sessions of 45 minutes each
- After 45 minutes, have everyone delete their code
- For the next session, each developer pairs with a new partner
The goal of each session is not to provide a complete solution to the problem, but to practice skills like TDD, taking small steps, writing easy-to-understand code,… By requiring everyone to delete their code after each session, the focus is kept on trying new things and improving your techniques, rather than staring blindly at the problem at hand.
Because not everyone is as familiar with the principles of pairing, TDD and good object-oriented design (we even had testers that had never written a single line of code hanging out with us), the facilitator lays out the 4 rules of simple design:
- Your code must pass all tests. This implies you must actually write tests. It does not say you have to write your tests before you write code, but we did TDD the entire day with great results.
- Maximize clarity. Do not write any comments, the code must speak for itself. For anyone interested, clean code is an obligatory read for everyone that ever writes a single line of code.
- Minimize duplication. This not only applies to production code, but also to test code (a real eye-opener for me, single line assertions are so pretty!) and duplication of meaning. At one point, we had two sets of rules. One set defined when a dead cell should regenerate, the other set defined when a living cell should die. When our facilitator pointed out the duplication in meaning in this (what exactly is the difference between “dead” and “alive”?), we had our Eureka-moment and were able to get to a much cleaner design.
- As little as strictly necessary. Don’t implement nice-to-haves, don’t think too far ahead. Write the bare minimum to get your current failing test to pass. In combination with TDD, this rule has changed the way I write software for the better.
Only when you violate one of these 4 rules, the facilitator will gently nudge you in the right direction. Erik Talboom, our facilitator of the day, did this by sticking a post-it on your screen listing the rule you were violating.
The first session serves as a get-to-know-the-problem-and-concept-of-a-coderetreat kind of thing. To make things extra interesting, each following 45-minute session had a combination of several constraints:
- Every method can have a maximum of 4 lines. This keeps code fragments small and understandable.
- Avoid datastructures. Instead of forcing the problem into the data-structures of the programming language you’ve come to know and love, this constraint lets you focus on implementing the business logic, the real business value first. It was a great experience for me to see how far we actually got by just implementing the behaviour first (i.e. implementing the rules that define whether a cell lives or dies in the next generation) and not think about class-structure or any datastructures in general.
- Mute ping-pong. This one i really loved. During ping-pong, the first developer writes a test and passes the keyboard to his partner. The partner writes just enough code to make the test pass and writes a new test. The partner then passes the keyboard back. Lather, rinse, repeat. But here’s the kicker: it’s mute ping-pong. You. don’t. talk! This constraint really forces you to write meaningful and self-explanatory code (both in test and production code). At first I was a bit scared, because for this session I had decided to pair with someone that was working in Lua, a scripting language I had never even heard of. This turned out to be no problem at all, since as he wrote the first test he litteraly showed me the syntax of the language by example.
- Baby steps. Another favorite of mine! Software developers tend to bite off more than they can chew. I know I have been guilty of this (for example, by making a bunch of changes to a build script that takes half an hour to run, only to realise after a failing build 25 minutes later that somewhere in bunch of changes I had made a mistake). If you take small steps and verify the end-result (i.e. run your test suite) it’s easy to back out of a mistake, since it’s the last little change you just made. The baby steps constraint pushes this way of thinking to its limit: before you start writing code, set a timer on 2 minutes. You can write as many tests, produce as much code or perform as many refactorings as you want. When all tests are green, you can relax and commit your work to a local source control repository like Git. But when the timer rings and you were still working on something, you must revert to the latest version you commited. git reset –hard, no exceptions. We had a few time-outs in the beginning, but after a while me and my partner were really making progress in these 2-minute timeframes and the timer rarely went off anymore. Add a test, write some production code, run tests, commit. Spot some duplication, refactor, run tests, commit. We combined this constraint with ping-pong, which resulted in a very fast and steady pace of development. Of all the sessions, we got the furthest to solving the entire problem. This constraint might be pushing it too far, the constant time-pressure and context-switching is very fatiguing and not a suitable state of mind for everyone. Our facilitator enlightened us with a fitting analogy:
In order to bend steel in a certain angle, you must flex it too far in order for it to remain bent in the position you want.
- TDD as if you meant it. The idea here is to really push TDD to the limit: You write a failing test. Next, you implement the production code to make the test pass in the test method itself. Remove duplication by extracting common code in the tests into a method in the test class itself. Only when you have several methods in the test class that fit nicely together, introduce a new class and move the methods there. After a while, these new classes will attract more and more data and behaviour out of the test class. I must admit I had problems with this constraint. Things just didn’t seem to “click” in my mind as with the other ones. I think the problems I had originated from the fact that we took a different approach to the problem compared to the other sessions. Me and my pair had done the “who lives”/”who dies”-rules for the entire day and wanted to tackle the problem from another angle, the grid itself. This turned out to be a lot less straightforward, especially when combined with this constraint. I am however fascinated by the rationale behind TDD as if you meant it and am very eager to try it out again in the next coderetreat.
After each session, we held a retrospective to discuss our experiences. Since this event was called global day of coderetreat, we did some retrospectives using Google+ hangouts with developers all around the world. This is a very nice format, as it allows for knowledge sharing not only across pairs, but across the entire audience. The retrospectives often lead to interesting discussions about software development in general, different approaches used by developers and general communication skills.
What I learned.
It was very nice to get back into the reality of software development. It’s been a while since I had touched a modern IDE. Writing object-oriented code test-first in a range of modern IDE’s while pairing with passionate developers reminded me why I really love my job.
Some key points that stuck with me:
- Duplication in tests is as bad as duplication in production code. When refactoring, a test suite burdened with duplication is just as painful.
- Once you know your way around your IDE, TDD does not slow you down. Write a failing test, stub in a method to be created at the push of a button just to get the test to compile, run the test by pressing ctrl-F11 to make sure it fails, implement the least amount of logic to make the test pass, rerun the tests to make sure it’s green. Refactor your code under the safety net of tests, absolving all sins you commited to get to green as fast as possible. All of this does not take longer than just writing code and adding in tests when you see fit. In addition, the code coverage will be very high by definition, allowing you to refactor your code with confidence.
As an added bonus, code resulting from TDD done right is clean, modular and testable by design!
- Take small steps. Make a small change, run the tests, refactor, run the tests again. When the tests turn out red, it’s very easy to spot your mistake if you only changed a single line of code.
- It’s all about communication. Don’t write code in the literal sense of the word. A computer will understand you, no matter how cryptic you are in your naming conventions or programming style. It’s the other developers you should be writing the code for in the first place. Choose meaningful names. Keep your methods small and understandable. This might require more effort in the initial development process, but it all pays off once you – or even worse, someone else – gets asked to fix a bug in your cryptic mess.
Rejuvenated by my experiences during the coderetreat, I applied some of the principles that stuck with me as soon as I got back to work on monday. I currently work on a SQL-heavy application and I hadn’t really tried applying TDD principles there. I was amazed by the results of this approach, even in a non-OO environment.
I would like to thank everyone I paired with, everyone that gave me new insights during the retrospectives and our facilitator of the day for a great day of learning and geeky fun!