Thursday, April 21, 2016

TJUG Code Kata

Bob Damato and Shane Boucvalt of Valpak in St. Pete hosted the Tampa Java User Group (TJUG) Meetup tonight at Valpak's Manufacturing Center.  Tonight's meetup was run as a Code Kata, which is basically where a facilitator hands out a problem statement / requirement that can be solved/coded/tested within the space of a meeting in a safe environment where like minded developers can collaborate to solve the assigned issue.   The purpose behind the Kata is to give the developers a chance to practice their craft in that safe environment.  The problems are usually a generic puzzle style problems that require some thought goes into the solution and the unit testing scenarios.

Tonight's problem was called the Monty Hall problem.  From wikipedia:

Suppose you're on a game show, and you're given the choice of three doors: Behind one door is a car; behind the others, goats. You pick a door, say No. 1, and the host, who knows what's behind the doors, opens another door, say No. 3, which has a goat. He then says to you, "Do you want to pick door No. 2?" Is it to your advantage to switch your choice?

We were asked to run 2 - scenarios of 1000 runs each where the winning door and your guess are selected at random.  In  scenario 1, you stick with your first choice.  In scenario 2, you pick the remaining door.  The code is to determine which scenario has the advantage.  You could write in the language of your choice but given that this is the TJUG, java was kind of expected.  I choose Groovy because I like it and its close enough to Java that the others could read my code if I was explain it.  I wrote my tests in Spock and was happy that I could quickly spin up an app with a Gradle build and Spock tests within Intellij Idea.

It was a last minute decision on my part to attend as I was cutting it close to leave work at 5:30 pm in Tampa to get to St. Pete for the 6:30 meetup.  Because you so rarely get to do any coding in these type of user group meetings, I really wanted to attend this one.  It had a somewhat small turnout, but was interesting none the less.  It took me about an hour to get a working application that yielded the results.  My test were more about exercising my solution rather than checking the solution's validity.   Bob, Shane and other Valpak employee's who had previously done this Kata, shared their solutions and showed how to break testing down to 4 simple scenarios that validated the outcomes.  I was happy to have the opportunity to share my solution at the lectern with this small crowd.  I'm not always comfortable speaking in large group settings, so I was glad to have a chance to do this in this environment.

It was a really fun exercise and I look forward to sharing the Kata experience back at the office. Thanks to Bob and Shane, as well as Valpak for hosting this meetup. I am including both my code and tests for the Kata below.  More refactoring could be done but I wanted to post exactly what I ended up with in the allotted time:


KataMain.groovy

 package com.bpcs.kata  
 /**  
  * Main Kata for TJUG  
  *  
  * Created by wpfeiffe on 4/21/16.  
  */  
 class KataMain  
 {  
   public static void main(String[] args)  
   {  
     KataMain kataMain = new KataMain()  
     int winner = kataMain.runScenario()  
   }  
   int runScenario()  
   {  
     int winner = -1  
     Integer firstStrategyResult = this.getFirstStrategyResult()  
     Integer secondStrategyResult = this.getSecondStrategyResult()  
     println "The first strategy wins $firstStrategyResult times out of 1000"  
     println "The second strategy wins $secondStrategyResult times out of 1000"  
     if (secondStrategyResult > firstStrategyResult)  
     {  
       winner = 2  
     }  
     else if (firstStrategyResult > secondStrategyResult)  
     {  
       winner = 1  
     }  
     println "The winning strategy is $winner"  
     return winner  
   }  
   Integer getFirstStrategyResult()  
   {  
     Integer result = 0  
     List<Integer> doors = createItems()  
     List<Integer> guesses = createItems()  
     doors.eachWithIndex{ int door, int i ->  
       // if they picked correctly  
       if (door == guesses[i])  
       {  
         result++  
       }  
     }  
     return result  
   }  
   Integer getSecondStrategyResult()  
   {  
     Integer result = 0  
     List<Integer> doors = createItems()  
     List<Integer> guesses = createItems()  
     doors.eachWithIndex{ int door, int i ->  
       // if they did NOT pick correctly  
       if (door != guesses[i])  
       {  
         result++  
 //        Integer nextPick = pickRandomDoor(2)  
 //        if (guesses[i] == 1)  
 //        {  
 //          nextPick++  
 //        }  
 //        else if (guesses[i] == 2)  
 //        {  
 //          if (nextPick == 2)  
 //          {  
 //            nextPick++  
 //          }  
 //        }  
 //        else  
 //        {}  
 //        if (door == nextPick)  
 //        {  
 //          result++  
 //        }  
       }  
       // else they change and result is 0  
     }  
     return result  
   }  
   List<Integer> createItems()  
   {  
     List<Integer> items = []  
     (1..1000).each {  
       items << pickRandomDoor(3)  
     }  
     return items  
   }  
   Integer pickRandomDoor(int max)  
   {  
     Random rand = new Random()  
     rand.nextInt(max) + 1  
   }  
 }  

KataMainSpec.groovy

 package com.bpcs.kata  
 import spock.lang.*  
 /**  
  * Spock tests for TJUG Kata  
  *  
  * Created by wpfeiffe on 4/21/16.  
  */  
 class KataMainSpec extends Specification  
 {  
   def "Test Create Items"() {  
     setup:  
       KataMain kataMain = new KataMain()  
     when:  
       List<Integer> items = kataMain.createItems()  
     then:  
       items != null && items.size() == 1000  
   }  
   def "Test Random Door"()  
   {  
     setup:  
     KataMain kataMain = new KataMain()  
     when:  
     Integer door = kataMain.pickRandomDoor(3)  
     then:  
     door > 0 && door < 4  
   }  
   def "Test First Strategy"(){  
     setup:  
     KataMain kataMain = new KataMain()  
     when:  
     Integer successCount = kataMain.getFirstStrategyResult()  
     println "First result = $successCount"  
     then:  
     successCount >= 0 && successCount <= 1000  
   }  
   def "Test Second Strategy"(){  
     setup:  
     KataMain kataMain = new KataMain()  
     when:  
     Integer successCount = kataMain.getSecondStrategyResult()  
     println "Second result = $successCount"  
     then:  
     successCount >= 0 && successCount <= 1000  
   }  
   def "Test All"() {  
     setup:  
     KataMain kataMain = new KataMain()  
     when:  
     Integer winner = kataMain.runScenario()  
     then:  
     winner >= 1 && winner <= 2  
   }  
 }  

build.gradle

 group 'com.bpcs.kata'  
 version '1.0-SNAPSHOT'  
 apply plugin: 'groovy'  
 apply plugin: 'java'  
 sourceCompatibility = 1.8  
 repositories {  
   mavenCentral()  
 }  
 dependencies {  
   compile 'org.codehaus.groovy:groovy-all:2.4.4'  
   testCompile group: 'junit', name: 'junit', version: '4.12'  
   testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'  
 }  

No comments: