nothing new ever works

Jerry Weinberg's latest blog is a guest entry from me!
It's an email I sent detailing a personal example of his New Law...

Hi Jerry,

I just had a moment of enlightenment about the New Law I wanted to share with you... I was giving Patrick, my son, some calpol (liquid paracetamol - he's ill off school today). The bottle had a new plastic widget in the top. With the bottle there was a new small syringe with a new plunger. This was a new design - instead of simply pouring the calpol onto a teaspoon you clearly had to fill up the syringe. Try as I might I could not get the syringe through the hole in the plastic widget in the neck of the bottle. So was it The New Law - Nothing new ever works?

My beautiful wife Natalie came to my rescue. It did work and she showed me how.

I just re-read The New Law from your book. I noticed that all the examples, the coffee maker, the pills, the car-battery, the car, the hospital procedure were examples where the new thing was genuinely not working. But in my case the new thing WAS working. It was ME that was not working!

From this I have realized that

1) It's easy to think the emphasis in "Nothing New Ever Works" is on the word "new" but it's equally on the word "works"!

2) Something being new is a relationship

3) Something working is a relationship

4) When I say "it's not working" what I always mean is "I can't get it working"

Also, it might give some insight into the question you pose at the end of the New Law...

"Everyone knows that new things never work."

"Then why is everyone obsessed with changing everything for something new?"

"If you answer that, you'll have something worth writing about"

Well, when things go wrong we can look for the cause outside of ourselves, or we can look for the cause inside of ourselves. But, looking for the cause inside of ourselves would mean WE had failed. Which is unthinkable. Therefore the cause must be outside of ourselves. Viz, if it's a choice between changing the world around us, or changing the world inside us, outside wins. And that's one reason why we create new things!

Cheers

Jon


Alice in wonderland

is an excellent book by Lewis Carroll. As usual I'm going to quote from a few pages:
It was labelled ORANGE MARMALADE, but to her great disappointment it was empty.
Down, down, down. Would the fall never come to an end?
She generally gave herself very good advice (though she very seldom followed it).
Alice felt so desparate that she was ready to ask help of anyone.
Why, said the Dodo, the best way to explain it is to do it.
It sounded like an excellent plan, no doubt, and very neatly and simply arranged; the only difficulty was, that she had not the smallest idea how to set about it.
Would you tell me, please, which way I ought to go from here?
That depends a good deal on where you want to get to, said the Cat.
I don't much care where - said Alice.
Then it doesn't matter which you go, said the Cat.
Have some wine, the March Hare said in an encouraging tone.
Alice looked all round the table, but there was nothing on it but tea.
I don't see any wine, she remarked.
There isn't any, said the March Hare.
The chief difficulty Alice found at first was in managing her flamingo.
Alice soon came to the conclusion that it was a very difficult game indeed.
Take off your hat, the King said to the Hatter.
It isn't mine, said the Hatter.
Stolen, the King exclaimed, to the jury, who instantly made a memorandum of the fact.
I keep them to sell, the Hatter added as an explanation: I've none of my own. I'm a hatter.
Begin at the beginning, the King said gravely, and go on till you come to the end: then stop.

viking laws


Several years ago I bought this postcard from Olso airport.

be brave and aggressive

  • be direct
  • grab all opportunities
  • use varying methods of attack
  • be versatile and agile
  • attack one target at a time
  • don't plan everything in detail
  • use top quality weapons

be prepared

  • keep weapons in good shape
  • keep in shape
  • find good battle comrades
  • agree on important points
  • choose one chief

be a good merchant

  • find out what the market needs
  • do not promise what you can't deliver
  • do not demand overpayment
  • arrange things so you can return

keep the camp in order

  • keep things tidy and organized
  • arrange enjoyable activities which strengthen the group
  • make sure everyone does useful work
  • consult all members of the group for advice


kanban push-me-pull-you

I've been thinking some more about kanban and visualization. A while ago I blogged about my security-scan kanban idea of introducing proper physical kanban onto the board. Instead of writing a work-in-progress limit of 5 at the top of a column you introduce 5 physical "empty-tray" kanbans. Different columns use different coloured kanban. For example, here's a very simple kanban board with a Wibbling limit of 4 yellow trays and a Fubaring limit of 5 red trays. The stories are in blue and must always be in a tray.


I mentioned how this allows genuine pulling. For example, the Fubarers can signal they're ready to pull a story from the Wibblers by moving an empty red kanban tray into the Wibbling column.


I said that the Wibblers could simply move a done blue story from its yellow kanban into an empty red kanban. Something about that bothered me and I think I now know what it is. Once again it's about visualization. What bothers me is that there is no representation of whether a blue story is done until it's moved into an empty kanban. There is no visual display of whether a blue story actually is "in-progress" and being worked on, or whether its "in-queue" and waiting for an empty red kanban. That feels wrong.

More recently, I blogged about about the common pattern of splitting each column; one for ongoing, one for done, like this. Something about the done column didn't feel quite right either.


So here's what I'm thinking. As well as moving empty-kanbans upstream to signal a pull, you can also move full-kanbans downstream to signal a push. For example, when a Wibbler finishes a blue story they don't leave it in their Wibbling column, waiting for a red kanban pull signal, they move it, still in its yellow kanban, into the Fubaring column, like this:



Ideally, the departing full-yellow-kanban will be just-in-time to meet an arriving empty-red-kanban between the columns...



...and the blue-story will flow from the full-yellow-kanban into the empty-red-kanban:



On the other hand, if the Wibblers are working much faster than the Fubarers then the Fubarer's column will fill up with full-kanban push-requests:



As the Fubarer's column fills up with full-kanban push-requests from upstream it's likely it will also be filling up with empty-kanbans pull-requests from downstream (in green say):


Push-me-pull-you is very visual:
  • There's one representation of flow ; thin columns with kanban of one colour only.
  • There's a different representation of lack of flow ; fat columns filling up (at the bottleneck) with two or three different coloured kanbans.
Push-me-pull-you points to problems:
  • If the yellow Wibblers work faster than the downstream red Fubarers, the Wibbler's full yellow kanban get stuck downstream in the Fubarer's column, inviting the Wibblers to help the Fubarers.
  • If the red Fubarers work faster than the upstream yellow Wibblers, the Fubarer's empty red kanban get stuck upstream in the Wibbler's column, inviting the Fubarers to help the Wibblers.
Push-me-pull-you has helped me understand:
  • pull does not preclude push; you can have push and pull.
  • wip-limits are not limited to pull systems; wip-limits would help in push systems too.


multi-tasking

Many years ago, in a taxi, in Athens, I watched with a mixture of amazement and fear as my driver freed up both hands by steering with his elbows. It was quite an experience!

Multi-tasking is a bad idea when you're doing tasks requiring "immersion". After being interrupted it takes you a long time to get back to where you were. One of the least talked about reasons why pair-programming can be so effective is that a pair seems to be much more resilient to interruptions than an individual. In other words, yet again, pair-programming is partly about programming, but it's mostly about the pairing.

Jerry Weinberg observed that if you have two task to choose from you don't in fact have two tasks to choose from. You have three. Your third task is deciding which of the other two tasks you should tackle!

Recently, on a train, a man sitting opposite me was reading The Telegraph. An article on the front page about multi-tasking caught my eye. It quoted some research by Professor David Strayer from the University of Utah. It said multi-taskers often end up juggling activities not because they are good at it, but because they are easily distracted and cannot concentrate on the job at hand. And in contrast, the most efficient multi-tasker is the person least likely to do so because they can focus on one thing at a time. The implication is that someone who claims to be good at multi-tasking probably isn't!

Zen and the art of motorcycle maintenance

is an excellent book by Robert Pirsig (isbn 978-0-099-32261-0). As usual I'm going to quote from a few pages:
By far the greatest part of his [the mechanic's] work is careful observation and precise thinking.
Care and Quality are internal and external aspects of the same thing. A person who sees Quality and feels it as he works is a person who cares. A person who cares about what he sees and does is a person who's bound to have some characteristics of Quality.
As Poincaré would have said, there are an infinite number of facts about the motorcycle, and the right ones don't just dance up and introduce themselves. The right facts, the ones we really need, are not only passive, they are damned elusive and we're not going to just sit back and "observe" them. We're going to have to be in there looking for them or we're going to be here a long time. Forever. As Poincaré pointed out, there must be a subliminal choice of what facts we observe. The difference between a good mechanic and a bad one, like the difference between a good mathematician and a bad one, is precisely this ability to select the good facts from the bad ones on the basis of quality. He has to care!
That's really why he got so upset that day when he couldn't get his engine started. It was an intrusion into his reality.
The range of human knowledge today is so great that we're all specialists and the distance between specializations has become so great that anyone who seeks to wander freely among them almost has to forego closeness with the people around him.
This isn't really a small town. People are moving too fast and too independently of one another.
I've a set of instructions at home which open up great realms for the improvement of technical writing. They begin, 'Assembly of Japanese bicycle require great peace of mind.'
Peace of mind isn't at all superficial really, I expound. It's the whole thing. That which produces it is good maintenance; that which disturbs it is poor maintenance. What we call workability of the machine is just an objectification of this peace of mind. The ultimate test's always your own serenity. If you don't have this when you start and maintain it while you're working you're likely to build your personal problems right into the machine itself.
There is an infinity of hypotheses. The more you look the more you see.
It's the sides of the mountain which sustain life, not the top.
It is not the facts but the relation of things that results in the universal harmony that is the sole objective reality.
Always take the old part with you to prevent getting a wrong part.
Impatience is close to boredom but always results from one cause: an underestimation of the amount of time the job will take.
Mu means "no thing". Like "Quality" it points outside the process of dualistic discrimination. Mu simply says, "No class; not one; not zero, not yes, not no." It states that the context of the question is such that a yes or no answer is an error and should not be given. "Unask the question" is what it says. Mu becomes appropriate when the context of the question becomes too small for the truth of the answer.
Apart from bad tools, bad surroundings are a major gumption trap.
Religion isn't invented by man. Men are invented by religion.
When handling precision parts that are stuck or difficult to manipulate, a person with mechanic's feel will avoid damaging the surfaces and work with his tools on the nonprecision surfaces of the same part whenever possible. If he must work on the surfaces themselves, he'll always use softer surfaces to work with them. ... Handle precision parts gently.
Want to know how to paint a perfect painting? It's easy. Make yourself perfect and then just paint naturally. That's the way all experts do it.
The real cycle you're working on is a cycle called yourself.


Scrum buses

Some buses are busy busing people. Picking up passengers at stops. Not stopping when there are no passengers. Busy bus-y.

Suppose bus 5 picks up slightly more passengers than normal. This delays it slightly. It takes slightly longer to reach the next stop. This means it again picks up slightly more passengers than normal. Bus 5 gets further and further behind bus 6 ahead of it.

Do we understand the bus system? We have a cause and an effect which seem plausible. I've learned that saying something is a cause and something is an effect is fraught with danger. With a deeper understanding, what is cause and what is effect start to blur together. Saying this is a cause and that is an effect is a clumsy way of saying they are part of the same system.

Back to the slightly delayed bus 5. Behind bus 5 is bus 4. Bus 5's delay means bus 4 picks up slightly fewer passengers than normal. Bus 4 gets closer and closer to bus 5 ahead of it.

Now it's less clear bus 5 is causing the problem. Perhaps bus 5 picked up more passengers than usual because bus 6 ahead of it was catching up bus 7 ahead of it. And bus 7 is really the cause. But two ahead of bus 7 is bus 9. Maybe bus 9 in the cause? Or maybe we need to look at the whole system.

You wait ages for a bus and then two or more turn up at the same time! The buses are queueing just like the passengers at the stops! A trip that should take 15 minutes takes 45 minutes.

Queues will form when processes with variability are loaded to high levels of utilization without constraint.

What does the Bus "route" master do? They constrain the system.
  • Buses depart at evenly-spaced fixed-duration intervals.
  • If a bus is ready to go but it's not its time yet then it waits.
  • They limit the number of people getting on the bus.
  • They do something if people are not getting off the bus!


Feller's walk

Image you have a fair coin, and you flip it 1000 times, adding 1 or subtracting 1 each time you flip either a head or a tail respectively. How do you think the cumulative total will behave as the number of coin flips progresses from 1 to 1000?

Don Reinersten poses this question in his excellent book the Principles of product development FLOW. Don read it in William Feller's book An introduction to probability theory and its applications.

Feller says most people, even trained mathematicians and statisticians, assume that the cumulative total will hover around zero. It doesn't. It tends to drift further and further above or below zero. In fact, there is only a 50% chance the cumulative total will cross the zero line in the second 500 flips! Intrigued by this I've written a short javascript program to simulate 5000 walks and plot two graphs (using the jQuery flot library). You can grab my code from github if you're interested.

The first graph plots the cumulative total on a single walk.

  • Y-axis is cumulative total, marked -40,-20,0,20,40
  • X-axis is walk step, marked 0,100,200,...,900,1000
The walk plotted above is fairly typical - it drifts down and ends with a cumulative total of about Y=-42 at X=1000.

The second graph plots the probabilities for the cumulative total after N flips at
  • N=10 (orange line)
  • N=30 (blue line)
  • N=100 (red line)
  • N=1000 (green line)
  • Y-axis is probability, marked 0.00, 0.05, 0.10, 0.15, 0.20, 0.25
  • X-axis is cumulative total, marked -125,-100,-75,-50,-25,0,25,50,75,100,125
The most probable value for the cumulative total is always zero, but this probability gets lower and lower as N increases. After 1000 flips of a fair coin, there's only about a 1 in 50 chance the cumulative total will be zero. I find that pretty amazing. Without constraints variance will accumulate. As Don says

over time queues will randomly spin out of control ... You cannot rely on randomness to correct the problems that randomness creates.


kanban musing


Here's a typical kanban board; three vertical sections, each with a work-in-progress wip-limit, each split into two sections; Ongoing work on the left, Done work on the right. I've been thinking about the Done columns. Specifically, the fact that they are labelled Done. You see, Analysis's Done is Development's Backlog. And Development's Done is Acceptance's Backlog. So none of the Done's are really done. Not done-done. Why are they labelled Done? Why not Backlog? Or donelog? The labelling seems to reflect a push mentality. I wonder whether there is a better way to draw and label them. One that places equal weight on removing items from the queue. One that would help to suggest a more connected process. Perhaps draw it between Development and Acceptance but inside neither?

I've also been pondering the label "wip-limit". In the picture above, Development has a wip-limit of 3. That strikes me as a bit odd. Development's limit of 3 is really a combination of a work-in-progress-limit for its left-half Ongoing column, and a work-not-in-progress-limit for its right-half Done column. Since Development's right-half Done column is also Acceptance's Backlog why does Acceptance not have a say on that part of the limit?

Even the word itself "wip" conjures an image of frenetic activity. A fast moving, whip cracking wip. Can't we have another word for the limit on the work that is not in progress? One that conjures an image of stillness? Any ideas? After all, as Don Reinersten says

making activities more efficient is much less important than eliminating inactivity


non violent communcation

is an excellent book by Marshall Rosenberg (isbn 978-1892005038). As usual I'm going to quote from a few pages:
Observing without evaluating is the highest form of human intelligence.
NVC is a process language that discourages static generalizations; instead, evaluations are to be based on observations specific to time and context.
In the sentence, "I feel I didn't get a fair deal," the words I feel could be more accurately replaced with I think.
When the faculties are empty, then the whole being listens.
Intellectual understanding blocks empathy.
I had read research indicating a lack of agreement among psychiatrists and psychologists regarding these terms. The reports concluded that diagnoses of patients in mental hospitals depended more upon the school the psychiatrists had attended than the characteristics of the patients themselves.
When we have a judgemental dialogue going on within, we become alienated from what we are needing and cannot then act to meet those needs. Depression is indicative of a state of alienation from our own needs.
Studies in labor-management negotiations demonstrate that the time required to reach conflict resolution is cut in half when each negotiator agrees, before responding, to accurately repeat what the previous speaker had said.
Don't just do something, stand there.
When we focus on clarifying what is being observed, felt, and needed rather than on diagnosing and judging, we discover the depth of our own compassion.

Thinking fast and slow

is an excellent book by Daniel Kahneman (isbn 978-0-141-03357-0). As usual I'm going to quote from a few pages:
The accurate intuition of experts are better explained by the effects of prolonged practice than by heuristics.
It is the mark of effortful activities that they interfere with each other.
It is easier to recognize other people's mistakes than our own.
A sentence is more easily understood if it describes what an agent does than if it describes what something is, what properties it has.
You will find in the changing size of your pupils a faithful record of how hard you worked.
Cognitive strain is affected by both the current level of effort and the presence of unmet demands.
This quality of pastness is an illusion. The truth is, as Jacoby and many followers have shown, that the name David Stenbill will look more familiar when you see it because you will see it more clearly.
I find this astonishing. A sense of cognitive ease is apparantly generated by a very faint signal from the associative machine, which "knows" that the three words are coherent (share an association) long before the association is retrieved.
Do the good feelings actually lead to intuitions of coherence? Yes, they do.
An important principle of skills training: rewards for improved performance work better than punishment of mistakes.
Professional golfers putt more accurately for par than for a birdie.
A single cockroach will completely wreck the appeal of a bowl of cherries, but a cherry will do nothing at all for a bowl of cockroaches. [Paul Rozin]
Our brains are not designed to reward generosity as reliably as they punish mistakes.
In addition to improving the emotional quality of life, the deliberate avoidance of exposure to short-term outcomes improves the quality of both decisions and outcomes.


Poker hands in Ruby

John Cleary (@TheRealBifter) is doing a nice project - The 12 TDD's of Xmas. Day 11 was Poker Hands. I did it in Ruby. Here's the code from traffic-light 116.

Tests first:
require './card'
require './hand'
require 'test/unit'

class TestUntitled < Test::Unit::TestCase

  def test_start
    hand = Hand.new("2H 4S 4C 2D 4H")
    assert_equal Card.new('2',:hearts),   hand[0]
    assert_equal Card.new('4',:spades),   hand[1]
    assert_equal Card.new('4',:clubs),    hand[2]
    assert_equal Card.new('2',:diamonds), hand[3]
    assert_equal Card.new('4',:hearts),   hand[4]
  end

  def test_card_has_pips_and_suit_set_on_creation
    card = Card.new('2',:hearts)
    assert_equal '2', card.pips
    assert_equal :hearts, card.suit
    card = Card.new('T',:hearts)
    assert_equal 'T', card.pips
    assert_equal :hearts, card.suit
    card = Card.new('J',:hearts)
    assert_equal 'J', card.pips
    assert_equal :hearts, card.suit
    card = Card.new('Q',:hearts)
    assert_equal 'Q', card.pips
    assert_equal :hearts, card.suit
    card = Card.new('K',:hearts)
    assert_equal 'K', card.pips
    assert_equal :hearts, card.suit
    card = Card.new('A',:hearts)
    assert_equal 'A', card.pips
    assert_equal :hearts, card.suit
  end

  def test_hand_ranked_three_of_a_kind
    assert_equal :three_of_a_kind, Hand.new("2H 4S 4C AD 4H").rank
  end

  def test_hand_ranked_one_pair
    assert_equal :one_pair, Hand.new("2H 4S 5C JD 4H").rank
  end

  def test_hand_ranked_two_pairs
    assert_equal :two_pairs, Hand.new("2H 4S 5C 2D 4H").rank
  end

  def test_hand_ranked_flush
    assert_equal :flush, Hand.new("2H 4H 6H 8H TH").rank
  end

  def test_hand_ranked_straight
    assert_equal :straight, Hand.new("2H 3C 4H 5H 6H").rank
  end

  def test_hand_ranked_full_house
    assert_equal :full_house, Hand.new("2H 4S 4C 2D 4H").rank
  end

  def test_hand_ranked_four_of_a_kind
    assert_equal :four_of_a_kind, Hand.new("2H 4S 4C 4D 4H").rank
  end

  def test_hand_ranked_straight_flush
    assert_equal :straight_flush, Hand.new("2H 4H 3H 5H 6H").rank
  end

  def test_hand_ranked_high_card
    assert_equal :high_card, Hand.new("2C 3H 4S 8C AH").rank
  end

  def test_full_house_beats_flush
    black = Hand.new("2H 4S 4C 2D 4H")    
    white = Hand.new("2S 8S AS QS 3S")
    assert_equal 1, black <=> white
  end

  def test_higher_card_wins_if_equal_rank
    black = Hand.new("2H 3D 5S 9C KD")
    assert_equal :high_card, black.rank
    white = Hand.new("2C 3H 4S 8C AH")
    assert_equal :high_card, white.rank
    assert_equal -1, black <=> white
  end

  def test_equal_hands
    black = Hand.new("2H 3D 5S 9C KD")
    assert_equal :high_card, black.rank
    white = Hand.new("2D 3H 5C 9S KH")
    assert_equal :high_card, white.rank
    assert_equal 0, black <=> white
  end

end
Code second:
class Hand

  def initialize(cards)
    @cards = 
      cards.gsub(/\s+/, "")
           .scan(/.{2}/)
           .map{|ch| Card.new(ch[0],suit(ch[1]))}
  end

  def [](n)
    return @cards[n]
  end

  def rank
    return :straight_flush if straight? && flush?
    return :flush          if flush?
    return :straight       if straight?

    pip_tallies = pip_counts.sort.reverse
    return {
      [4,1] => :four_of_a_kind,
      [3,2] => :full_house,
      [3,1] => :three_of_a_kind,
      [2,2] => :two_pairs,
      [2,1] => :one_pair,
      [1,1] => :high_card
    }[pip_tallies[0..1]]
  end

  def <=>(other)
    keys <=> other.keys
  end

  def keys
    [ranking,pip_counts]
  end

private

  def ranking
    ranks.index(rank)
  end

  def ranks
    [
      :high_card,
      :pair,
      :two_pairs,
      :three_of_a_kind,
      :straight,
      :flush, 
      :full_house,
      :four_of_a_kind,
      :straight_flush
    ]
  end

  def pip_counts
    "23456789TJQKA"
      .chars
      .collect {|pips| pip_count(pips)}
  end

  def pip_count(pips)
    @cards.count{|card| card.pips == pips}
  end

  def pip_flags
    pip_counts.map{|n| n > 0 ? 'T' : 'F'}.join
  end

  def straight?
    pip_flags.include? 'TTTTT'
  end

  def flush?
    suit_counts.any?{|n| n == 5}
  end

  def suit_counts
    suits.collect{|suit| suit_count(suit)}
  end

  def suits  
    [:clubs,:diamonds,:hearts,:spades]
  end

  def suit_count(suit)
    @cards.count{|card| card.suit == suit}
  end

  def suit(ch)
    return suits["CDHS".index(ch)]
  end

end
class Card

  def initialize(pips,suit)
    @pips,@suit = pips,suit
  end

  def ==(other)
    pips == other.pips && suit == other.suit
  end

  def pips
    @pips
  end

  def suit
    @suit
  end

end
You can replay my entire progression (warts and all) on Cyber-Dojo (naturally).

Galileo once said

You cannot teach a man anything; you can only help him to discover it in himself.


Phone Numbers in Ruby

John Cleary (@TheRealBifter) is doing a nice project - The 12 TDD's of Xmas. Day 10 was the Phone number prefix problem. I did it in Ruby. Here's the code from traffic-light 14.

Tests first (very minimal - I'm a bit pressed for time):
require './consistent'
require 'test/unit'

class TestUntitled < Test::Unit::TestCase

  def test_consistent_phone_list
    list = { 
      'Bob' => '91125426',
      'Alice' => '97625992',
    }
    assert consistent(list)
  end

  def test_inconsistent_phone_list
    list = { 
      'Bob' => '91125426',
      'Alice' => '97625992',
      'Emergency' => '911'
    }
    assert !consistent(list)
  end

end
Code second:
def consistent(list)
  list.values.sort.each_cons(2).none? { |pair| prefix(*pair) }
end

def prefix(lhs,rhs)
  rhs.start_with? lhs
end
The each_cons from the previous problem proved very handy here. As did none? I really feel I'm starting to get the hang of ruby. You can replay my entire progression (warts and all) on Cyber-Dojo (naturally).

Monty Hall in Ruby

John Cleary (@TheRealBifter) is doing a nice project - The 12 TDD's of Xmas. Day 4 was the Monty Hall problem. I did it in Ruby. Here's the code from traffic-light 111.

Tests first:
require './monty_hall'
require 'test/unit'

class TestMontyHall < Test::Unit::TestCase

  def test_either_goat_door_is_opened_when_you_choose_the_car_door
    check_either_goat([:car, :goat, :goat],
      { :chosen_door => 0, 
        :goat_doors  => [1, 2] 
      })
    check_either_goat([:goat, :car, :goat],
      { :chosen_door => 1, 
        :goat_doors  => [0, 2]
      })
    check_either_goat([:goat, :goat, :car],
      { :chosen_door => 2, 
        :goat_doors  => [0, 1]
      })
  end

  def test_other_goat_door_is_opened_when_you_choose_a_goat_door
    prizes = [:car, :goat, :goat]
    check_other_goat(prizes, 
      { :chosen_door  => 1, 
        :opened_door  => 2, 
        :offered_door => 0
      })
    check_other_goat(prizes, 
      { :chosen_door  => 2,  
        :opened_door  => 1, 
        :offered_door => 0 
      })

    prizes = [:goat, :car, :goat]
    check_other_goat(prizes, 
      { :chosen_door  => 0, 
        :opened_door  => 2, 
        :offered_door => 1
      })
    check_other_goat(prizes, 
      { :chosen_door  => 2, 
        :opened_door  => 0, 
        :offered_door => 1
      })

    prizes = [:goat, :goat, :car]
    check_other_goat(prizes, 
      { :chosen_door  => 0, 
        :opened_door  => 1, 
        :offered_door => 2
      })
    check_other_goat(prizes, 
      { :chosen_door  => 1,  
        :opened_door  => 0, 
        :offered_door => 2
      })
  end

  def test_strategy_of_sticking_with_chosen_door
    wins = Array.new(big) { MontyHall.new() }
                .count { |game| game.chosen_door == game.car_door }
    puts "Win car(sticking with chosen door):#{wins}/#{big}"
  end

  def test_strategy_of_switching_to_offered_door
    wins = Array.new(big) { MontyHall.new() }
                .count { |game| game.offered_door == game.car_door }
    puts "Win car(switching to offered door):#{wins}/#{big}"
  end

  #- - - - - - - - - - - - - - - - - - - - - - - -

  def check_either_goat(prizes, expected)
    chosen_door = expected[:chosen_door]
    goat_doors = expected[:goat_doors]
    check_params(prizes, chosen_door, goat_doors[0], goat_doors[1])
    
    goat_counts = [0,0]
    100.times do |n|
      game = MontyHall.new(prizes,chosen_door)

      opened_door = game.opened_door
      offered_door = game.offered_door

      assert_equal chosen_door, game.chosen_door
      assert_equal goat_doors.sort, [opened_door,offered_door].sort
      assert_equal doors, [chosen_door,opened_door,offered_door].sort
      assert_equal :car , prizes[chosen_door]
      assert_equal :goat, prizes[opened_door]
      assert_equal :goat, prizes[offered_door]     

      [0,1].each do |n|
        goat_counts[n] += (offered_door == goat_doors[n] ? 1 : 0)
      end
    end
    [0,1].each { |n| assert goat_counts[n] > 25 }
  end

  def check_other_goat(prizes, expected)
    chosen_door = expected[:chosen_door]
    opened_door = expected[:opened_door]
    offered_door = expected[:offered_door]

    check_params(prizes, chosen_door, opened_door, offered_door)

    game = MontyHall.new(prizes, chosen_door)

    assert_equal  chosen_door, game.chosen_door
    assert_equal  opened_door, game.opened_door
    assert_equal offered_door, game.offered_door

    assert_equal :goat, prizes[ chosen_door]
    assert_equal :goat, prizes[ opened_door]
    assert_equal :car , prizes[offered_door]
  end

  def check_params(prizes, door1, door2, door3)
    assert_equal 3, prizes.length
    prizes.each { |prize| assert [:goat,:car].include? prize }
    assert_equal doors, [door1,door2,door3].sort
  end

  def doors
    [0,1,2]
  end

  def big
    1000
  end

end
Code second:
class MontyHall

  def initialize(prizes = [:goat,:goat,:car].shuffle, 
                 chosen_door = doors.shuffle[0])
    @prizes = prizes
    @chosen_door = chosen_door
    @car_door = prizes.find_index { |prize| prize == :car }
    if prizes[chosen_door] == :car
      @opened_door = goat_doors.shuffle[0] 
    end
    if prizes[chosen_door] == :goat
      @opened_door = (goat_doors - [chosen_door])[0] 
    end
    @offered_door = (doors - [chosen_door, opened_door])[0]
  end

  def chosen_door
    @chosen_door
  end

  def car_door
    @car_door
  end

  def opened_door
    @opened_door
  end

  def offered_door
    @offered_door
  end

private 

  def doors
    [0,1,2]
  end

  def goat_doors
    doors.select { |door| @prizes[door] == :goat }
  end

end
You can replay my entire progression (warts and all) on Cyber-Dojo (naturally).

Bowling Game in Ruby

John Cleary (@TheRealBifter) is doing a nice project - The 12 TDD's of Xmas. Day 9 was the Bowling Game problem. I did it in Ruby. Here's the code from traffic-light 100.

Tests first:
require './score'
require 'test/unit'

class TestScore < Test::Unit::TestCase

  def test_score_uninteresting_game
    #           7     7     7     7    7 = 35
    #        6     6     6     6     6   = 30
    balls = "51|52|51|52|51|52|51|52|51|52"
    assert_equal 65, score(balls)
  end

  def test_score_all_frames_5_spare
    #           15    15    15    15    15 = 75
    #        15    15    15    15    15    = 75
    balls = "5/|5/|5/|5/|5/|5/|5/|5/|5/|5/|5"
    assert_equal 150, score(balls)
  end

  def test_perfect_score
    #          30  30  30  30  30 = 150
    #        30  30  30  30  30   = 150
    balls = "X|X|X|X|X|X|X|X|X|X|XX"
    assert_equal 300, score(balls)
  end

  def test_10_strikes_then_33
    #          30  30  30  30  16 = 136
    #        30  30  30  30  23   = 143
    balls = "X|X|X|X|X|X|X|X|X|X|33"
    assert_equal 279, score(balls)
  end

  def test_game_with_spare_in_middle_of_strikes
    #          20   30  30  30  30    = 140
    #        25  20   30  30  30      = 135
    balls = "X|X|5/|X|X|X|X|X|X|X|XX" 
    assert_equal 275, score(balls)
  end

  def test_game_with_strike_in_middle_of_spares
    #           15    20   15    13    20  = 83
    #        13    11    20   14    12     = 70
    balls = "2/|3/|5/|1/|X|3/|5/|4/|3/|2/|X"
    assert_equal 153, score(balls)
  end

  def test_game_with_zero_balls
    #           8     7     7     7     7 = 36
    #        6     5     6     6     6    = 29
    balls = "51|62|50|52|51|52|51|52|51|52"
    assert_equal 65, score(balls)
  end

  def test_game_with_dash_as_zero_balls
    #           8     7     7     7     8 = 37
    #        6     5     6     6     6    = 29
    balls = "51|62|5-|52|51|52|51|52|51|62"
    assert_equal 66, score(balls)
  end

end
Code second:
def score(balls)
  frames = (balls).split("|")
  while frames.length != 12
    frames << "0"
  end
  frames.each_cons(3).collect{ |frame| 
    frame_score(frame)
  }.inject(:+)
end

def frame_score(frames)
  if strike? frames[0]
    10 + strike_bonus(frames[1..2])
  elsif spare? frames[0]
    10 + ball_score(frames[1][0]) 
  else
    frames[0].chars.collect{ |ball| 
      ball_score(ball)
    }.inject(:+)
  end
end

def strike_bonus(frames)
  if frames[0] == "XX"
    20
  elsif strike? frames[0]
    10 + ball_score(frames[1][0])
  elsif spare? frames[0]
    10
  else
    ball_score(frames[0][0]) + ball_score(frames[0][1])
  end
end

def ball_score(ball)
  if strike? ball
    10
  else
    ball.to_i
  end
end

def strike?(frame)
  frame == "X"
end

def spare?(frame)
  frame[-1] == "/"
end
It took me a while to realize that each_slice should have been each_cons. You can replay my entire progression (warts and all) on Cyber-Dojo (naturally).

Losing my virginity

is an excellent book by Richard Branson (isbn 978-0-7535-1955-4). As usual I'm going to quote from a few pages:
During January and February 1966, Jonny and I began to talk about how to change the school rules. We were fifteen years old, but we believed that we could make a difference. My parents had brought me up to think that we could change the world, so when I looked at how Stowe was run I felt sure that I could do it better.
Above all, you want to create something you are proud of.
Life in the basement was the kind of all-embracing glorious chaos in which I thrived and have thrived ever since.
Hearing others' stories made me realise how lucky I was in my relationships with my own parents. They had never judged me, and always supported me, always praised the good things rather than criticised the bad things.
Look, she said, I wouldn't lend you the money if I didn't want to. What's money for anyway? It's to make things happen.
I rely far more on gut instinct than researching huge amounts of statistics. This might be because, due to my dyslexia, I distrust numbers, which I feel can be twisted to prove anything.
Another man had to hand over his three-year-old daughter to his nanny and say goodbye to her. I just hugged him. There was nothing else I could do. We both had tears in our eyes. I was a father too.
It was clear that Lord King treated me with a contempt that would rub off on how everyone at British Airways felt they could treat Virgin Atlantic.
Fun is at the core of the way I like to do business and it has been key to everything I've done from the outset. More than any other element, fun is the secret of Virgin's success.
Even though I'm often asked to define my 'business philosophy', I generally won't do so, because I don't believe it can be taught as if it were a recipe.
My vision for Virgin has never been rigid and changes constantly, like the company itself.
Our priorities are the opposite of our large competitors'. Convention dictates that a company should look after its shareholders first, its customers next, and last of all worry about its employees. Virgin does the opposite. For us, our employees matter the most. It just seems common sense to me that, if you start off with a happy, well-motivated workforce, you're much more likely to have happy customers. And in due course the resulting profits will make your shareholders happy.
It is my belief that most 'necessary evils' are far more evil than necessary.
It's just a matter of scale, but first you have to believe you can make it happen.

assert_not_diff

The output of Ruby's Test::Unit::TestCase's
assert_equal(expected, actual) when expected and actual are not the same is often not as useful as it could be. For example:
expected = [1,99,2,3,{:a=>34,:b=>43}]
actual = [1,2,3,4,{:a=>324,:c=>555,:b=>43},5]
assert_equal expected, actual
produces:
<[1, 99, 2, 3, {:a=>34, :b=>43}]> expected but was
<[1, 2, 3, 4, {:a=>324, :c=>555, :b=>43}, 5]>.
For large objects which differ only slightly the output that tells you where they differ quickly gets lost in the mass of output telling you where they don't.

Perhaps what's happened here is a sort of Primitive Obsession.
It's as though assert_equal assumes it will only ever be called with primitives.

So I put together a little bit of code to help out. The simplest solution I can think of uses json and diff, so I thought I'd call it assert_not_diff
require 'json'
require 'Tempfile'

def assert_not_diff(lhs,rhs)
  if lhs != rhs
    puts `diff -y #{file_for lhs} #{file_for rhs}`
  end
end

def file_for(obj)
  exp = Tempfile.new("bk", "/tmp").open
  exp.write(JSON.pretty_generate(obj))
  exp.close
  exp.path
end

expected = [1,99,2,3,{:a=>34,:b=>43}]
actual = [1,2,3,4,{:a=>324,:c=>555,:b=>43},5]
assert_not_diff expected, actual
This produces:
[                  [
  1,                 1,
  99,            <
  2,                 2,
  3,                 3,
                 >   4,
  {                  {
    "a": 34,     |     "a": 324,
                 >     "c": 555,
    "b": 43            "b": 43
  }              |   },
                 >   5
]                  ]
Which I think is a lot more useful.
Hope this proves useful to someone!

smart swarm

is an excellent book by Peter Miller (isbn 978-0-00-738297-2). As usual I'm going to quote from a few pages:
As successful foragers return to the nest with seeds, they're met at the nest entrace by foragers waiting in reserve. This contact stimulates the inactive ants to go out. Foragers normally don't come back until they find something. So the faster the foragers return, the faster other ants go out, enabling the colony to tune its work force to the probability of finding food.
Instead of attempting to outsmart the desert environment, the ants, in a sense, were matching its complexity with their own.
Instead of trying to keep fine-tuning a system so it will work better and better, maybe what we really ought to be looking for is a rigourous way of saying, okay, that's good enough. [Deborah Gordon]
If a scout bee was impressed by another scout's dance, she might fly to the box being advertised and conduct her own inspection, which could last as long as an hour. But she would never blindly follow another scout's opinion by dancing for a site she hadn't visited.
J. Scott Turner considers the mound's function as a respiratory system so essential that the termites couldn't live without it. In a sense, he argues, the mound is almost a living part of the colony.
If individuals in a group are prompted to make small changes to a shared structure that inspires others to improve it even further, the structure becomes an active player in the creative process.
Unlike our systems, which are tuned for efficiency, the termites' systems have been tuned for robustness, which they demonstrate by building mounds that are constantly self-healing.
What really made the lights go on was the realization that termites don't pay attention to the environment itself but to changes in the environment.
Not only does this complicated structure represent an indirect collaboration among millions of individuals, it also embodies a kind of ongoing conversation between the colony and the world outside. The mound might look like a structure, but it's better thought of as a process.
We should think of it [the termite mound] as a dynamic system that balances forces both inside and outside its walls to create the right environment for the termites.
When you feel like you belong to something, it gives you so much more freedom and so much more energy that might otherwise be used up in anxiety, to do other things.
On January 12, 2006, several hundred thousand pilgrims had gathered in a dusty tent city at Mina, three miles east of Mecca...
By noon... about a half-million or more pilgrims filled the Jamarat plaza in front of the bridge... The pressure inside the crowd was crushing... More than an hour later, victims were piled up seven layers deep: 363 men and women were dead.
"Those in charge need to remember the root cause of the problem: too many people trying to get through too small a space. The ingress rate at the bridge was 135,000 per hour. The thoughput rate of the pillars was only 100,000 an hour. You can't put a pint into a half-pint jug." [Keith Still]

the life of brian

is an excellent screenplay by Monty Python (isbn 0-413-74130-3). As usual I'm going to quote from a few pages:

Why aren't women allowed to go to stonings, Mum?
Because it's written, that's why.

Jaguar's ear lobes. Wolf nipple chips. Gem 'em while they're hot. They're lovely. Dromedary pretzels, only half a dinar. Tuscany fried bat.

The People's Front of Judea fucking gets things done!

What's this then? 'Romanes Eunt Domus'?
It says 'Romans go home'.
No it doesn't. What's the Latin for Romans? Come on … come on

And what have they ever given us in return?
The aqueduct?

Oh … I'll give you nineteen then.
No, no. Do it properly.
What?
Haggle properly. This isn't worth nineteen.
But you just said it was worth twenty.

Eighteen?
No, no, no. You go to fourteen now.
Fourteen.
Fourteen, are you joking?

Siblings!! Let us not be disheartened. One total catastrophe like this is just the beginning!

What is the secret?
Leave me alone.
Yes! Tell us the secret!
What is the secret?
is is the secret of Eternal Life?

Look … you've got it all wrong. You don't need to follow me. You don't need to follow anybody. You've got to think for yourselves. You're all individuals.
Yes, we're all individuals.
You're all different.
Yes, we are all different.

Always look on the bright side of life.


Perfect Software and other illusions about testing

is the title of an excellent book by Jerry Weinberg. As usual I'm going to quote from a few pages:
Testing a system is a process of gathering information with the intent that the information could be used for some purpose.
Without a process that includes regular technical reviews, no project will rise above mediocrity, no matter how good its machine-testing process.
At least half your testing costs can be cut before anybody ever runs a test, if only your systems are designed with testability in mind.
"We absolutely need this software in place twenty-four weeks from tomorrow. We need two weeks to staff up and get approvals. Then we'll need four weeks for requirements, four weeks for architecture. four weeks for design, and eight weeks for coding. That adds up to twenty-two weeks, so we'll have two weeks left for testing."
If you have ten kilograms of pure uranium-235 and you add another ten kilograms, you'll have twenty kilograms. But if you do this a few more times, you won't have fifty kilograms, you'll have a nuclear explosion. One plus one doesn't always equal two.
The more bugs you find, the more you're going to find, not the other way around.
The human mind craves meaning. If you feed people a random bit of data, they'll struggle to divine meaning from it - and they'll move from the intake phase to the meaning phase so fast they won't be aware of doing so.
You have to know what you're expecting before you give meaning to a test report, otherwise everything looks or sounds right. That's why I'm a strong advocate of the test-first philosophy, whereby developers write their tests to include expected results before they write a line of code. It's what we did fifty years ago, but the practice was gradually lost when industry trends separated testing from development.
That separation occurred initially because it's psychologically difficult for people to test their own programs. There's still significant risk if you rely on test-first without pair-programming or some other process that casts more than one pair of eyes, and more than one brain, on a program.
If test-first is a good idea, then significance-first is even better. Why? … if you actually perform even an enormous number of tests, you would likely lose the valuable information among all the worthless crud. The number of tests performed should be as small as possible, but no smaller.
"We didn't have any problems until we started testing. We were right on schedule. Testing screwed up everything."
"What the American public wants in the theatre is a tragedy with a happy ending." [William Dean Howells]

Experiential Learning 3: Simulation

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:
Would be writers commonly trap themselves by speaking their stories, rather than writing them.
The essential principle of the fieldstone method is "energy".
In a few days we can raise the participants' level of both creating and reviewing, which are the yin and yang of such creative work.
Really, the possibilities are endless, so there's never an excuse for saying you can't think of an experiential exercise.
If they cannot overcome their feelings that the simulation is "silly", then that is an important perception which we'll want to examine during the invention.
A simulation doesn't have to be "real" to be successful as an experiential learning too. What has to be real the feelings it stimulates in the participants, for feelings are what drive learning.
Paradoxically, realism often interferes directly with learning from a simulation.
Frequently, a VW company will sell a poem without knowing whether they can build it.
"Rules" are frozen solutions. Rules are solutions to yesterday's problem, carried forward to the present, but usually without reference to the problem they were intended to solve. Each rule is really an "if-then" rule, but "if-then" part is seldom stated.
You are not a grader, but a teacher.
Every time you jiggle one of your control points, you're ruining some of the teaching power of the simulation. Why? Because you're simulating a universe in which there are powerful hidden gods who control the world.

surely you're joking Mr Feynman

subtitled 'Adventures of a Curious Character', is an excellent book by Richard Feynman (isbn 978-0-099-17331-1). As usual I'm going to quote from a few pages:
Radio sets were much easier to understand in those days because everything was out in the open. After you took the set apart (it was a big problem to find the right screws), you could see this was a resistor, that's a condenser, here's a this, there's a that; they were all labelled.
I finally fixed it beause I had, and still have, persistence.
They didn't even know what they "knew". I don't know what's the matter with people: they don't learn by understanding; they learn by some other way - by rote, or something. Their knowledge is so fragile.
In this room there were wires strung all over the place! Switches were hanging from the wires, cooling water was dripping from the valves, the room was full of stuff, all out in the open. Tables piled with tools were everywhere; it was the most godawful mess you ever saw. The whole cyclotron was there in one room, and it was complete, absolute chaos!
It reminded me of my lab at home. Nothing at MIT had ever reminded me of my lab at home. I suddenly realized why Princeton was getting results. They were working with the instrument. They built the instrument; they knew where everything was, they knew how everything worked. ... It was wonderful! Because they worked with it. They didn't have to sit in another room and push buttons.
I sat with the physicsts, but after a bit I thought: It would be nice to see what the rest of the world is doing, so I'll sit for a week or two in each of the other groups.
So you must be always jiggling a little bit, testing out which way seems to be the easiest.
One day I was watching a paramecium and I saw something that was not described in the books I got in school - in college, even. These books always simplify things so the world will be more like they want it to be.
I chose to play a thing called a "frigideira" which is a toy frying pan made of metal, about six inches in diameter, with a little metal stick to beat it with. ... I practiced all the time. I'd walk along the beach holding two sticks that I had picked up, getting the twisty motion of the wrists, practicing, practicing, practicing.
One day, shortly before Carnival time, the leader of the samba school said, "OK, we're going to practice marching in the street. ...
It was rush hour in Copacabana, and we were going to march down the middle of Avenida Atlantica.
It said to myself, "Jesus! The boss didn't get a license, he didn't OK it with the police, he didn't do anything. He's decided we're just going to go out."
So we started to go out into the street, and everybody, all around, was excited. Some volunteers from a group of bystanders took a rope and formed a big square around our band, so the pedestrians wouldn't walk through the lines. People started to lean out of the windows. Everybody wanted to hear the new samba music. It was very exciting!
As soon as we started to march, I saw a policeman, way down at the other end of the road. He looked, saw what was happening, and started diverting traffic! Everything was informal. Nobody made any arrangements, but it all worked fine.
One exercise they had invented for loosening us up was to draw without looking at the paper. Don't take your eyes off the model; just look at her and makes the lines on the paper without looking at what you're doing.
One of the guys says, "I can't help it. I have to cheat. I bet everybody's cheating!"
"I'm not cheating!" I say.
"Aw, baloney!" they say.
I finish the exercise and they come over to look at what I had drawn. They found that, indeed, I was NOT cheating; at the very beginning my pencil point had busted, and there was nothing but impressions on the paper.
When I finally got my pencil to work, I tried again. I found that my drawing had a kind of strength - a funny, semi-Picasso-like strength - which appealed to me. The reason I felt good about that drawing was, I knew it was impossible to draw well that way, and therefore it didn't have to be good - and that's really what all the loosening up was all about. I had thought that "loosen up" meant "make sloppy drawings," but it really meant to relax and not worry about how the drawing is going to come out.
When it came time to evaluate the conference at the end, the others told how much they got out of it, how successful it was, and so on. When they asked me, I said, "This conference was worse than a Rorschach test: There's a meaningless inkblot, and the others ask you what you think you see, but when you tell them, they start arguing with you!


nothing new ever works

I'm having a new bathroom put in at the moment. The plumber was here doing some plumbing. Then the tiler was doing some tiling. He proudly mentioned that he had a new van. When he said that I thought of the New Law from Jerry Weinberg's The Secrets of Consulting

Nothing new ever works

Then he says he has to go out to get something. He says he'll only be half an hour. Ninety minutes later he's still not back. For a moment I start to think negative thoughts about the stereotype of an unreliable workman. Then I remember his new van. Sure enough, he turns up a few minutes later and he's fallen foul of the New Law. His new van had got a puncture, and being the first one it had taken him ages to change the wheel.

Buckminster Fuller once said...

If you want to change how someone thinks, give up. You cannot change the way people think. Instead, give people tools that help them do something different.


wip limit

I bumped into a nice example of a wip limit. It's in a Columbo episode called The Conspirators. In it the murderer, a man called Joe Devlin, likes to drink whiskey. He's careful not to like drinking whiskey too much though, so before drinking he uses a diamond (set into a ring) to mark the side of the whiskey bottle. As Devlin makes the mark he says "This far and no farther". Once the level drops to the mark he stops drinking. Thus Devlin is using a WIP limit - a Whiskey In Progress limit.

Ackoff's Best

Ackoff's Best, by Russell Ackoff is an excellent book by (isbn 978-0-471-31634-3). As usual I'm going to quote from a few pages:
Analysis looks into things; synthesis looks out of things … Analysis yields knowledge; synthesis yields understanding … The former enables us to describe; the latter, to explain … In analytic thinking, the thing to be explained is treated as a whole to be taken apart. In synthetic thinking the thing to be explained is treated as part of a containing whole. The former reduces the focus of the investigator; the latter expands it … Synthesis, or putting things together, is the key to systems thinking just as analysis, or taking them apart, was the key to Machine-Age thinking.
The essential properties of a system taken as a whole derive from the interactions of its parts, not their actions taken separately. Therefore, when a system is taken apart it loses its essential properties. Because of this - and this is the critical point - a system is a whole that cannot be understood by analysis.
Organisms and organisations are systems that usually have purposes of their own. However, the parts of an organism (i.e., hearts, lungs, brain) do not have purposes of their own, but the parts of an organisation do … An organisation with purposeful parts almost inevitably generates internal conflict … An organisation is a system whose major deficiencies arise from the ways its parts interact, not from their actions taken separately.
Automation is fundamentally different from mechanisation. Mechanization has to do with the replacement of muscle; automation with the replacement of mind.
The publicly owned company became a corporation (derived from "corpus", meaning "body") and the chief executive became the "head" of the firm.
Development of individuals and corporations is more a matter of learning than earning.
The most variety-decreasing type of social system is one we call a bureaucracy. A bureaucracy is an organisation whose principal objective is to keep people busy doing nothing. … The problem created by people who are busy doing nothing is that they frequently obstruct others who have real work to do. … Bureaucracies obstruct development. … Because bureaucracies tend to be inefficient and obstruct development they invite and encourage corruption.
If you're going to sin, sin against God, not the bureaucracy. God will forgive you but the bureaucracy won't. [Admiral Hyman G. Rickover]
Wisdom is the ability to see the long-run consequences of current actions, the willingness to sacrifice short-run gains for larger long-run benefits, and the ability to control what is controllable and not to fret over what is not … Even the best planning of which we are capable requires at least as much art as it does science … Planning is not an act but a process …
Today's students are over instructed in what they can better do alone: take things and concepts apart; and they are under instructed in what is very difficult to do alone: put what they have learned together into an understanding of the world and their role in it.
Effectiveness is evaluated efficiency. It is efficiency multiplied by value, efficiency for a valued outcome. Intelligence is the ability to increase efficiency; wisdom is the ability to increase effectiveness … Growth does not require an increase in value; development does.
Separation of the relevant information from the irrelevant is a critical part of problem formation … the reasons for wanting to answer a question determines what is the right answer to it.
A wrong solution to the right problem is generally better than the right solution to the wrong problem, because one usually gets feedback that enables one to correct wrong solutions, but not wrong problems. Wrong problems are perpetuated by right solutions to them.
Even those aspects of an organisation's future that are not affected by what it and others do (e.g. the weather) cannot be forecasted well for more than a short period. As in the case of the weather, however, the need to forecast it can be eliminated by bringing it under control, as we do by building structures within which work can proceed whatever the external weather may be.

stuka pilot

is an excellent book by Hans Ulrich Rudel (isbn 978-1908476876). As usual I'm going to quote from a few pages:
He tells me that a large scale offensive is in preparation in my sector... approximately three hundred tanks are to be employed in this operation... The number three hundred flabbergasts me... I reply that I find some difficulty in believing it... He says to me, half in earnest, half in jest: "If I didn't know you, for two pins I would have you put under arrest for saying such a thing. But we will soon find out." He goes to the telephone and is connected with the Chief of the General Staff. "You have just given the Fuhrer the figure of three hundred tanks for operation X." "Yes I did." "I want to know the names of the divisions concerned with their present strength in tanks. I have somebody with me who is well acquainted with the position." ... the Chief of the General Staff has the bad luck to begin with the 14th armoured division. He says it has sixty tanks. Goering can hardly contain himself. "My man reports that the 14th has one!" A lengthy silence at the other end of the line. "When did he leave the front?" "Four days ago." Again silence. Then "Forty tanks are still on their way to the front. The rest are in repair shops on the line of communications, but will certainly reach their units by zero day, so that the figures are correct." He has the same answer for the other divisions. The Reichsmarschall slams down the receiver in a rage. "That is how it is!" The Fuhrer is given a totally false picture based on incorrect data and is surprised when operations do not have the success expected... The South Eastern zone with its network of communications is being incessantly blanketed by the enemy's bomber formations. Who knows how many of those forty tanks, for example, will ever reach the front or when? Who can say if the repair shops will get their spare parts in time and if they will be able to complete their repairs within the specified time?
In ministries and departments, however, mistakes are denied on principle.
Another confirmation of the truth of our old Stuka maxim: "Nothing comes off - except what you have practised."
We have long since ceased to develop practice from theory; we do just the opposite.
The fitters have their hands full, for the aircraft have been heavily damaged by flak. The life of such an aeroplane will always be limited.
Little by little I discover all the tricks. Skill is often the result of getting hurt.
I now see that perfectly plainly. We are alone to possess this knowledge; the responsibility is ours.


the power of pairing

In a previous post I talked about an example where a pair performed better than either individually. Here's another small example that happened to me today.
My very good friend Syver was running a coding dojo in Erlang. A test for the filter exercise looked like this:
odd(Integer) when Integer rem 2 == 1 ->
    true;
odd(_) ->
    false.

filter_test() ->
    ?assertEqual([3, 1], 
      filter(fun(Elem) -> odd(Elem) end, [1, 2, 3, 4])).    
I don't know Erlang at all, so Syver helped me out with this first-cut version:
filter(_, []) ->
    [];
filter(Fun, [Head|Tail]) ->
    filter_helper(Fun(Head), Fun, Head, Tail, []).

filter_helper(true, Fun, TrueElement, [Head|Tail], Result) ->
    filter_helper(Fun(Head), Fun, Head, Tail, [TrueElement|Result]);
filter_helper(true, _, TrueElement, [], Result) ->
    [TrueElement|Result];
filter_helper(false, Fun, _, [Head|Tail], Result) ->
    filter_helper(Fun(Head), Fun, Head, Tail, Result);
filter_helper(false, _, _, [], Result) ->
    Result
I realized Erlang is a lot like Prolog which I knew in the dim and distant past. I stared at the code and after several minutes something about it started nagging me. It was the splitting of the list into it's Head and Tail elements in both filter and filter_helper. I wondered if this duplication could be avoided by making filter_helper call back into filter. After several false attempts I came up with:
filter(_, []) ->
    [];
filter(Fun, [Head|Tail]) ->
    filter_helper(Fun(Head), Fun, Head, Tail).

filter_helper(true, Fun, TrueElement, List) ->
    X = filter(Fun,List),
    [TrueElement|X];
filter_helper(false, Fun, _FalseElement, List) ->
    filter(Fun, List).
Then Syver showed me how the use of X could be collapsed:
filter(_, []) ->
    [];
filter(Fun, [Head|Tail]) ->
    filter_helper(Fun(Head), Fun, Head, Tail).

filter_helper(true, Fun, TrueElement, List) ->
    [TrueElement|filter(Fun, List)];
filter_helper(false, Fun, _FalseElement, List) ->
    filter(Fun, List).
We did some argument renaming:
filter(_, []) ->
    [];
filter(Fun, [Head|Tail]) ->
    filter_helper(Fun(Head), Fun, Head, Tail).

filter_helper(true, Fun, Head, List) ->
    [Head|filter(Fun, List)];
filter_helper(false, Fun, _, List) ->
    filter(Fun, List).
Then Syver noticed that we could pass Head,Tail as a single [Head|Tail] argument:
filter(_, []) ->
    [];
filter(Fun, [Head|Tail]) ->
    filter_helper(Fun(Head), Fun, [Head|Tail]).

filter_helper(true, Fun, [Head|Tail]) ->
    [Head|filter(Fun, [Head|Tail])];
filter_helper(false, Fun, [_|Tail]) ->
    filter(Fun, Tail).
We agreed that filter_helper was better as filter:
filter(_, []) ->
    [];
filter(Fun, [Head|Tail]) ->
    filter(Fun(Head), Fun, [Head|Tail]).

filter(true, Fun, [Head|Tail]) ->
    [Head|filter(Fun, [Head|Tail])];
filter(false, Fun, [_|Tail]) ->
    filter(Fun, Tail).
As a final polish Syver refactored to this:
filter(_, []) ->
    [];
filter(Fun, [Head|Tail] = List) ->
    filter(Fun(Head), Fun, List).

filter(true, Fun, [Head|Tail]) ->
    [Head|filter(Fun, [Head|Tail])];
filter(false, Fun, [_|Tail]) ->
    filter(Fun, Tail).
and then, again, after the dojo, thanks to Syver's comment below, to this:
filter(_, []) ->
    [];
filter(Fun, [Head|_] = List) ->
    filter(Fun(Head), Fun, List).

filter(true, Fun, [Head|Tail]) ->
    [Head|filter(Fun, [Head|Tail])];
filter(false, Fun, [_|Tail]) ->
    filter(Fun, Tail).
We agreed that the final version was definitely better than either of us could have come up with individually.