What I learned in the Global Day of Code Retreat
Join the DZone community and get the full member experience.
Join For FreeThis Saturday, 2200 software developers gathered in more than 90 cities around the world to improve their skills. This Global Day of Code Retreat was the biggest edition of such an event.
I attended the local edition of Milan, which quickly filled up all the available seats in half a day from the announcement. This local event was organized by exponents of the local XP User Group.
The rules
Code reatreats are organized as a set of iterations of 45 minutes, with a retrospective at the end of each, and a short break for coffee and food. 3 iterations are performed in the morning, and 3 in the afternoon.
During the iterations, TDD and Pair Programming are used to develop a simulation of Conway's Game of Life. At the end of each iteration, the code is deleted: the point of the day is training in facind and solving a coding problem, and in a few concepts such as the use of programming languages, the 4 rules of simple design, or pair programming. The goal is not to write production code, but to sharpen our saws.
During the retrospective at the end of each iteration, everyone can tell the group what he has learned, or what he thinks will improve next time. Moreover, some constraints are introduced for the next iteration.
As our host said, you don't know what you can do with your left arm until you lose the right one. We introduced constraints such as no primitive types, no else keywords, or mandatory ping pong pair programming.
1st iteration
Featuring: PHP, outside-in approach (starting from the Api of a World object representing the whole game).
We wrote a working solution for implementing the first rule of the game (cells that die of solitude). However, it was a lot of code for a 4-line test, and and the green and refactoring phases took a very long time.
What I learned: during outside-in approaches it's mandatory to delve into unit tests for internal components, not only work with end-to-end ones. Even if you are short on time, you can't ignore the feedback of finer-grained tests. Maybe implementing the first outside-in tests with mocks and stubs to transform it into unit ones will help to avoid using them for the whole system.
2nd iteration
Featuring: Ruby, a bottom up approach (the opposite of outside-in, starting from the Api of the single cells).
We introduced a limitation in scope to favor an incremental approach: first, we only implemented one rule at the time (the game is built from 3 rules, but we ignored the latter 2 when starting.) Second, we reduced the problem to a single dimension: an infinite line instead of a plane. This constraint fueled us up and it really helped to get started writing simple tests and code.
What I learned: BDD is a standard in Ruby while TDD is a standard in PHP; RSpec is their PHPUnit I guess. It's more readable, and probably has a steeper learning curve; it contains the same setUp() and lots of tests divided in contexts/test cases as xUnit, the difference is in method's names, and how you write assertions.
3rd iteration
Featuring: JavaScript, bottom-up; the constraint of avoiding Primitive Obsession (no strings, arrays, or floats; only object that wrap them are allowed.) A way to easily avoid Primitive Obsession is to prescribe that primitive types can only be passed to constructors and not to other methods.
The most significant problem of the iteration was getting meaningful error messages from the tests, as jsTestDriver only shows the errors generated by the browser it's using to run the code. Maybe I should look into Jasmine, another JavaScript testing tool that many people used.
We introduced not only the Cell object this time, but also the Neighborhood object because we couldn't pass arrays but only objects wrapping them.
What I learned: thanks to the avoidance of primitive types, we introduced the Neighborhood, an object that encapsulated the state of the cells around a current one (and some behavior: counting how many of them are alive at a given time). With this design, the code was really beautiful as the Cell object only had the responsibility of mutating itself instead of looking around (communicating with a passed in Neighborhood)
4th iteration
Featuring: PHP, and an approach which I don't know if it's outside-in or bottom-up as it was really incremental.
We grew an object from representing a cell to representing a triplet of cells on a line, and then 6 cells on two lines.
What I learned: my pair taught me how to work with a lot of Fake It choices and lots of tests, in a very granular approach. In many cases the cycle time of red/green/refactor was really a minute or so.
5th iteration
Featuring: Clojure (a dialect of LISP).
The approach was using an immutable data structure, a list, to represent a line of cells. The the tick() pure function and all its delegates took the structure and returned the new line after the evolution.
The open problems remain how to represent infinite lines, how to extend this data structure, and how to call the smaller functions. restOfGrid sucks as a name, but I have not much experience in naming functions as I have with naming objects.
What I learned: The problem adapts really well to the functional style: for example, in imperative languages there were race conditions between updating a cell with the state after the tick, and maintaining the information of the older state to calculate what the other cells should become. Using immutable Value Objects is the approach of OOP here, and it is really similar to the functional one.
6th iteration
Featuring: still Clojure, and another pair who wanted to learn the language. Moreover, I wanted to repeat the kata to learn Clojure idioms.
An example of new idiom learned is that I can use map instead of recursion for the easier cases, when the evolution of an element of the list depends only on itself. Is Replace Recursion With Map a functional language refactoring?
I think I need a book on LISP to understand this concepts better, but now I know that functional languages are not toys and can be used to solve complex problems (although I do not always immediately seem how.)
This time, functions gained easier to read names, and I tried to move logic between them.
What I learned: the double cycle of TDD (red on end-to-end tests, red and green on unit tests, and finally green on end-to-end tests) applies also to pure functions and their decomposition. Instead, we wrote again a lot of code based only on the end-to-end test (for the global function *tick*). Maybe a bit of design on the back of a napkin of the functions needed for the current test would help.
Opinions expressed by DZone contributors are their own.
Comments