Experiential Learning 2: Invention

is an excellent book by Jerry Weinberg. There's no isbn - you can buy it from Leanpub. As usual I'm going to quote from a few pages:
At intervals, keep adding members from the observer corps to each team and observe how each team handles the additional members.
They were… concentrating with their eyes closed (that is, sleeping).
Everything that happens in an exercise is an experience; and every experience provides an opportunity for learning.
Let the students design a slide show of their learnings, and present it to you.
If you were to run this exercise again, with observers chosen before the exercise started, what would you instruct the observers to keep track of? How would you process those data once the exercise was finished?
If you can’t find a regular pattern of some time for self-observation, your leadership development program is in serious trouble.
Have each participant make a "sandwich board" on a large sheet of paper saying:
1) what I'm seeking in teammates
2) what I have to offer my teammates
When standing aside at some distance, we can often see what we couldn’t see up close - that the whole structure is about to collapse, and that additional work will just be wasted work.

the book of tea

is an excellent book by Kakuzo Okakura (isbn 0-486-200070-1). As usual I'm going to quote from a few pages:
One of the cardinal concepts of Oriental thought, from even before the time of Confucius, has been the belief that alternating, diametrically opposed forces govern the universe, like day and night.
Those who cannot feel the littleness of great things in themselves are apt to overlook the greatness of little things in others.
The art of life lies in a constant readjustment to our surroundings.
We must know the whole play in order to properly act our parts; the conception of totality must never be lost in that of the individual.
Truth can be reached only through the comprehension of opposites.
It is much to be regretted that so much of the apparent enthusiasm for art in the present day has no foundation in real feeling.
We classify too much and enjoy too little.

sliming and refactoring and deliberate duplication



Suppose I'm doing the Print-Diamond kata in Ruby:
Given a letter print a diamond starting with 'A' 
with the supplied letter at the widest point. 
For example: print-diamond 'E' prints
    A
   B B
  C   C
 D     D
E       E
 D     D
  C   C
   B B
    A
I start with a test
def test_diamond_A
  assert_equal ['A'], diamond('A')
end
which I pass using
def diamond(widest)
  ['A']
end
I add another test
def test_diamond_B
  assert_equal [' A',
                'B B',
                ' A'], diamond('B')
end
which I pass using
def diamond(widest)
  if widest == 'A'
    return ['A']
  end
  if widest == 'B'
    return [' A',
            'B B',
            ' A']
  end
end
I add one more test
def test_diamond_C
  assert_equal ['  A',
                ' B B',
                'C   C',
                ' B B',
                '  A'], diamond('C')
end
which I pass using
def diamond(widest)
  if widest == 'A'
    return ['A']
  end
  if widest == 'B'
    return [' A',
            'B B',
            ' A']
  end
  if widest == 'C'
    return ['  A',
            ' B B',
            'C   C',
            ' B B',
            '  A']
  end
end
The tests have already proved valuable:
  • I've decided I don't want to actually test printing
  • I've chosen the result format - an array of strings
  • I've chosen not to embed newlines at the end of the strings
  • I've something to refactor against
However, there is no point in carrying on sliming. As the tests get more specific, the code should get more generic. I have three specific tests, but the code is equally specific. I need to generalize the code.

While coding the array of strings for the 'C' case I found myself copying the result for 'B' and modifying that. Specifically, I had to:
  • duplicate the 'B B' string
  • add a space at the start of the ' A' and 'B B' strings
  • add a new middle string 'C C'
This gave me the idea to try a recursive implementation. My first step was to refactor the code to this:
def diamond(widest)
  d = inner_diamond(widest)
  mid = d.length / 2
  d[0..mid-1] + d[mid+1..-1]
end

def inner_diamond(widest)
  if widest == 'A'
    return ['A',
            'A']
  end
  if widest == 'B'
    return [' A',
            'B B',
            'B B',
            ' A']
  end
  if widest == 'C'
    return ['  A',
            ' B B',
            'C   C',
            'C   C',
            ' B B',
            '  A']
  end
end
This looks a promising step towards a recursive solution - to make the implementation of 'C' contain the implementation of 'B' and then add strings only for 'C'. So, remembering what I had to do when copying and modifying, I refactored to this:
def inner_diamond(widest)
  if widest == 'A'
    return ['A',
            'A']
  end
  if widest == 'B'
    return [' A',
            'B B',
            'B B',
            ' A']
  end
  if widest == 'C'
    b = inner_diamond('B')
    upper,lower = split(b.map{ |s| ' ' + s })
    c = widest + '   ' + widest
    return upper + [c,c] + lower
  end
end

def split(array)
  mid = array.length / 2
  [ array[0..mid-1], array[mid..-1] ]
end
From here I verified the recursive solution works for 'B' as well:
def inner_diamond(widest)
  if widest == 'A'
    return ['A',
            'A']
  end
  if widest == 'B'
    a = inner_diamond('A')
    upper,lower = split(a.map{ |s| ' ' + s })
    b = widest + ' ' + widest
    return upper + [b,b] + lower
  end
  if widest == 'C'
    b = inner_diamond('B')
    upper,lower = split(b.map{ |s| ' ' + s })
    c = widest + '   ' + widest
    return upper + [c,c] + lower
  end
end
Now I worked on generalizing the use of the hard-coded argument to inner_diamond() and the hard-coded number of spaces:
def inner_diamond(widest)
  if widest == 'A'
    return ['A','A']
  end
  if widest == 'B'
    a = inner_diamond(previous(widest))
    upper,lower = split(a.map{ |s| ' ' + s })
    n = (widest.ord - 'A'.ord) * 2 - 1
    b = widest + (' ' * n) + widest
    return upper + [b,b] + lower
  end
  if widest == 'C'
    b = inner_diamond(previous(widest))
    upper,lower = split(b.map{ |s| ' ' + s })
    n = (widest.ord - 'A'.ord) * 2 - 1
    c = widest + (' ' * n) + widest
    return upper + [c,c] + lower
  end
end

def previous(letter)
  (letter.ord - 1).chr
end
Now I collapsed the duplicated specific code to its more generic form:
def inner_diamond(widest)
  if widest == 'A'
    return ['A','A']
  else
    a = inner_diamond(previous(widest))
    upper,lower = split(a.map{ |s| ' ' + s })
    n = (widest.ord - 'A'.ord) * 2 - 1
    b = widest + (' ' * n) + widest
    return upper + [b,b] + lower
  end
end
Finally some renaming:
def inner_diamond(widest)
  if widest == 'A'
    return ['A','A']
  else
    inner = inner_diamond(previous(widest))
    upper,lower = split(inner.map{ |s| ' ' + s })
    n = (widest.ord - 'A'.ord) * 2 - 1
    middle = widest + (' ' * n) + widest
    return upper + [middle,middle] + lower
  end
end
To summarise:
  • When sliming I try to think ahead and choose tests which allow me to unslime the slime.
  • If I have slimed 3 times, my next step should be to unslime rather than adding a 4th gob of slime.
  • My first unsliming step is often deliberate duplication, done in a way that allows me to collapse the duplication.


Experiential Learning 1: Beginning

is an excellent book by Jerry Weinberg. There's no isbn - you can buy it from Leanpub. As usual I'm going to quote from a few pages:
This is a very simple exercise, but it will get people talking about process improvement.
If there is no provocation, there is no learning. ... We must first put our students into a provocative environment. We must encourage them to experiment - to play with the materials in that environment.
In many traditional courses, the only significant observation made is pass/fail on the test.
By the mathematical properties of averaging, almost all teams will perform "better" than almost all individuals - simply because they are more average. … All we are measuring is how much closer an average answer is likely to be to another average answer which is essentially a tautology.
People are more ready to accept your facts than your opinions, so be very careful to separate observation (news) from interpretation and significance.
Be patient with silence. Usually a long silence comes just before a breakthrough idea.
Different people on each team learned different things from the same trial of the same exercise. This is characteristic of well designed and well led experiential exercises.
Leaders are not in complete control of what participants are going to learn. Are you going to be able to live with that?
The strongest way to achieve safety in experiential exercises is by making clear that every exercise is optional. If someone doesn't want to participate, they are always free to step aside without explaining their reasons, and without any attempts to persuade or cajole. If someone wishes to opt out, then the learning leader should invite them to take an observer role, but they may opt out of that, too.
You can't just pop experiential exercises at people regardless of the context, so pay special attention to the very first exercise you do with a group.
There must be a bazillion ways to form teams, but we've tried only half of them.

The principles of product development flow

is an excellent book by Donald Reinersten (isbn 978-1-935401-00-1). As usual I'm going to quote from a few pages:
Operating a product development process near full utilisation is an economic disaster.
When we emphasise flow, we focus on queues rather than timelines.
Almost any specialist can become a queue.
We grow queues much faster than we can shrink them.
When queues are large, it is very hard to create urgency.
Queues amplify variability. Moving from 75 to 95% utilisation increases variability by 25 times.
Sequential phase-gate processes have inherently large batch transfers.
Large batches encourage even larger batches.
Reducing batch size is usually the single most effective way to reduce queues.
Companies inevitably feel they can computerise this whiteboard, however, they almost always create a more elegant but less useful system.
The speed of feedback is at least two orders of magnitude more important to product developers than manufacturers.
The human effect of fast feedback loops are regenerative. Fast feedback gives people a sense of control; they use it, see results, and this further reinforces their sense of control.
Homeostasis is the tendency of a system to maintain its current state.
In product development, our problem is virtually never motionless engineers. It is almost always motionless work products.
Opportunities get smaller with time, and obstacles get larger.
The scarcest resource is always time.
To align behaviours reward people for the work of others.
It has been said that one barbarian could defeat one Roman soldier in combat, but that 1,000 Roman soldiers could always defeat 1,000 barbarians.
The Marines, and all other elite organisations, maintain continuity in their organisational units.


Olve's uncle

Yesterday, whilst stuck in a traffic jam, my great friend Olve Maudal told me a wonderful story about his uncle. Olve's uncle lived in the country. He didn't much care for the city. He felt the city folk were always in a rush. Often too busy to remember basic courtesy. One day he had to go into the city so he got into his old Volvo and set off. In the middle of the city the old Volvo stalled. He tried restarting it several times with no luck. Then the driver behind him starting tooting his horn. Olve's uncle calmly opened his door, got out his car, and walked towards the tooting driver. Olve's uncle explained to the driver that his old Volvo wouldn't start, and, offering him the car key, asked him if he knew how to get it started. The driver immediately, and in a friendly manner, said yes and took the key. As the tooting driver started walking towards the old Volvo, Olve's uncle said, "I'll wait here and toot your horn for you".

practising

Last week I attended a two day course on the banks of the River Tay learning to speycast using a 15 foot double handed rod. I learned it quickly and effectively, for three reasons:
  • First, I was taught by a great tutor, Gary Scott. Not only is Gary a world champion spey caster he is also a really great teacher and a thoroughly nice bloke to boot.
  • Second, I had almost no previous experience of fly-fishing for trout. This was very helpful as I had no bad habits to unlearn. In contrast, some of the other anglers who attended Gary's course were experienced trout fly-fishers. Gary would correct some particular movement and for a few casts they would do the new movement - but then Gary would move along to help the next angler and soon they dropped back into muscle-memory-mode and had lost the new movement.
  • Third, when I started Gary made sure I did not have a hook tied to the end of the line. This would have been plain dangerous before I had at least some control. Having a small piece of wool instead of the hook meant I was not thinking about catching a salmon; I was thinking only about improving my casting technique. In contrast the other anglers on the course started with a hook and their efforts to improve their casting were inevitably watered down by their desire to catch a salmon.


red-green starts with red

Suppose I've written a test and got it passing...
@Test
public void yahtzee_full_house_scores_25() {
  assertEquals(25, 
    new YahtzeeScorer(4,4,3,4,3).fullHouse());
}
After refactoring I write my next test...
@Test
public void yahtzee_not_full_house_scores_0() {
  assertEquals(0, 
    new YahtzeeScorer(4,4,4,4,4).fullHouse());
}
And this passes first time. That is, it passes without failing first. One of the reasons for failing first is to be sure the test is actually running. For example, suppose I'd forgetten to write @Test and didn't notice that the JUnit output wasn't showing one more test passing. Ooops. A question I've been asked on several occasions is whether, in this situation, you should change the code or the tests to force an initial red. For example, my first version of the yahtzee_not_full_house_scores_0 could have been this, (where I've deliberately used 42 instead of 0 simply because 42 is a good example of a number that is not 0):
@Test
public void yahtzee_not_full_house_scores_0() {
  assertEquals(42, 
    new YahtzeeScorer(4,4,4,4,4).fullHouse());
}
I see it fail, and then change the 42 to 0 and see it pass. This works, and I have done this. Perhaps you have too. If so, do you agree that it doesn't feel right? I've learned that when something doesn't feel right my subconscious is trying to tell me something. I've learned that when I've got two choices it's often a good idea to look for a third. And there is a third way. I could instead start with this:
@Test
public void yahtzee_not_full_house_scores_0() {
  fail("RED-FIRST");
}
And when I've seen it fail, I delete the fail() and write the actual code I want to write:
@Test
public void yahtzee_not_full_house_scores_0() {
  assertEquals(0, 
    new YahtzeeScorer(4,4,4,4,4).fullHouse());
}
Or, as an alternative, I could start with this:
@Test
public void yahtzee_not_full_house_scores_0() {
  fail("RED-FIRST");
  assertEquals(0, 
    new YahtzeeScorer(4,4,4,4,4).fullHouse());
}
and when I've seen it fail I simply delete the fail() line.

Either way I get the mechanics of seeing the fail out of the way and then I write the code as a separate thing. By un-asking the question I avoid having to decide what to temporarily fiddle with - the code or the tests. I get to write the code I actually want to write. All the time.

yahtzee cyber-dojo refactoring




Several people have asked for refactoring sessions in cyber-dojo. The idea is that instead of starting from the minimal start code and working towards a solution, you start from finished (but poor) solution and work on refactoring instead. So here are four deliberately poor solutions to Yahtzee in Java, C#, C++, and Python just itching to be refactored!
These buttons create Individual Practices:
These buttons create Group Practices:

when it shocked us

A while ago I set myself a goal of reading all four volumes of Jerry Weinberg's Quality Software Management twice. I'm 7/8 through and this morning some of volume 4, Anticipating Change, really spoke to me.

Figure 10-9 extends the simple view of a feedback controller, to show that the environment of each level contains both the levels above and below.
In a feedback control system, the roles of system and controller are symmetrical. It's only our perception that determines which is controller and which is controllee, which is high and which is low.
In all the cases I have examined, the error correction mechanism seems to start at the lowest possible level and slowly works its way higher. [Donald Norman. Psychology of Everyday Things].
Norman is talking about correcting errors in handling everyday things, like being unable to insert the car key, trying again, trying the key upside down, trying another key, wiggling the handle, trying another door, and finally realizing that it's the wrong car. But the same way of progressing through levels is commonly found in correcting organizational faults.
Maturity tends to mean reliability.
In terms of the Feedback Control Model, every one of the more than a hundred failures I've studied closely can be attributed to poor management.
Software is invisible only when we have not developed the correct engineering measurements. A hundred years ago electricity was considered invisible. We only knew of its existence when it shocked us.
Software often lacks sufficient stability to make meaningful measurements.


the cat in the hat

I've blogged before about how Patrick and I often watch The Princess Bride. Patrick has Asperger's syndrome and loves to watch the same film many times. Many many times. It would be easy for me to not watch a repeat-showing with Patrick on the grounds I'd find it boring. I think that not that many years ago that's exactly what I would have done. But something Jerry Weinberg wrote (in Quality Software Management volume 1 Systems Thinking, page 111) struck a chord with me. He said:

It's not the event that counts, it's your reaction to the event.

So now I challenge myself to watch the film with Patrick (for the umpteenth time) and change the way I react so I don't find it boring. For example, I can specifically look for scenes or lines that I can relate to software development. I've found there will always be some. Here are some from The Cat in The Hat:

For refactoring and continuous-improvement (the song at the end after they've tidied up the mess they made)

I've got to admit it's getting better.

For attitude (after they make the cupcakes which taste disgusting)

They're horrible. Who want's some?

For gratitude (again at the end)

This day has been amazing. Thank you.

For pair-programming! (when they're in the car)

Two people can't drive at the same time.

For testing! (when they're in the car again)

I think there's something wrong with your brakes. When was the last time you had them checked?

For quick and dirty (which is really slow-and-dirty)

There's no way to explain this to mom.

For QWAN, Quality Without A Name, when they're riding the Mrs KWAN roller-coaster:

Please keep your hands and feet in the KWAN at all times.

It's amazing how what you see changes when you change how you look.

big cyber-dojo in Beijing


Mike Long (@meekrosoft) ran a Cyber-Dojo for 32 people in Beijing yesterday. Way to go Mike :-)

cyber-dojo in the cloud

http://cyber-dojo.com is now properly hosted in the Amazon cloud :-) I'll leave the old server, 81.31.112.23 (in my house, under the stairs, with the flaky internet connection - I live in a rural area) up for a few days, but will be gone soon.

A few people have been asking if they could donate something towards running Cyber-Dojo. Now that I'm paying for the hosting that seems a sensible idea, so I've added a donate button. Thanks.

Emil's cyber-dojo




I ran a Mastering Agile Practice tutorial with Kevlin Henney at the recent Scandinavian Developer Conference in Sweden. Emil Jönsson attended and liked Cyber-Dojo so much he ran one at his company afterwards. He says:

Just wanted to let you now that the Cyber-Dojo session I organised at work last week went really well. We did the leap year kata in Java and we were eight in total, so we ended up working in four pairs. It was fun to hear all the interesting discussions taking place and it was perfect how we could jump between the different solutions of the pairs afterwards when talking about the code. The feedback after the dojo was all positive and my colleagues liked the Cyber-Dojo way of practicing.

I hope this will become a reoccurring event. Thanks for the excellent work creating the Cyber-Dojo.

It's my pleasure Emil.


ACCU conference charity bookstall



A big thank you to the excellent people attending the ACCU 2012 conference who raised £645.77 plus a €10 note plus a very small silver coin of unknown origin! This will be split equally between Paws with a Cause and The Autism Trust.

building a rails 3 turnkey cyber-dojo server




NOTE: The cyber-dojo github repo now uses ruby(2.1.3), Rails(4) and docker(1+).
I don't think these instructions will work anymore.
Instead see setting up your own cyber-dojo docker server

I've been working on building a cyber-dojo VirtualBox Turnkey image that uses rails 3 and ruby 1.9.3 on top of the Turnkey Rails app. I figured the steps involved might be useful for someone so here they are. You can also download them as a shell file here .

First I removed the existing ruby
# cd ~
# apt-get purge ruby-enterprise
Then install libyaml
# cd ~
# wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
# tar xzf yaml-0.1.4.tar.gz
# cd yaml-0.1.4
# ./configure
# make
# make install
Then install the version of Ruby I want (this takes quite a while)
# cd ~
# wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p125.tar.gz
# tar xzf ruby-1.9.3-p125.tar.gz
# cd ruby-1.9.3-p125
# ./configure --disable-install-doc
# make
# make install
Then pull the rails3 Cyber-Dojo source (hit return when it asks for a password). I got some utf-ascii conversion warnings which don't seem to matter. When asked if I wanted to overwrite an executable I responded [y]es. This too takes quite a while.
# cd /var/www
# git clone https://JonJagger@github.com/JonJagger/cyberdojo
# chown -R www-data cyberdojo
# chgrp -R www-data cyberdojo
# cd cyberdojo
# gem update --system
# gem update --no-rdoc
# gem install bundle --no-ri --no-rdoc
# bundle install
Then setup apache
# cd /etc/apache2/sites-enabled
# sed s/railsapp/cyberdojo/ <railsapp >cyberdojo
# rm railsapp
# cd /etc/apache2/sites-available
# sed s/railsapp/cyberdojo/ <railsapp >cyberdojo
# rm railsapp
# cd /etc/apache2/conf
# sed s/railsapp/cyberdojo/ <railsapp.conf >cyberdojo.conf
# rm railsapp.conf
Then setup passenger (it takes quite a while), and edit /etc/apache2/conf.d/passenger as directed by the output
# cd ~
# apt-get update
# apt-get install libcurl4-openssl-dev
# cd /var/www/cyberdojo
# gem install passenger --no-ri --no-rdoc
# passenger-install-apache2-module
Then
# cd /var/www/cyberdojo
# service apache2 restart
And viola, cyber-dojo was up. Saving to a .ova file creates a 418MB file. This will give you C and C++ (gcc 4.4.5), Perl (5.10.1), Python (2.6.6), Ruby (1.9.3). If you want to upgrade any of these or use any of the other languages you'll need to install their compilers and unit test frameworks.

cyber-dojo Skillsmatter podcast

I had the pleasure of running a Cyber-Dojo at Skillsmatter's 2 day Progressive Java tutorial last week. The session was video'd and is available here.

requiem for C head cam

At the ACCU 2012 conference Uncle Bob gave his excellent keynote Requiem for C. Skillsmatter video'd the whole keynote and it will be available soon. As an experiment Uncle Bob gamely agreed to wear a Go Pro 2 head camera whilst giving the keynote! So here, possibly for the first time ever, are a few rough clips of what it's like to give a keynote.





The evolution of useful things


is an excellent book by Henry Petroski (isbn 0-679-74039-2). As usual I'm going to quote from a few pages:
Can any single theory explain the shape of a Western saw, which cuts on the push stroke, as readily as an Eastern one, which cuts on the pull?
A French book of advice to students recognised the implicit threat involved in using a weapon at the table, and instructed its readers to place the sharp edge of their knife facing towards themselves… Such actions, coupled with the growing widespread use of forks, gave the table knife its now familiar blunt-tipped blade.
Round chopsticks would tend to twist in the fingers and roll off the table, and so squaring one end eliminated two annoyances in what is certainly a brilliant design.
The stories associated with knives, forks, and spoons also illustrate well how interrelated are technology and culture generally.
Luxury, rather than necessity, is the mother of invention.
The very properties of the material that make it possible to be shaped into a useful object also limit its use.
Engineering is invention institutionalised, and engineers engaged in design are inventors who are daily looking for ways to overcome the limitations of what already works.
It is not the form follows function but, rather, that the form of one thing follows from the failure of another thing to function as we would like.
When sewn into a garment, a piece of thread can be thought of as a continuous and flexible ghost of a needle.
It is 3M's policy (and that of other enlightened companies) to allow its engineers to spend a certain percentage of their work time on projects of their own choosing, a practice known as "bootlegging".

Consilience


is an excellent book by Edward O. Wilson (isbn 0-349-11112-X). As usual I'm going to quote from a few pages:
The first step to wisdom, as the Chinese say, is getting things by their right names.
The cost of scientific advance is the humbling recognition that reality was not constructed to be easily grasped by the human mind.
Analysis and synthesis, he [Goethe] liked to say, should be alternated as naturally as breathing in and breathing out.
Nothing in science - nothing in life, for that matter - makes sense without theory.
Complexity is what interests scientists in the end, not simplicity.
Consilience among the biological sciences is based on a thorough understanding of scale in time and space.
Complexity theory can be defined as the search for algorithms used in nature that display common features across many levels of organisation.
In a system containing perfect internal order, such as a crystal, there can be no further change.
The brain is a machine assembled not to understand itself, but to survive.
The biologist S. J. Singer has drily expressed the matter thus: I link, therefore I am.
No example of bias-free mental development has yet been discovered.