Lessons from a Night at the Randori

Although my claim to being a software engineer spans two millennia, the recent job change has made me keenly aware that my previous support and evangelism roles, while quite technical in focus, had me writing programs versus really developing software. In terms of processes and development lifecycles, my practical skills hearken back to the days of Ada and DOD-STD-2167A, so I’m making it a priority to dive in to modern techniques like Scrum, TDD, DDD, AOP, etc.

chaos taking

To that end, I attended the Boston Software Craftsmanship meetup this past Monday, where the featured activity was a Randori session. The setup is simple: provide a small programming task (conversion from Roman to Arabic numerals, in this case) and apply a test-driven design approach to solving that problem. The twist here is that you work in pairs (one person coding, one person typing) for 5 minutes before shuffling the typist off and bringing a new coder into the mix. Within that five-minute span the goal is to make progress on the task and leave the system so that test cases are green when the given shift is over.

Kudos to the organizers for keeping the programming environment and details out of the way – JavaScript + Jasmine + Sublime – really provided a minimal logistical barrier to entry. Even so, and as much as I’m used to speaking to audiences, I have to say live coding always makes me feel ‘exposed.’ I jumped in anyway toward the middle of the exercise, and thought I’d reflect on the experience (unfortunately, I had to leave a bit early, so wasn’t able to stay for the post-exercise discussion).

  1. It’s hard to let go.  When the kata was announced, I spent a few moments mentally formulating an approach to the problem; that approach though didn’t match the flow of the first few participants, and when I got to the hot seat, it was harder than I expected to adapt.
  2. It’s ok to fake it (but that doesn’t mean I like it!).  My “do it right the first time” mentality is being challenged by the mantra that passing the test by any means is the goal. For instance, assuming the domain of Roman numerals with values from 1 to 100, the following (pseudo) code would pass the test for the input “I”:
    // romanNumeral is a string input
    int value = getArabicValue(romanNumeral);
     
    function getArabicValue(s)
    {
         if (s.length === 1)
              switch (s[0])  {
                   case "C": return 100;
                   case "L": return 50;
                   case "X": return 10;
                   case "V": return 5;
                   case default: return s.length;
              }
         return s.length;
    }

    I know that seems horribly contrived, but for about half of the exercise, the use of string length in just this context passed muster. Perhaps the contextual error (specifically in the default branch of the switch) would be caught in later testing rounds, but I would submit that it very well might not be. The test passes so all is good right?  That kind of leads me to my next confliction…

  3. It should be ok to think. The Wikipedia TDD entry mentions

    At this point [write some code], the only purpose of the written code is to pass the test; no further (and therefore untested) functionality should be predicted and ‘allowed for’ at any stage.

    but that seems just a tad draconian to me. Certainly you don’t want to go full bore and reduce TDD to a single test of the complete system, but there were times I felt constrained to ignore the obvious and go only where the test guided me. I’ll grant that such singular focus enforces a certain purity in the process, but the dead-ends and thrashing that could have been avoided by just a little bit of a look ahead still nag me. At one point the apocryphal story of monkeys on a typewriter banging out the works of Shakespeare came to mind – I could see we’d eventually get there, but somehow the journey seemed longer than necessary.

  4. Involve domain-savvy users. Our coding scenario (Roman numeral conversion) was pretty simple and well-understood; nevertheless, as the first round of tests went down a (natural) sequential path 1, 2, 3, 4, etc., it became clear to me that domain knowledge should play a part in the test case development. For instance, you need to know a little about the Roman numeral system to realize that 19 is a bit more interesting than 15. Do I even trust myself to create meaningful tests? Might I not project my biases or misunderstanding of the domain into my testing?
  5. Testing is free. Ok, well, not completely free, but it’s kind of cool to see your test suite grow without it seeming like another onerous task. A workflow that doesn’t get in your way is key here: if you have to move from your coding editor to some other system to create a test and run it, it will feel like a hurdle and you won’t do it. I suspect too that’s a main barrier to TDD adoption – not that the tools aren’t there, but that people need to experience the cycle to appreciate it. The legacy of test plans, test procedures, and other onerous (and often meaningless) project documentation probably plays a part as well in unfairly giving “testing” the baggage that it has.

Leave a Reply

Your email address will not be published. Required fields are marked *