- "Ruby guy?"
- "Willing to teach?"
- "Yes, no problem."
This was Saturday morning. Cluj Cowork. A two storey house, with tall, airy rooms. Inner staircase and sturdy timber vintage furniture. A thin balcony upstairs, traced with wrought steel. Back in the days of my small internet marketing empire, I remember dreaming of working in a such a dynamic place.
The first round had started. It was a loose warmup. I was surprised how quickly you could hack something together in Ruby. "I'm in love", I confessed to my pair. No, not with him, with Ruby.
We chopped a couple of classes and a test scenario in RSpec. The one and the only testcase for that session, actually. It checked whether the desired output was given based on a blinker input.
The challenge: Conway's Game of Life
The lack of stable Internet connection warded off my habit of spending too much time documenting myself to know everything about... everything. More doing!
It was time to focus on tests more. Assumption: TDD works. Why does it work? Well, insight occurs after you mastered it (I'm nowhere near that).
Second round was a drag, because of environment issues. Not wanting to let the time to go waste, I fired up Octave and started sketching some functions and input data, while my pair wrote a couple of tests on a piece of paper.
After this session, my fellow coders started raising some interesting points. How do you write your first, primitive test? Start with the user story, a basic use case, your standard survival rules.
What were we doing here? Upside down? Bottom up? What types of tests were writing? "Inside-out design" was also coined, which, at least for me, made a some sense in regards to how we were tackling the problem.
Apparently it doesn't matter much. TDD is a discovery process, a technique that makes your design evolve. You can expect to either confirm your early design choices or find that there are better choices you can make.
I felt a bit lost but my ideas started to settle down with the next session. Java and JUnit were the tools of the trade. First test: there exists one Universe with a single dead cell. Lesson learned: The best place to have a method which creates the Universe is in the tests. In production, you'll likely never encounter this need, and unused code smells. One can start with a test like "iterate through the cells until you encounter one live cell with a neighbor". Such a test should be removed at the next refactoring. Same goes for a method which creates a new Universe.
During lunch, members of other teams got together and the conversations started getting abstract. Anonynous functions, sparse matrices, serialization methods and yes, even memory concerns sparked.
My brain was turned into fuzz, while the extra sweet dessert encouraged me to drop most of my assumptions about the Universe. The concept of a Universe turned out to be nuiance for others too. Ideas started getting bold and interesting, while a new, "ping pong" rule was instated: one member of the pair writes a test, the other does the magic for it to pass, and serves back another test.
I was geared up with enthusiasm "Let's start from a cell. Let's not even know we have two states, since we only need to know about state when we start poking the logic around the fourth rule", I suggested and my pair quickly resonated with the idea.
Lessons learned: If possible, refactor after every test in such a way to keep the production feature which it tests. Even if a test is removed, the feature which it tested should be preserved. A test is useful when it helps you generate code.
At one point the question as to why were there tests written for classes popped up? A different suggestion was made to write unit tests for rules instead.
We took this approach for the fifth and final session. We started with the fourth rule of Game of Life, since it dealt only with dead cells. To make things even more challenging we were not allowed to speak to each other. Once more, to my delight Ruby and RSpec
The last discussion session brought up a couple of insights about comments. Document what's not obvious after going through the code. If you do a hack, write a comment for your future self.
My conclusions on TDD:
TDD is a technique which aims at creating healthy development habits. TDD is not a religion (like OOP), there's no bible for it, and there's no way of doing things in a pure TDD way. Sorry. You can't write tests without having a design in mind. Tests provide a safety net, but no silver bullet (sic) can replace thinking while even high testability doesn't imply a good design.
What's next for me? A Sublime mix of Ruby flavored with scent of Jasmine.
Thanks for the amazing day, everyone! Especially: Raluca, Cristina, Silviu, Florin, Istvan, Csaba, Costin, Corina, Sergiu, Robert Vissier, Oana, Alex, Nora, Florin C. That's everyone I can recall from the top off my head.
And thank you RABS for bringing us together.
Photo courtesy of RABS
How was your CodeRetreat?