Each year JUG Łódź is hosting (with ofc the great help of our sponsors) a Global Day of Coderetreat. For anyone that is not familiar with this type of event: it’s a whole day of 45-minute sessions of pair programming. After each session, there is retrospective where each pair describes what went well and what went wrong. Did I mention that we randomize people in pairs each time? Yes! Coderetreat is supposed to help you start looking on a problem from a different angle: if your partner is using different language, platform, technology than you’re used to it’s a wonderful opportunity to learn.
We started with introducing ourselves, I laughed a bit because it looked like an AA meeting. Every participant stood up and said his name and programming languages he had configured on his laptop.
You can imagine that on an event prepared by JUG there will be a lot of Java, but many people wanted to work in Scala, Kotlin. We had one person with C++, one with Erlang and one with F# (me). When people started to describe what they wanted to try the most then Kotlin was the definite winner. As I normally work in Java / Kotlin I hoped for a session with someone programming in Haskell, Lisp, ML - maybe next time.
Before I start describing each session and how they went, I would like to quickly thank the facilitators of the event: Paweł Włodarski and Piotr Przybylak. They introduced each session rules and explained issues we might find. During the sessions, they went from pair to pair to monitor the progress and answer any questions that popped up. Great work guys!
The “Game” plays out on an infinite two-dimensional grid of cells, each of which can be dead or alive. Every cell has eight neighbours, each step of the game the following rules are used:
To start the game you need to pass an initial pattern (seed) of alive and dead cells. The game continues infinitely (or for how long you want). You can read more about it on Wikipedia.
The first session was a warmup, we could code however we wanted, no limits. I already had few ideas how to approach the problem the week before the event so I really wanted to hear how other people think. After a little bit of a discussion with my partner, we came up with a solution like this:
width * height
I suggested that we should go with a stateless solution. So the
Game just took
Board state and produced another
Board state. After a bit of implementing, Paweł came and told us:
After this recommendation, we went on to testing and implementing just the rules of the “Game”. Unfortunately, we just managed to write few tests before we ran out of time.
I need to apologize to my second partner because I completely dominated that session. I just wanted to implement one of my ideas to solve the problem so badly :-( Sorry Marek!
I tweaked the limits for this session and added some more:
So what devious idea did I have? It’s very simple or at least I thought so before I saw my partner’s face expression ;-) Basically, everyone so far was implementing the “Game” with a distinction between alive and dead cells. Why not just drop the idea of dead cells completely? I know it’s tempting to use those to ease the “reproduction” part of the game but do we really need those?
Although Kotlin is not a “pure functional programming” language it was a pure pleasure (pun intended!) to implement the whole thing. Especially collections made everything easy as a walk in the park. It was possible to focus only on the algorithm! Our final solution was more or less 50 lines long (sic!). By final solution I mean the code without printing game iterations or running it.
After a short discussion, we went with implementing the
Cell class hierarchy idea. My partner wanted to learn Kotlin better so I thought this session would be nice to introduce him to some concepts like
extension function and
extension fields. I was happy that I could teach something in this short amount of time. We had also a short but nice discussion about the Observer pattern implementation, I was advised to watch this talk by Adam Badura and I definitely will!
You probably noticed that I’m hardly writing anything about our glorious implementation? You’re correct because it didn’t go well. We created the hierarchy but we had issues with traversing cells correctly. Not a lot of conclusions on the retrospective so I will skip it.
I loved this session! It was a real mind bender and a tough one. Everything seemed simple until we started thinking what should be produced by the stream.
I have only small experience with streams (mostly RxJava), in most cases, they were backed up by finite collections. Believe me, I did not know where to start. I had a vision of combining or zipping the streams, but what streams I did not know ;-) As always Paweł came with help and suggested combining a stream of alive cells with a stream of neighbours but we were lost in the implementation.
This session was all about TDD, we were supposed to write the tests first. Writing a
Cell class would be considered cheating in this exercise. Why? Simply because everything should be extracted from the test instead of written before. We want our tests to be a contract for our code, we do not know yet how this code will look like because TDD is supposed to give it the “correct” form.
How to apply this to our “Game”? Let’s start with simple things like: “if there are no alive cells then no cells can be born”.
Do we need anything to write this test?
No! We do NOT need to create a
Cell class! We can use a
Boolean to represent it.
Boolean is especially useful as we get dead and alive cells for free - but it’s not important now!
What about coordinates?
What coordinates!? Our test doesn’t say anything about any position at all so we don’t need any. It’s important to focus on defining the contract first.
So we created few passing tests then when to extract?
Whenever you will see some duplication. By duplication I mean when the same idea is repeated not the same code (there is a big difference). Now, this is the tricky part how to spot such duplication? A simple example:
There is a vague duplication of an idea. The idea of changing a set of cells to another set of cells. Now we could probably extract some function that takes the state of the “Game” and returns another. The same thing goes for other more detailed tests, at some point our
Boolean cell won’t be enough and we will refactor it into something better suited to our needs. Important thing is to create only things that are needed for the test to pass and nothing more!
Unfortunately, I could not stay for the final sixth session - working with legacy code. The idea was simple, people should not delete their solutions after session 5 and just swap laptops between pairs. Every session was great but that TDD one made the day for me, definitely time well spent.