the Importance of Observers 34
This week I spent 2 days with my friend Luke Hohmann getting trained in the use of Innovation Games®. Innovation Games® are a class of so-called serious games that use metaphor and experiential learning situations with an end-result-goal of developing actionable information. (This is my current way of describing them anyway.)
During one of these games I played the role of a facilitator. There were 2 of us facilitating, three “customers” being interviewed and 4 observers.
In my typical consulting role, I am often playing the role of facilitator, but I also have set myself up as an observer at the same time. In the past, this has seemed to make sense given I was the only consultant in the room. This recent experience, however, has really changed how I think about those situations.
In the design of Innovation Games®, the facilitator will typically have a number (1/2 – 1/3) of the participants serve as observers. This has several advantages.- The facilitator can focus on one thing (think single responsibility principle).
- Different observers, different filters (we all have filters all of the time), resulting in more perspectives captured, giving better overall information.
- Given enough observers, you can have individual observers focus on specific things.
- Since the observers are typically from the team (not the consulting company), it reinforces the notion of ownership. The facilitator does not own the results, nor does s/he produce the results.
Why so many observers? Innovation Games® are designed to get access to the things you don’t know you don’t know.
Jerry Weinberg has a simple model of leadership. The MOIJ model.- M is for Motivation
- O is for Organization
- I is for Innovation
- J is for Jiggle
In any situation, take a read. Do you have too much Motivation or too little? Too much? People are frantic and running around like kids just after getting back from a successful night of trick-or-treating. Too little? Everybody is exhausted from yet another all nighter getting ready for a demo because too much focus was placed on adding stuff rather than adding stuff well.
The same idea applies to Organization and Innovation. It is possible to have to much or too little organization and too many or too few ideas.
What happens when none of those first three seem to fit? That’s the Jiggle. You introduce some random element to see if you can get access to something you don’t know you don’t know.
With many observers (e.g. 8-10 in a group of 20), you have the flexibility to have someone look at hand gestures, someone to look at eye contact, someone to listen to change in vocal pitch, etc. That is, you have “typical” observers listening for “important” information and “jiggiling” observers searching form something else. Since you don’t know what you don’t know, doing things with specific kinds of observations might jiggle out information that otherwise you would have missed. It may not, that’s part of the problem of trying to work in the space of you don’t know you don’t know.
In any case, to me this is now one of those “intuitive once you know it” things. In the past, I have worked within my self-perceived constraints of being a single person with 2 roles needing to be filled. Maybe on an intellectual level I understood the value of having observers separate from the facilitator but I did not really grok it.
Now I think I do.
Will I always separate those roles? I don’t believe in context-free best practices, so no. However, will I make this my default preference? I’ll certainly work on it.
More specifically, how am I going to use this new knowledge?
In 2 weeks, Michael Feathers and I are co-teaching an Agile/XP Immersion in Seattle. I’ve already planned to use a few of the Innovation Games® during the class. The big difference, however, is that I’m going to encourage a number of the students to play the role of an observer (listening, recording, saying nothing) to give the customer a chance to own what’s going on rather than being the recipient of a technique.
I’m sure it will take me some time to embody this new approach as my default rather than falling back on the (up until now) current way I’ve been doing things. I’m sure I’ll stumble along the way. But as long as I keep making new mistakes and not repeating the old ones over and over, I’ll be moving in a good direction.
Oh you poor, poor customer 43
I just got back from my third time at the AYE conference and it was another great time. I had a real eye-opening experience on Wednesday and it had to do with how I interact with customers, QA and even developers. Pretty much anybody taking a class or starting a project where I am involved.
- There were two of us playing customers – we did not understand the problem and we did not necessarily agree or understand where we had different interpretations
- We were freshly assigned the role and did not quite understand the details of the problem, our actual responsibility or how to interact with the team (a deficit of tacit knowledge)
- Time was (perceived to be) at a premium
The session/simulation was run with great expertise by Don Gray.
My first really strong observation was during the first meeting with the development group – about 5 minutes in. My co-customer and I had spent a few minutes (literally) reading the requirements and coming to some partial understanding. We met with the “simulated” development team and all hell broke loose (at least in my head).
The development team did some things well.- They tried to think of something small they could do in a time-box.
- They presented us (the customers) with concrete examples of things they could do as first examples.
- They asked concrete questions about the requirements.
- The presented some preliminary examples of possible interpretations.
These are all good things; things I would and have recommend in the past – and will contine to do in the future. And these things did not work for me.
“Playing” the role of customer, when I came to that initial meeting there were many things in flux.- I did not really have much of an idea of a time-box.
- I had looked at the problem in a very different way than the development team, so many of their questions simply did not make any sense to me.
- I felt bombarded by many voices, with many different kinds and levels of content.
- I am a big-time extravert (Jung’s definition) and I’ve been the source of this kind of bombardment.
- I need to catch myself jumping right in on what I think is important and instead ask what is important to the customer (or BA or QA or developer for that matter).
- I probably have overly high expectations of what can be accomplished before the team has started to form, much of that initial interaction lacks the tacit knowledge of actual roles and requirements, such that many things are in flux.
- Or, given a team that has been together, I need to get a grasp on its structure before making change recommendations.
At one point, someone mentioned (in essence) that the “actual” requirements were coming from Don, not me, and essentially wrote me off. That was quite a powerful experience as I felt completely devalued as the customer. I can imagine a business person or QA person feeling the same thing.
I think the biggest one-word summary of the experience for me is empathy.
“After” the simulation (I still had not fully decompressed I think), one person expressed concern over how the customers (me) had not followed “the process”. Wow is all I can say to my experience during that simple, loaded phrase.
In my world of the simulation, there was no process – explicit or implicit. If there was one used by the team, it was tacit and I certainly was not aware of it (in fact, I don’t think there was one “the process” as far as I could tell because I was able to both participate and observe). But regardless of whether there was or was not an explicit or implicit process, it does not matter. Can you imagine someone who is not fully available (a customer), being treated as if they were “not following the process?”, which I inferred to mean “I was being difficult.”
When I’ve thought that, consciously or even subconsciously, I’m certain that belief clouded my interactions with other people and it probably has come across as aggressive/offensive/inconsiderate. Maybe a good mantra to repeat to myself is something like:No matter how it might look, people are trying to be helpful to the best of their ability.I know for certain my intentions during that simulation were good. I was trying to give information to the best of my abilities. I just wasn’t yet aware of the requirements and I did not know how the development team was working. To be treated as if I was sabotaging “the process” was in fact quite offensive to me. I am certain I’ve done that over the years. “The process”, regardless of which process it is, is a model of how to do things. And something I overheard really speaks about this:
All models are wrong; some are useful.
(Notice how that applies to things like TDD, BDD, Scrum, XP, ...?-)
If you have a chance to attend AYE next year (or PSL in May), I’d encourage you to do so. But be prepared to be overwhelmed with personal observations.
C++ Bowling Kata Result 65
I’m teaching a TDD and Refactoring class this week using C++. Since I had not recently wrote the bowling kata in C++, I figured it was about time to do it again.
Unlike the previous Scala version, this one only addresses the happy-path. I do not consider throwing too many balls or scoring too many pins in any frame. However, having just written this in Scala, I’m sure I could do something similar in C++.
I just switched to CppUTest 2.0 and something I noticed is that if you use <vector> or other std-based classes, you need to make sure to include those first before including <CppUTest/TestHarness.h>. This is because CppUTest overloads new and delete, which causes havoc with the std-based classes. No big deal, I just made sure to include that file as the last header (rather than the first, which is what I used to do).
Here are the various files:RunAllTests.cpp
1 2 3 4 5 |
|
BowlingScoreCardTest.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
|
BowlingScoreCard.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
BowlingScoreCard.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
|
I sure do miss refactoring tools!-)
Scala Bowling Kata - still in the middle I suppose 77
"One more roll on a game with 20 rolls and an open 10th frame" should {
20 times { roll(1) }
roll(1) must throwA[IllegalArgumentException]
}
"Two more rolls a game with 10 spares" should {
10 times { spare }
roll(1)
roll(1) must throwA[IllegalArgumentException]
}
"Two marks in the 10th frame should" should {
18 times { roll(1) }
strike
spare
roll(1) must throwA[IllegalArgumentException]
}
On my flight from DFW to SNA, I got these behaviors implemented. The code was pretty ugly!
However, ugly code in hand, passing examples, a slight understanding of some of the problems with my code and a desire to make the BowlingScorer immutable was all I needed to make progress.
I removed the index instance field by rewriting the score method and injecting a tuple into foldLeft (written here using the short-hand notation /:): def scoreAt(frame:Int) =
((0,0) /: (1 to frame)) { (t, _) =>
(t._1 + scoreAtIndex(t._2), t._2 + incrementAt(t._2))
}._1
def onFirstThrow = {
var index = 0
while(index < rolls.length)
if(isStrike(index)) index += 1 else index += 2
index == rolls.length
}
While I am happy I was able to remove the index variable, which was really a parameter being passed around in a field (ugly), I am not happy with this method.
I changed the roll method to return a new instance of a BowlingScorer, making the bowling scorer immutable: def roll(roll:Int) = {
validate(roll)
new BowlingScorer(rolls ++ Array(roll))
}
So I think I’m still somewhere in the middle of working through this code. Again, I’m still learning Scala. I have a lot to learn. I really only barely understand functional programming and, frankly, the Eclipse IDE, while functional, is getting in the way quite a bit. So for a toy example it is OK. Given the choice of this environment or vi and the command line, I’d not pick the former. (I might give the other IDE’s a go, but that’s not really what I’m interested in learning right now.)
So here’s the next version. I plan to work through all of the comments I’ve yet to process from the previous blog posting over the next few days. If you can recommend a better implementation of onFirstThrow, I’d appreciate it.
Other general comments also welcome.
BowlingScorerExampleGroup.scala
package com.om.example
import org.specs._
object BowlingScorerExampleGroup extends SpecificationWithJUnit {
var scorer = new BowlingScorer(Nil);
def roll(value:Int) =
scorer = scorer.roll(value)
def haveAScoreOf(expected:Int) =
scorer.score must_== expected
def strike =
roll(10)
def spare {
roll(5)
roll(5)
}
implicit def intToDo(count: Int) = {
new {
def times(f: => Unit) = {
1 to count foreach { _ => f }
}
}
}
"A Newly Created Bowling Scorer" should {
haveAScoreOf(0)
}
"A game with all 0's" should {
20 times { roll(0) }
haveAScoreOf(0)
}
"A game with all 1's" should {
20 times { roll(1) }
haveAScoreOf(20)
}
"A game with a single spare followed by a 5" should {
spare
roll(5)
haveAScoreOf(20)
}
"A game with all 5's" should {
10 times { spare }
roll(5)
haveAScoreOf(150)
}
"A game with a single strike followed by a 4" should {
strike
roll(4)
haveAScoreOf(18)
}
"A game with a strike, spare then an open frame with two 3's" should {
strike
spare
2 times { roll(3) }
haveAScoreOf(39)
}
"A game with strike, spare then an open frame with two 3's" should {
spare
strike
2 times { roll(3) }
haveAScoreOf(42)
}
"A Dutch 200 game, Spare-Strike" should {
5 times {
spare
strike
}
spare
haveAScoreOf(200)
}
"A Dutch 200 game, Strike-Spare" should {
5 times {
strike
spare
}
strike
haveAScoreOf(200)
}
"A Perfect game" should {
12 times { strike }
haveAScoreOf(300)
}
"The score for each frame of a Perfect game, each frame" should {
12 times { strike }
1 to 10 foreach { frame => scorer.scoreAt(frame) must_== 30 * frame }
}
"An individaul roll of > 10" should {
roll(11) must throwA[IllegalArgumentException]
}
"An iniviaul roll of < 0" should {
roll(-1) must throwA[IllegalArgumentException]
}
"A frame trying to contain more than 10 pins" should {
roll(8)
roll(3) must throwA[IllegalArgumentException]
}
"One more roll on a game with 20 rolls and an open 10th frame" should {
20 times { roll(1) }
roll(1) must throwA[IllegalArgumentException]
}
"Two more rolls a game with 10 spares" should {
10 times { spare }
roll(1)
roll(1) must throwA[IllegalArgumentException]
}
"Two marks in the 10th frame should" should {
18 times { roll(1) }
strike
spare
roll(1) must throwA[IllegalArgumentException]
}
}
BowlingScorer.scala
package com.om.example
class BowlingScorer(rollsSoFar:List[Int]){
val rolls:List[Int] = rollsSoFar
def roll(roll:Int) = {
validate(roll)
new BowlingScorer(rolls ++ Array(roll))
}
def validate(roll:Int) {
if(invalidRoll(roll))
throw new IllegalArgumentException("Individaul rolls must be from 0 .. 10")
if(frameRollTooHigh(roll))
throw new IllegalArgumentException("Total of rolls for frame must not exceed 10");
if(willBeTooManyRolls)
throw new IllegalArgumentException("Game over, no more rolls allowed")
}
def invalidRoll(roll:Int) =
(0 to 10 contains(roll)) == false
def frameRollTooHigh(roll:Int) =
openScoreAt(indexToValidate) + roll > 10
def willBeTooManyRolls =
tenthRolled(indexOf10thFrame) && nextRollTooMany(indexOf10thFrame)
def tenthRolled(tenthIndex:Int) =
tenthIndex < rolls.length
def nextRollTooMany(tenthIndex: Int) =
allowedTenthFrameRolls(tenthIndex) < rollsInTenthFrame(tenthIndex) + 1
def indexOf10thFrame =
(0 /: (1 until 10)) {(c, _) => c + incrementAt(c)}
def allowedTenthFrameRolls(index:Int) =
if(isMark(index)) 3 else 2
def rollsInTenthFrame(index: Int) =
rolls.length - index
def indexToValidate =
if(onFirstThrow) rolls.length else rolls.length - 1
def onFirstThrow = {
var index = 0
while(index < rolls.length)
if(isStrike(index)) index += 1 else index += 2
index == rolls.length
}
def scoreAt(frame:Int) =
((0,0) /: (1 to frame)) { (t, _) =>
(t._1 + scoreAtIndex(t._2), t._2 + incrementAt(t._2))
}._1
def score = scoreAt(10)
def scoreAtIndex(index:Int) =
if(isMark(index)) markScoreAt(index) else openScoreAt(index)
def incrementAt(index:Int) =
if(isStrike(index)) 1 else 2
def isMark(index:Int) =
isStrike(index) || isSpare(index)
def isStrike(index:Int) =
valueAt(index) == 10
def markScoreAt(index:Int) =
sumNext(index, 3)
def isSpare(index:Int) =
openScoreAt(index) == 10 && valueAt(index) != 10
def openScoreAt(index:Int) =
sumNext(index, 2)
def sumNext(index:Int, count:Int) =
(0 /: (index until index+count))(_ + valueAt(_))
def valueAt(index:Int) =
if(rolls.length > index) rolls(index) else 0
}
Scala Bowling Kata - somewhere in the middle... 44
- Installed the Eclipse Scala Plugin
- Installed Scala using Mac Ports
- Figured out how to get those things playing nice (the plugin page pretty much did that, but in a nutshell, add a few jar files to the classpath)
- We don’t need YADT – Yet another damn term
- Trait is a heavily overloaded word
- I like the term BDD better and it fits.
Anyway, one such choice was Specs, which is what I decided to use.
So back to yak shaving:- I added another jar to my classpath in Eclipse
- Then read how to get it running in Eclipse. Not too bad, I suppose.
So now I need to learn Scala. Sure, I’ve used it, but far less than Ruby. So it took me several hours to get specs running along with writing some Scala code to score a game – I’m glad I know the domain at least.
I wanted to make similar behaviors to the ones I wrote for the Ruby version, which I did.
However, unlike the Ruby version, I was curious what would happen if I:- Took an approach similar to Uncle Bob – strikes take one slot in an array
- Added input validation
On the one hand, there are some interesting things I managed to create. On the other hand, I’ve got a bit of a mess. I have a stateful object to avoid passing parameters so that I can write some of the code cleanly. I know I need to add in an intermediate computational object, and I’m going to get to that. However, I wanted to get feedback on what I’ve put out there so far.
Specifically,- What do you think of the (bdd-style) examples from specc?
- What is the correct way to write the Times(20).Do( ...) thing I came up with, there has be a better way?
- For the part of the bowling scoring code that is not stateful (read this as, does not violate the SRP), what do you think of it?
- How would you remove most/all of the state (other than the individual rolls) out of the Bowling scorer class? (Or would you choose to have the roll() method return a new instance of BowlingScorer with the new score recorded?)
- Notice that the class maintains a mini state machine in the form of tracking whether the first ball of he current frame (not tracked) has or has not been thrown. That’s only there to be able to perform input validation. I considered:
- Walking the array
- Going to 2 slots for every frame (making it easy to find the frame)
- Storing a frame object (ok, I didn’t really consider it, but I did think about it)
- The mini state machine
- nextFrameScore uses the index instance variable, and changes it. This both violates command-query separation and demonstrates a violation of the SRP, but it made the scoreAt method look nice.
An interesting side effect is that scoring marks (strikes and spares) uses the same approach, sum up three rolls total.
I know this needs work. What I’ve got works according to its current specification (its examples), so in a sense, that’s a good thing because I’ve already stared experimenting with trying out different solutions. However, I am painfully aware of how unaware I am of Scala at the moment, so your (hopefully gentle) feedback will tell me what I need to learn next.
Looking forward to the virtual beating …
Brett
Here are the two files I’ve created so far (and to be clear, all of the examples pass): BowlingScorerExampleGroup.scalapackage com.om.example
import org.specs._
object BowlingScorerExampleGroup extends SpecificationWithJUnit {
var scorer = new BowlingScorer();
def roll(value:Int) {
scorer.roll(value)
}
def rollMany(rolls:Int, value:Int) {
0.until(rolls).foreach { arg => scorer.roll(value) }
}
def haveAScoreOf(expected:Int) {
scorer.score must_== expected
}
def strike {
roll(10)
}
def spare {
rollMany(2, 5)
}
abstract class IDo {
def Do(block: => Unit)
}
def Times(count:Int): IDo = {
return new IDo {
def Do(block: => Unit) {
1.to(count).foreach( arg => block )
}
}
}
"A Newly Created Bowling Scorer" should {
haveAScoreOf(0)
}
"A game with all 0's" should {
Times(20).Do( roll(0) )
haveAScoreOf(0)
}
"A game with all 1's" should {
Times(20).Do { roll(1) }
haveAScoreOf(20)
}
"A game with a single spare followed by a 5" should {
spare
roll(5)
haveAScoreOf(20)
}
"A game with all 5's" should {
Times(10).Do( spare )
roll(5)
haveAScoreOf(150)
}
"A game with a single strike followed by a 4" should {
strike
roll(4)
haveAScoreOf(18)
}
"A game with a strike, spare then an open frame with two 3's" should {
strike
spare
Times(2).Do( roll(3) )
haveAScoreOf(39)
}
"A game with strike, spare then an open frame with two 3's" should {
spare
strike
Times(2).Do( roll(3) )
haveAScoreOf(42)
}
"A Dutch 200 game, Spare-Strike" should {
Times(5).Do {
spare
strike
}
spare
haveAScoreOf(200)
}
"A Dutch 200 game, Strike-Spare" should {
Times(5).Do {
strike
spare
}
strike
haveAScoreOf(200)
}
"A Perfect game" should {
Times(12).Do( strike )
haveAScoreOf(300)
}
"The score for each frame of a Perfect game, each frame" should {
Times(12).Do( strike )
1.to(10).foreach{ frame => scorer.scoreAt(frame) must_== 30 * frame }
}
"An individaul roll of > 10" should {
roll(11) must throwA[IllegalArgumentException]
}
"An iniviaul roll of < 0" should {
roll(-1) must throwA[IllegalArgumentException]
}
"A frame trying to contain more than 10 pins" should {
roll(8)
roll(3) must throwA[IllegalArgumentException]
}
}
BowlingScorer.scala
package com.om.example
class BowlingScorer {
var rolls:Array[Int] = Array()
var index:Int = 0
var firstBallInFrameThrown: Boolean = false;
def roll(roll:Int) = {
validate(roll)
record(roll)
}
def validate(roll:Int) {
if((0).to(10).contains(roll) == false)
throw new IllegalArgumentException("Individaul rolls must be from 0 .. 10")
if(openScoreAt(indexToValidate) + roll > 10)
throw new IllegalArgumentException("Total of rolls for frame must not exceed 10");
}
def record(roll: Int) {
rolls = rolls ++ Array(roll)
firstBallInFrameThrown = firstBallInFrameThrown == false && roll != 10
}
def indexToValidate = {
if(firstBallInFrameThrown) rolls.length - 1 else rolls.length
}
def scoreAt(frame:Int) = {
1.to(frame).foldLeft(0) { (total, frame) => total + nextFrameScore }
}
def score = {
scoreAt(10)
}
def nextFrameScore = {
var result = 0;
if(isStrike(index)) {
result += markScoreAt(index)
index += 1
} else if(isSpare(index)) {
result += markScoreAt(index);
index += 2
} else {
result += openScoreAt(index);
index += 2
}
result
}
def isStrike(index:Int) = {
valueAt(index) == 10
}
def markScoreAt(index:Int) = {
sumNext(index, 3)
}
def isSpare(index:Int) = {
openScoreAt(index) == 10
}
def openScoreAt(index:Int) = {
sumNext(index, 2)
}
def sumNext(index:Int, count:Int) = {
index.until(index+count).foldLeft(0)(_ + valueAt(_))
}
def valueAt(index:Int) = {
if(rolls.length > index) rolls.apply(index) else 0
}
}
Bowling Game Kata in Ruby 56
I have not really used Ruby much. I’ve written a few tutorials, messed around with RSpec and Test::Unit and even Rails a bit, but I really don’t know Ruby that well. I get Ruby (the MOP, instances, blocks, open classes, ...) but there’s a difference between understanding that stuff and using it day-to-day.
Last night we had a Dojo in Oklahoma City and I wanted to get refreshed with RSpec, so I decided to jump in and do the bowling game kata. I did not follow uncle bob’s lead exactly. For one, I went ahead and stored two throws for each frame. While what he ends up with is a bit shorter, it bothers me a little bit. I’ve also seen people surprised by how bob stores his scores, so in a sense it violates the law of least astonishment.
That’s neither here nor there, I got it working just fine – though handling strikes was a bit more difficult because I decided to store two rolls instead of one (so clearly, there’s no best answer, just ones that suck for different reasons).
After my first go around, I had a single spec with examples all under a single describe (what’s that term they’d use for what the describe expression creates?). I added several examples for partial scores, to make sure I was handling incomplete games correctly. I restructured those a bit and tried to make the names a bit more clear, not sure if I was successful.
In my original version I started with a frame in the score method as a local variable, but it quickly got converted to an index, and the index was mostly passed around after that. The approach was very c-esque. I didn’t like that index all over the place, so I tried to remove it by refactoring. It took several false starts before I bit the bullet and simply duplicated each of the methods, one at a time, using parallel development. The old version using an index, the new one use a 1-based frame number. After I got that working with frames, I removed most of the methods using an index, except for a few.
What follows is the spec file and the ruby class. If you read the names of some of the examples, you might think I used to bowl in league, I did. My average was a paltry 158, my best game ever a 248. Best split I ever picked up? 4, 6, 7, 10.
Comments welcome.
bowling_score_card_spec.rb
require 'bowling_score_card'
describe BowlingScoreCard do
before(:each) do
@bowling_game_scorer = BowlingScoreCard.new
end
def roll value
@bowling_game_scorer.roll value
end
def roll_many count, value
count.times { roll value }
end
def score_should_be value
@bowling_game_scorer.score.should == value
end
it 'should score 0' do
score_should_be 0
end
describe 'Scores for Complete Games' do
it 'should score 0 for an all gutter game' do
roll_many 20, 0
score_should_be 0
end
it 'should show 20 for an all 1 game' do
roll_many 20, 1
score_should_be 20
end
it 'should score game with single spare correctly' do
roll_many 3, 5
roll_many 17, 0
score_should_be 20
end
it 'should score game with single strike correctly' do
roll 10
roll 5
roll 2
roll_many 17, 0
score_should_be 24
end
it 'should score a dutch-200, spare-strike, correclty' do
10.times do
roll_many 2, 5
roll 10
end
roll_many 2, 5
score_should_be 200
end
it 'should score a dutch-200, strike-spare, correctly' do
10.times do
roll 10
roll_many 2, 5
end
roll 10
score_should_be 200
end
it "should score all 5's game as 150" do
roll_many 21, 5
score_should_be 150
end
it 'should score a perfect game correctly' do
roll_many 12, 10
score_should_be 300
end
it 'should not count a 0, 10 roll as a strike' do
roll 0
roll 10
roll_many 18, 1
score_should_be 29
end
end
describe 'Scoring for open games' do
it 'should score just an open frame' do
roll 4
roll 3
score_should_be 7
end
it 'should score just a spare' do
roll_many 2, 5
score_should_be 10
end
it 'should score partial game with spare and following frame only' do
roll_many 3, 5
score_should_be 20
end
it 'should score an opening turkey correctly' do
roll_many 3, 10
score_should_be 60
end
end
describe 'Scoring open game starting with a srike' do
before(:each) do
roll 10
end
it 'should score partial game with only strike' do
score_should_be 10
end
it 'should score partial game with strike and half-open frame' do
roll 4
score_should_be 18
end
it 'should score partial game with strike and open frame' do
roll 3
roll 6
score_should_be 28
end
it 'should score partial game with strike and spare' do
roll 3
roll 7
score_should_be 30
end
end
describe 'Open game starting with two Strikes' do
before(:each) do
roll 10
roll 10
end
it 'should have a score of 30' do
score_should_be 30
end
it 'should score correctly with following non-mark' do
roll 4
score_should_be 42
end
it 'should score correclty with third frame open' do
roll 4
roll 3
score_should_be 48
end
end
end
bowling_score_card.rb
class BowlingScoreCard
def initialize
@rolls = []
end
def roll value
@rolls << value
@rolls << 0 if first_throw_is_strike?
end
def score
(1..10).inject(0) { |score, frame| score += score_for frame }
end
def score_for frame
return strike_score_for frame if is_strike_at? frame
return spare_score_for frame if is_spare_at? frame
open_score_for frame
end
def first_throw_is_strike?
is_first_throw_in_frame? && @rolls.last == 10
end
def is_first_throw_in_frame?
@rolls.length.odd?
end
def open_score_for frame
first_throw_for(frame) + second_throw_for(frame);
end
def spare_score_for frame
open_score_for(frame) + first_throw_for(next_frame(frame))
end
def strike_score_for frame
score = open_score_for(frame) + open_score_for(next_frame(frame))
if is_strike_at? next_frame(frame)
score += first_throw_for(next_frame(next_frame(frame)))
end
score
end
def next_frame frame
frame + 1
end
def is_spare_at? frame
(open_score_for frame) == 10 && is_strike_at?(frame) == false
end
def is_strike_at? frame
first_throw_for(frame) == 10
end
def first_throw_for frame
score_at_throw(index_for(frame))
end
def second_throw_for frame
score_at_throw(index_for(frame) + 1)
end
def index_for frame
(frame - 1) * 2
end
def score_at_throw index
@rolls.length > index ? @rolls[index] : 0
end
end
Notes from the OkC Dojo 2009-09-30 65
Tonight we had a small group of die-hard practitioners working with Ruby and RSpec. We intended to use the Randori style, but it was a small enough group that we were a bit more informal than that.
We tried the Shunting Yard Algorithm again and it worked out fairly well. The level of experience in Ruby was low to moderate (which is why we wanted to get people a chance to practice it) and the RSpec experience was generally low (again, great reason to give it a try).
- Forth
- Operator precedence
- Operator associativity
- L-Values and R-Values
- Directed Acyclic Graphis
- In-fix, pre-fix, post-fix binary tree traversal
- Abstract Syntax Trees (AST)
- The list goes on, I’m a big-time extrovert, so I told Chad to occasionally tell me to shut the heck up
- 1 + 3 becomes 1 3 +
- a = b = 17 becomes a b 17 = =
- 2 + 3 * 5 becomes 2 3 5 * +
- 2 * 3 + 5 becomes 2 3 * 5 +
One typical approach to this problem is to develop an AST from the in-fix representation and then recursively traversing the AST using a recursive post-fix traversal.
What I like about he Shunting Yard Algorithm is it takes a traditionally recursive algorithm (DAG traversal, where a binary tree is a degenerate DAG) and writes it iteratively using it’s own stack (local or instance variable) storage versus using the program stack to store activation records (OK stack frames). Essentially, the local stack is used for pending work.
This is one of those things I think is a useful skill to learn: writing traditionally recursive algorithms using a stack-based approach. This allows you to step through something (think iteration) versus having to do things whole-hog (recursively, with a block (lambda) passed in). In fact, I bought a used algorithm book 20 years ago because it had a second on this subject. And looking over my left shoulder, I just saw that book. Nice.
To illustrate, here’s the AST for the first example:
Since the group had not done a lot with recursive algorithms (at least not recently), we discussed a short hand way to remember the various traversal algorithms using three letters: L, R, P
- L -> Go Left
- R -> Go Right
- P -> Print (or process)
- in-fix, in -> in between -> L P R
- pre-fix, pre, before -> P L R
- post-fix, post, after -> L R P
- in-fix: Go left, you hit the 1, it’s a leaf note so print it, go up to the +, print it, go to the right, you end up with 1 + 3
- post-fix: Go left you hit the 1, it’s a leaf node, print it, go back to the +, since this is post-fix, don’t print yet, go to the right, you get the 3, it’s a leaf node, print it, then finally print the +, giving: 1 3 +
- pre-fix: start at + and print it, then go left, it’s a leaf note, print it, go right, it’s a leaf node, print it, so you get: + 1 3 – which looks like a function call (think operator+(1, 3))
It’s not quite this simple – we actually looked at larger examples – but this gets the essence across. And to move from a tree to a DAG, simply iterate over all children, printing before or after the complete iteration; in-fix doesn’t make as much sense in a general DAG. We also discussed tracking the visited nodes if you’ve got a graph versus an acyclic graph.
After we got a multi-operator expression with same-precedence operators working, e.g., 1 + 3 – 2, which results in: 1 3 + 2 -, we moved on to handling different operator precedence.
Around this time, there was some skepticism that post-fix could represent the same expression as in-fix. This is normal, if you have not seen these kinds of representations. And let’s be frank, how often do most of us deal with these kinds of things? Not often.
Also, there was another question: WHY?
In a nutshell, with a post-fix notation, you do not need parentheses. As soon as an operator is encountered, you can immediately process it rather than waiting until the next token to complete the operator (no look-ahead required). This also led to HP developing a calculator in 1967 (or ‘68) that was < 50 pounds and around USD $5,000 that could add, subtract, multiply and divide, which was huge at the time (with a stack size of 3 – later models went to a stack size of 4, giving us the x, y, z and t registers).
During this rat-hole, we discussed associativity. For example, a = b = c is really (a = (b = c))
That’s because the assignment operator is right-associative. This lead into r-values and l-values.
Anyway, we’re going to meet again next week. Because we (read this as me) were not disciplined in following the Randori style, these side discussions lead to taking a long to fix a problem. We should have “hit the reset button” sooner, so next time around we’re going to add a bit more structure to see what happens:- The driver finishes by writing a new failing test.
- The driver commits the code with the newest failing test (we’ll be using git)
- Change drivers and give him/her some time-box (5 – 10 minutes)
- If, at the end of the current time-box, the current driver has all tests passing, go back to the first bullet in this list.
- If at the end, the same test that was failing is still failing, (fist time only) give them a bit more time.
- However, if any other tests are failing, then we revert back to the last check in and switch drivers.
Here’s an approximation of these rules using yuml.me:
(start)->(Create New Failing Test)->(Commit Work)->(Change Drivers) (Change Drivers)->(Driver Working) (Driver Working)-><d1>[tick]->(Driver Working) <d1>[alarm]->(Check Results)->([All Tests Passing])->(Create New Failing Test) (Check Results)->([Driver Broke Stuff])->(git -reset hard)->(Change Drivers) (Check Results)->([First Time Only and Still Only Newest Test Failing])->(Give Driver A Touch More Time)->(Check Results)
Note that this is not a strict activity diagram, the feature is still in beta, and creating this diagram as I did made the results a bit more readable. Even so, I like this tool so I wanted to throw another example in there (and try out this diagram type I have not used before – at least not with this tool, I’ve created too many activity diagrams). If you’d like to see an accurate activity diagram, post a comment and I’ll draw one in Visio and post it.
Anyway, we’re going to try to move to a weekly informal practice session with either bi-weekly or monthly “formal” meetings. We’ll keep switching out the language and the tools. I’m even tempted to do design sessions – NO CODING?! What?! Why not. Some people still work that way, so it’s good to be able to work in different modes.
If you’re in Oklahoma City, hope to see you. If not, and I’m in your town, I’d be interested in dropping into your dojos!
Improving Testability of GUI Code, an Eample 57
Just finished first draft. More to come, questions/comments appreciated.
http://schuchert.wikispaces.com/tdd.Refactoring.UiExample
Pair with one of us at Agile 2009 18
Dean, Uncle Bob, Michale Feathers and I will be spending time in our Agile 2009 booth working on problems and pairing with volunteers.
If you’d like to join us for some pairing, please stop by.
We’ll give you an autographed “code monkey” for your efforts.
The Daily Scrum Exercise Program 40
Yesterday I was in a chicken in a scrum meeting. I made the observation that the Daily Scrum was called that and not a “Stand-up meeting.”
Standing up is a mechanism for making the meeting fast. Someone mentioned that they actually used a weight in a previous team. You hand to hold the weight while talking.
This logically leads to a workout program. You start with a weight and, as people get used to it, you increase it. Start with 5 pounds, work up to 45. The problem with this is you’ll end up with inconsistent development. You’ll have a bunch of developers with strong, wide upper bodies but weak, pipe-like legs.
So the next logical step is to rotate the exercises used while reporting on what you did, what you’re going to do and roadblocks.
So maybe something like:- Monday, upper body, dumbbells held out in front or to the side (depending on where you need more definition.
- Tuesday, cardio, jog in place, kicking your knees up high.
- Wednesday, lower body, squat with your feet pointing at 45 degrees and legs apart.
- Thursday, cardio, jog in place, kicking your feet into your rear
- Friday, mid section, alternatively lift your knees to the opposite side of your body while twisting to the size of leg you are lifting.
You get the idea. Of course, you’d customize the workouts to at least the team or maybe even the developer.
I’d like to be on that team!