tag:blogger.com,1999:blog-79622176192088009612024-03-06T08:29:57.372+00:00On Food and Coding(Making, learning, hacking.)Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.comBlogger31125tag:blogger.com,1999:blog-7962217619208800961.post-1843385041808346312013-11-10T15:57:00.000+00:002013-11-10T15:57:00.073+00:00ArrivederciAll around the web you can find blogs which were once tended with
care, day-by-day, week-by-week. Then one day ... nothing. You're left
wondering what happened. Did their author literally get hit by a bus? Or what?
<br>
<br>
Rather than leave you in a similar state of puzzlement, I thought
it more polite to sign-off explicitly. I have not (hopefully) been hit
by a bus, but I've become a whole lot busier. I was quite surprised to
see that, according to "wc" anyway, I have this year written
approaching 30,000 words on this blog. But for the foreseeable future,
I'm going to be rather too busy with other things to keep that up.
So I think it's better for now to just stop.
<br>
<br>
I've enjoyed writing these posts, and I've enjoyed the discussions
that they sparked, mostly by email behind the scenes. (Drop me a line
if you have any thoughts about them. I'm sure I'll have time for
that.) I think I understand agile development much better now through
writing about it here. I'm glad I got various ideas about teaching
programming down in black and white.
I was surprised by the popularity of
<a href="http://onfoodandcoding.blogspot.co.uk/2013/06/the-robots-game.html">the
robots game</a>. I was also surprised by how hard it is to write up
recipes that I cook all the time in a form that might work for other people.
<br>
<br>
And I've still got a list of things that I intended to write about
but didn't: thoughts on the difference between programming
languages and programming systems; an "absentee review" and
retrospective on <i>The
Mother of All Demos</i>; a development of Meta-II called "metaphor", which
<a href="https://github.com/stuartwray/metaphor">I've put on
GitHub</a> but not really explained. At the end of the day I think
I have made some progress following up my two initial trains of
thought: that we
could do programming a whole lot better, and that we could learn
something from another group of people who produce things every day,
the people who work in kitchens. But I think there's a lot more to be
said, a lot more to be discovered.
<br>
<br>
So, I hope you enjoy the posts that remain here. (They will probably make more
sense if you start from
<a href="http://onfoodandcoding.blogspot.co.uk/2013/01/start-of-day.html">the
beginning</a>.) I think I'll be back one day to add some more. But I
may be some time ...
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com1tag:blogger.com,1999:blog-7962217619208800961.post-76693021495417907432013-11-03T10:21:00.000+00:002013-11-03T10:21:00.487+00:00"Film Night"Here are videos of some interesting talks. Grab a bag of popcorn
— or more healthily, a bag of pork scratchings — and
settle in to enjoy ...
<br>
<br>
<b>Recent Developments in Deep Learning</b><br>
Geoff Hinton, 30 May 2013<br>
<a href="http://www.youtube.com/watch?v=vShMxxqtDDs">www.youtube.com/watch?v=vShMxxqtDDs</a>
(65 minutes)
<br>
<br>
<iframe width="560" height="315"
src="http://www.youtube.com/v/vShMxxqtDDs?rel=0&fs=1"
frameborder="0"
webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>
<br>
<br>
Neural nets have been around for a long time, but people could not
get them to work as well as they had hoped. The explanation for
this was that learning by backpropagation would never give better
results because:
<br>
<ul>
<li>It required labelled training data.</li>
<li>Learning time was very slow with deep nets.</li>
<li>It got stuck in local optima.</li>
</ul>
Surprisingly, <i>every one of these statements was wrong</i>. Deep
neural nets are now practical, and they can do <i>amazing</i> things.
<br>
<br>
<b>Monads and Gonads</b><br>
Douglas Crockford, 15 January 2013<br>
<a href="http://www.youtube.com/watch?v=b0EF0VTs9Dc">http://www.youtube.com/watch?v=b0EF0VTs9Dc</a>
(49 minutes)
<br>
<br>
<iframe width="560" height="315"
src="http://www.youtube.com/v/b0EF0VTs9Dc?rel=0&fs=1"
frameborder="0"
webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>
<br>
<br>
Yet another monads tutorial? Is it any more comprehensible than the
others? It's certainly more entertaining, if only because Crockford
asserts that you don't need to understand Haskell, you don't need
to understand Category Theory, and if you've got the balls, you don't
even need static types. (As you might expect, he uses Javascript. I
really enjoyed this talk, but I found that I had to re-do his
<a href="https://github.com/douglascrockford/monad/blob/master/monad.js">Javascript</a>
in
<a href="https://github.com/stuartwray/bric-a-brac/blob/master/monads-and-gonads.py">Python</a>
to make sure I had understood it right.)
<br>
<br>
<b>Mission Impossible: Constructing Charles Babbage's Analytical Engine</b><br>
Doron Swade, 8 May 2012<br>
<a href="http://www.youtube.com/watch?v=FFUuN-ZRLz8">http://www.youtube.com/watch?v=FFUuN-ZRLz8</a>
(87 minutes)
<br>
<br>
<iframe width="560" height="315"
src="http://www.youtube.com/v/FFUuN-ZRLz8?rel=0&fs=1"
frameborder="0"
webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>
<br>
<br>
This is longer than the others, but there's really no heavy-lifting in
this talk. Swade outlines the very ambitious
project to complete the design and construction of Charles
Babbage's Analytical Engine. (If you want to support the effort, you
can make a contribution at
<a href="http://plan28.org/">plan28.org</a>.)
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com1tag:blogger.com,1999:blog-7962217619208800961.post-41585414666194033142013-10-27T13:12:00.000+00:002013-10-27T13:12:00.064+00:00Recipe: Chicken EspañolThis recipe was reverse-engineered from a Tesco ready-meal.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">3</td><td>Chicken breasts</td></tr>
<tr><td>2T </td><td>Olive oil</td></tr>
<tr><td>2t </td><td>Paprika</td></tr>
<tr><td>9 slices </td><td>Thinly sliced choritzo<td></tr>
<tr><td>120g </td><td>Cheddar cheese, grated</td></tr>
<tr><td>420g </td><td>Cream cheese</td></tr>
<tr><td> </td><td>Salt</td></tr>
<tr><td> </td><td>Ground pepper</td></tr>
<tr><td> </td></tr>
<tr><td colspan=2>
<i>For the sauce:</i> </td></tr>
<tr><td> </td></tr>
<tr><td>1 </td><td>Onion, finely chopped</td></tr>
<tr><td>2 </td><td>Cloves garlic, crushed</td></tr>
<tr><td>3T </td><td>Olive oil</td></tr>
<tr><td>1 </td><td>Tin of chopped tomatoes (440g)</td></tr>
<tr><td>pinch </td><td>Sage, dried</td></tr>
<tr><td>pinch </td><td>Thyme, dried</td></tr>
<tr><td>pinch </td><td>Oregano, dried</td></tr>
<tr><td>250ml </td><td>Red wine</td></tr>
<tr><td> </td><td>Salt</td></tr>
<tr><td> </td><td>Ground pepper</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
On the day before you want to cook this, first make a sideways slit in
each chicken breast, making a kind of pocket. Then put the chicken
breasts in a plastic bag with the olive oil, paprika and a few grinds
of salt and pepper. Squidge this around until the breasts are all
covered with this marinade then tie the bag and leave it in the fridge
overnight.
<br />
<br />
To make the sauce, fry the onion and garlic in olive oil over a medium
heat until the onion is turning brown. Add the chopped tomato, sage,
thyme and oregano. Then add the red wine. Add salt and pepper to
taste. Cook for around 30 minutes until thickened. (Reduce heat as
necessary. Blend with a hand-blender if you want it to be smoother.)
<br />
<br />
While that is going on, assemble the chicken with its other ingredients.
Each chicken breast cooks in the oven in its own container, which
should be about twice as big as the breast itself. (Replicating in
some sense the original ready-meal experience.) Assemble each
container as follows: first put 100g cream cheese in the
base. On top of that, sprinkle 20g of grated cheddar and a couple of
grinds of salt
and pepper. Now take a breast and into the "pocket", place 40g cream cheese
mixed with 20g grated cheddar.
Place the breast in the container and cover it with 3
slices of choritzo. Place the containers in an oven pre-heated to to
200°C (= gas mark 6 = 400°F) and cook for around 30 minutes.
<br />
<br />
To serve, lift out each breast onto a plate, stir around the creamy
sauce in its container and pour this sauce around the breast. Beside this,
place a similar quantity of the tomato-and-wine sauce. (For a
vegetable, steamed spinach works very well and makes a nice colour
combination.)
<br />
<br />
<b>Discussion</b>
<br />
<br />
You will find that you have too much of the tomato-and-wine sauce: the
above quantity would work for twice as much chicken. However, it's
less fiddly to make a bigger batch. For convenience you can
make the sauce well ahead of time and even freeze it and re-heat
it. Although it's probably not necessary to give each breast its own
little container, I think it probably is necessary to confine the area
over which the creamy sauce can spread, so that it doesn't burn and
the breasts don't dry out.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-29979642902157050822013-10-20T10:06:00.000+01:002013-10-20T10:06:00.418+01:00Democratic Development(This post is another follow-up to
<a href="http://onfoodandcoding.blogspot.com/2013/05/agile-is-antifragile.html">Agile
is Antifragile</a>.)
<br>
<br>
I recently finished
<a href="http://www.amazon.co.uk/dp/1846146631/">The Democracy
Project</a> by David Graeber.
It's an excellent book, in part a personal history of the Occupy Wall
Street movement, and in part an explanation of how to
organise groups and solve problems using the consensus processes of
"direct democracy".
To my surprise, I realised that Graeber's insights can also be
applied to software development. I think these insights explain not
only what Agile development is really trying to do, but also reveal
a cornucopia of organisational techniques that we can
reuse to improve our practice of Agile development.
<br>
<br>
In Agile development, the team is supposed to organise itself —
"horizonally" as Graeber would say — rather than being directed
"vertically" by some manager. But <i>exactly</i> how? Practically
every Agile process mandates short daily meetings, but practically no
Agile process suggests in detail how those meetings should be run, or
exactly how they lead to the team organising itself. What's really
going on here? And why is "horizontal" better than "vertical"? As
Graeber explains, what <i>should</i> be going on is decision making by
consensus:
<br>
<br>
<div style="margin-left: 2em;">
This is how consensus is supposed to work: the group agrees, first, to
some common purpose. This allows the group to look at decision making
as a matter of solving common problems. Seen this way, a diversity of
perspectives, even a radical diversity of perspectives, while it might
cause difficulties, can also be an enormous resource. After all, what
sort of team is more likely to come up with a creative solution to a
problem: a group of people who all see matters somewhat differently,
or a group of people who all see things exactly the same? (Graeber, p203)
</div>
<br>
The reason for adopting consensus in a group is that "horizontal"
decision making produces better decisions.
And the key thing to notice is that the point of every meeting is to
decide what to <i>do</i> next, in order to further the common purpose of the
group. (There can still be some disagreement. In particular, there is
no need to agree on "why". Agreement on "what" is sufficient.)
Graeber goes on to explain:
<br>
<br>
<div style="margin-left: 2em;">
The essence of consensus process is just that everyone should be able
to weigh in equally on a decision, and no one should be bound by a
decision they detest. In practice this might be said to boil down to
four principles:
<ul>
<li> Everyone who feels they have something relevant to say about a
proposal ought to have their perspectives carefully considered.
</li>
<li> Everyone who has strong concerns or objections should have those
concerns or objections taken into account and, if possible,
addressed in the final form of the proposal.
</li>
<li> Anyone who feels a proposal violates the fundamental principle
shared by the group should have the opportunity to veto ("block")
that proposal.
</li>
<li> No one should be forced to go along with a decision to which they
did not assent.
</li>
</ul>
Over the years, different groups or individuals have developed systems
of formal consensus process to ensure these ends. ... In fact there's
an endless variety of ways one might go about making decisions in the
spirit of those four principles. (p211)
</div>
<br>
You might question whether these principles of consensus are really
what Agile development is about. You might say, yes, these principles are
going to lead to better decisions. But the developers are, at the end
of the day, paid staff. If someone in authority decides to impose a
decision, the staff will have to go along with it even if they do detest
it. Maybe so. But I think this actually means that consensus is an excellent
touchstone for whether or not you are really doing Agile development.
I think that at the point when someone outside the team does impose a
decision, at that moment you know that you are no longer doing Agile
development.
<br>
<br>
Graeber goes on to explain a particular widely-used consensus process
for moderately sized groups which grew out of several different
traditions, including Quakerism and radical feminism. I won't go
through it here (it's outlined on p214-215) and as Graeber says, maybe
in a small group that kind of formality is not needed, if everyone
understands the consensus principles. But it does help, I think, to
have concrete processes to consider and use in larger
groups. Everything invented in the world of Agile development seems to
be foreshadowed in the world of "direct democracy". For example, a
"Scrum-of-Scrums" meeting is almost exactly the same as a
"spokescouncil". I think we can learn a lot from these people.
<br>
<br>
(If you want to see what some of these formal processes look like in
more detail, you can find a good overview in
<a href="http://www.starhawk.org/Empowerment_Five-Fold-Path.pdf">The
Five Fold Path of Productive Meetings</a> by Starhawk.)
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-52977028257314412932013-10-13T14:51:00.000+01:002013-10-18T11:54:05.738+01:00Recipe: Spare RibsThis recipe is a bit long-winded, but the results are excellent.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">1.5kg</td><td>Spare ribs</td></tr>
<tr><td> </td></tr>
<tr><td>60g </td><td>lard</td></tr>
<tr><td>1t </td><td>Fennel, ground</td></tr>
<tr><td>1t </td><td>Sichuan pepper, ground</td></tr>
<tr><td>1 </td><td>Cao guo (or "false cardamom")</td></tr>
<tr><td>1 </td><td>Piece of cassia bark (finger-sized)</td></tr>
<tr><td>2 </td><td>Star anise</td></tr>
<tr><td>1 </td><td>Onion, finely chopped</td></tr>
<tr><td>3 </td><td>Cloves garlic, finely chopped</td></tr>
<tr><td>2 </td><td>Slices of root ginger, finely chopped</td></tr>
<tr><td> </td></tr>
<tr><td>500ml </td><td>Water</td></tr>
<tr><td>500ml </td><td>Chicken stock</td></tr>
<tr><td>2t </td><td>Salt</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Bring a large pan of water to the boil. (I use a 10 litre stock-pot.)
Add the ribs, bring the water back to
the boil and leave the ribs to cook for a further 5 minutes. Skim off
the scum which rises to the surface. Lift out the ribs and transfer
them to a slow-cooker.
<br />
<br />
Heat the lard in a frying pan and when hot add the fennel, Sichuan
pepper, cao guo, cassia bark and star anise. After 1 minute add the
onion and cook this until it is brown (around 5 or 10 minutes). Add the
garlic and ginger when the onion starts to turn brown: they don't want
to cook for so long, only a minute or two. When it's ready, tip the
contents of the frying pan into the slow-cooker with the ribs.
<br />
<br />
Use the 500ml of water to deglaze the frying pan, and add this to the
slow-cooker too. Also add the chicken stock and salt to the slow-cooker.
<br />
<br />
Cook at a gentle heat for 3 hours, moving the ribs around every
hour or so.
<br />
<br />
Lift the ribs out onto a roasting tray and strain the liquid from the
slow-cooker through a sieve into a saucepan. Skim off the fat into a
container and keep it to hand. Reduce the sauce on a high heat.
<br />
<br />
Place the roasting tray containing the ribs in an oven pre-heated to
to 200°C (= gas mark 6 = 400°F). After 15 minutes, turn
the ribs and baste them with some of the skimmed fat. Return to the
oven for a further 10 minutes.
<br />
<br />
<b>Discussion</b>
<br />
<br />
This recipe evolved from a combination of other recipes, mostly those of
Kenneth Lo and Ken Hom. It's not clear to me which of the fiddly
details is really necessary to produce an excellent result, and I
haven't gone to the trouble of scientifically experimenting to find
out. I think that frying the spices and then basting the ribs with the
oil at the end must make a significant difference, because that should
transfer fat-soluble flavours more reliably to the final product.
<br />
<br />
As an alternative to putting the salt in with the stock-pot
ingredients, you can instead grind salt over the ribs when
you place them in the roasting tray, and then again on their other
side after you turn them over and baste them with fat.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-31336985653803227842013-10-06T10:43:00.000+01:002013-10-06T10:43:00.578+01:00Time, Value and the dark side of Agile(This post is a follow-up to
<a href="http://onfoodandcoding.blogspot.com/2013/05/agile-is-antifragile.html">Agile
is Antifragile</a>.)
<br>
<br>
What is the best way to organise a group of people who are working
together to make some software? This must be the central question of
software engineering, but we tend to think about it in a very narrow
way. It's rather odd that we are happy to talk about processes,
from Waterfall to Agile, but we don't like to talk about the kind of
practical problems that always arise when people come together to make
something for money.
<br>
<br>
These practical problems are standard fare in business schools and in
some mainstream engineering courses, where they are discussed under
the label Organisation Theory. This in turn has its roots in ideas of
"political economy" that go back over 200 years. Once you understand
these ideas, you can see clearly the cause of some tensions
that arise in software development. So, let's see if I can introduce
you to these ideas — I don't expect in this post to get to the
twentieth-century fashions started by Taylor and Mayo, but we should
be able to cover enough of the nineteenth century ideas to understand
the different feelings people have about Agile and to recognise its
dark side.
<br>
<br>
Where to start? Lisp-hacker Paul Graham, in his essay
<a href="http://www.paulgraham.com/wealth.html"><i>How to Make Wealth</i></a>,
uses the following example to explain how wealth or "value" can be
created by people out of nothing:
<br><br>
<div style="margin-left: 2em;">
"Suppose you own a beat-up old car. Instead of
sitting on your butt next summer, you could spend the time restoring
your car to pristine condition. In doing so you create wealth. The
world is — and you specifically are — one pristine old car the
richer. And not just in some metaphorical way. If you sell your car,
you'll get more for it. In restoring your old car you have made
yourself richer. You haven't made anyone else poorer."
</div>
<br>
Graham uses this parable to explain where the wealth comes from when
people work for themselves in a start-up company: it comes from people
spending their time working on something that's useful to
themselves and to others. This is scarcely a new thought, and although it
would be more traditional to say that "value" comes from
"socially necessary labour time", Graham's explanation of wealth
is essentially the same as the traditional one.
<br>
<br>
However, there is a subtlety here which Graham glosses over, a
subtlety that the old-time political economists were well aware of:
it's the issue of how things change when, rather than working for
yourself, you work for someone else. Following the culinary theme of
this blog, let's invent our own parable, with people working for
someone else in the kitchen of a restaurant.
<br>
<br>
In our make-believe restaurant there is a proprietor who pays the
rent and provides the furniture and most of the kitchen
equipment. Every day the proprietor buys the ingredients for the meals and
pays the wages of the staff. In return, the staff work a certain number
of hours each day, during which they transform those raw ingredients
into the meals which customers buy. Value has certainly been created,
and in return for this newly created value, the customers leave money
after they finish their meals, money which is collected by the
proprietor.
<br>
<br>
The key point here is to notice where the new value comes from: it
comes from the staff who spend their time preparing and cooking the
food. Not from the proprietor, who merely acts as a facilitator or
catalyst by providing the money that makes their work possible. In
Graham's car-refurbishment example, imagine that over the summer you
keep the stripped-down car in your uncle's garage as you do the
work. Does the fact that he is providing the garage mean that he is
directly creating value? No. He is <i>facilitating</i> the creation of
value, but unless he works on the car with you, that's all he is
doing. Without him, <i>you</i> would not be able to create value, but
without you, <i>he</i> would just have an empty garage and there would
be no newly created value, no new wealth.
<br>
<br>
Now we come to the central tension between the proprietor and the
restaurant staff: how does the newly created value get shared out?
Assuming the restaurant makes a profit, then after necessary running
expenses are paid, how much of the remaining money goes to the staff
as wages and how much to the proprietor? They both have a
moral right to that money, since they both have to play their part in
order for the new value to be created. There is an <i>unavoidable</i>
tension here: they are both in the right.
<br>
<br>
From the point of view of the proprietor, wanting to keep more of the
money for themselves,
there is no reason to pay the staff more than the current going-rate.
Look around: what are other restaurants paying? You really don't need
to pay any more than that. If you do, you are certain to find people
knocking on your door asking to work for you, regardless of what fraction
of the takings you keep for yourself and what fraction you distribute
to your staff as wages. And of course, if you pay less than the going
rate, your staff will be tempted away by better offers elsewhere. You
won't actually have a restaurant if all your staff leave.
<br>
<br>
So, the necessary level of wages is determined by the world outside the
restaurant, and provided the proprietor pays those wages, they can
take whatever money is left for themselves. We would naturally expect the
proprietor to try and take more rather than less, and there are
essentially two main methods to achieve this: the proprietor can
either try to increase the productivity of each member of staff
— but still pay the same wages — or they can try to
"de-skill" the work, then hire less-skilled employees who can be paid
less to produce the same value.
<br>
<br>
The classic way to achieve the first of these aims is to
increase productivity by the "division of labour", described by Adam
Smith in the eighteenth century and celebrated today on the back of
the British 20 pound note. The idea is that if particular people
specialise in particular tasks, then they will perform these tasks
quicker than if they continually switch from one thing to
another. This is the essence of the twentieth-century factory, with
jobs reduced to fitting a particular part or tightening a particular
bolt all day. And in the kitchen we do see division of labour to some
extent, with specialists in sauces and deserts, for example.
<br>
<br>
More interestingly, and less often noticed, the division of labour can
also achieve the second of the proprietor's aims: it can change the
nature of the work, de-skilling it and allowing the proprietor to pay
reduced wages, at least to some of the staff. This was well understood
by computing hero Charles
Babbage, who in the 1830s took time off from building the difference
engine to write a treatise on political economy, based on the
observations he made while touring the factories and workshops of
England. In <i>On
the Economy of Machinery and Manufactures</i> (1832), Babbage explains:
<br>
<br>
<div style="margin-left: 2em;">
"... the master manufacturer, by dividing the work to be executed
into different processes, each requiring different degrees of skill or
force, can purchase exactly that precise quantity of both which is
necessary for each process; whereas if the work were executed by one
workman, that person must possess sufficient skill to perform the most
difficult, and sufficient strength to execute the most laborious, of
the operations into which the art is divided." (pp175-176)
</div>
<br>
Babbage took Smith's example of a pin factory and went one better in
his analysis: he detailed the precise division of work and the wages
paid to each of the workers. Some processes in pin manufacture
required both skill and strength; some were so simple that a child could do
them — and since this was Victorian England, a
child <i>did</i> do them. So the highest paid worker on the staff was
a man, at 5s. 4½d. per day; the lowest paid a boy, at
4½d. per day. Which meant, as Harry Braverman points out in <i>Labor and
Monopoly Capital</i> (1974):
<br>
<br>
<div style="margin-left: 2em;">
"If the minimum pay for a craftsman capable of performing all
operations is no more than the highest pay in the above listing, and
if such craftsmen are employed exclusively, then the labour costs of
manufacture would be more than doubled, <i>even if the very same
division of labor were employed and even if the craftsmen produced
the pins at the very same speed as the detail workers</i>." (p80)
[italics in original]
</div>
<br>
This explains why it makes sense for the proprietor of the restaurant
to employ a less skilled person just to peel potatoes and wash the
dishes. The proprietor <i>could</i> hire a skilled cook to do this
work, but it will be cheaper to hire someone less skilled, preferably
the least capable person who can still do those jobs. A skilled cook
would be more expensive because their wage is determined by what they
could earn elsewhere, outside this restaurant, not by what they do
inside. And exactly the same is true of any job done for a wage
— a point which (finally) brings us back to software
development.
<br>
<br>
The proprietor of a software development organisation would obviously
like to benefit in the same way as the proprietor of the
restaurant. They would like to use division of labour, so that they
can reduce their wage-bill by hiring a staff of cheaper, less-skilled
people who can each only just do their own particular jobs. Wherever
people make things in return for wages there will be this
pressure. Software is no different.
<br>
<br>
But there's a catch. In software, is this really possible? Division of
labour makes sense in a mass-production environment, but is software
development such an environment? The proprietors of the software world
clearly <i>wish</i> it were so, but that wish can only come true to
the extent that software development is predictable and routine
— and for the most part it isn't. Just like other forms of
engineering, software development is around 70% repair and
maintenance. Repair is never routine, and in software even the initial
production is often unpredictable, because it is actually mostly design
work, not manufacture in the normal sense. (This is perhaps the main
way in which coding differs from cooking: coding is always about
process creation, cooking is usually about process execution.)
<br>
<br>
However, this practical difficulty doesn't prevent software proprietors
from yearning for predictability. It might even explain their
unreasonable enthusiasm for the Waterfall process over the years. Any
process that promises predictability is also implicitly promising a
less skilled staff and a lower wage-bill. In contrast, an Agile
process is implicitly demanding a more skilled staff and hence a
higher wage-bill — because when you don't believe in prediction
you need a flexible, broadly competent staff who can step-up and do
things that nobody expected. (Of course, to the extent that a
particular project really is unpredictable, the Agile enthusiasts will
be correct when they claim that in the end their way is actually
better, because the less skilled staff would actually take longer and
cost more, if they finished at all.)
<br>
<br>
What started as a tension between the proprietor and the staff over
how to share out the newly created value has turned into a tension
over skills and competence. Developers might naturally be expected to
take a pride in their craft skills, building them up over the years
like any artisan. Perhaps the best expression
of this desire can be found in open-source software, where there is
never any attempt to make the work of creating software routine,
predictable or de-skilled. But the difference here is that open-source
software is written by hackers for <i>themselves</i>, not for a wage.
<br>
<br>
Agile processes promise the developers an opportunity to practice
and grow their craft skills. Agile processes promise the proprietor
nothing but an extra expense, accepted only because predicting the
future is too hard. But some Agile processes implicitly make another promise
to the proprietor, a promise with a dark side. And I think this dark
side is perhaps why some developers are right to be suspicious of the
rhetoric of Agile development.
<br>
<br>
Remember the two ways the proprietor can make more money? I've
been concentrating on de-skilling, but there's also the other way:
the proprietor can keep more money for themselves if they can
increase the
productivity of each member of staff, but still pay the same
wages. With a given division of labour and a given level of skill, the
proprietor can keep more money for themselves if they can get their
staff to
work for longer each day or to work with greater intensity. And when we
deconstruct the terminology used by the most popular Agile process,
Scrum, we find an unfortunate allusion to work at a greater
intensity.
<br>
<br>
For example, the week-by-week cycle of development is called an
"iteration" in practically every other software process, including
Extreme Programming. In
Scrum this time period is called a Sprint. What associations does that
conjure up? Well when you sprint you make an extreme effort to go as
fast as possible, an effort that you can only keep up for a short
time. That's what "sprint" means in everyday life.
<br>
<br>
The list of unimplemented features is just called the "user
stories" in Extreme Programming. In Scrum this list is called the
Backlog. What does "backlog" mean in everyday life? It's the stuff
that you should have already finished. The metaphor is clear: Rush!
Rush! Finish it off quickly! You're late already.
<br>
<br>
Notice that I'm not saying that this is what these names <i>should</i>
mean, or that this is what Scrum practitioners <i>want</i> them to mean,
it's just that words come with everyday meanings, and people will
tend to understand them this way. Imagine if you went to a restaurant
and your waiter told you that the proprietor had introduced a new kind
of organisation in the kitchen, called Scrum. The kitchen staff now have a
"backlog" of dishes to prepare and they are "sprinting" to get them
done. As a customer, I think you would take the metaphor at face
value. Now imagine that you are a customer or a manager of a software
development team using Scrum. Is there any reason for you not to take
the metaphor at face value?
<br>
<br>
So this is the dark side of Agile: the danger that people outside the
development team will hear these metaphors and misunderstand
them — as a
promise of work
at a greater intensity and nothing more. Thinking that, apart from
that, Agile is business as usual. Still yearning to make more money
out of predictability, lower skills and lower wages. Not understanding
that the point of
Agile is <a href="http://onfoodandcoding.blogspot.com/2013/05/agile-is-antifragile.html">to
be Antifragile</a>.
<br>
<br>
It's easy to imagine, if you were a developer in such an environment,
how you would feel, how you would resist.
I think when Agile fails, it must often fail in this way.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-14071257950074780262013-09-29T11:29:00.000+01:002013-09-29T11:29:00.869+01:00Recipe: Tangerine-Peel ChickenThis recipe was originally based on one by Kenneth Lo, which he says
was adapted from the Chengtu Dining Rooms, Chengtu.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">4</td><td>Chicken thighs (say 600g)</td></tr>
<tr><td>1 </td><td>Medium onion, sliced</td></tr>
<tr><td>2 </td><td>Slices root ginger, finely shredded</td></tr>
<tr><td>1t </td><td>Salt</td></tr>
<tr><td>2t </td><td>Light soy sauce</td></tr>
<tr><td>1T </td><td>Rice wine</td></tr>
<tr><td> </td></tr>
<tr><td>200ml </td><td>Oil for semi-deep-frying</td></tr>
<tr><td> </td></tr>
<tr><td colspan=2>
<i>For the sauce:</i> </td></tr>
<tr><td> </td></tr>
<tr><td>1 </td><td>Small red pepper (say 100g), finely shredded</td></tr>
<tr><td>1 </td><td>Dried chilli, finely shredded</td></tr>
<tr><td>2T </td><td>Dried tangerine peel, broken into small
pieces</td></tr>
<tr><td>2T </td><td>Oil for frying</td></tr>
<tr><td>1T </td><td>Light soy sauce</td></tr>
<tr><td>3T </td><td>Chicken stock</td></tr>
<tr><td>1t </td><td>Sugar</td></tr>
<tr><td>1t </td><td>Sichuan pepper, lightly crushed</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Chop the chicken thighs through the bone into two or three
pieces. Leave the skin on.
<br />
<br />
Combine the sliced onion, shredded root ginger, salt, soy sauce and
rice wine in a bowl. Add the chicken pieces and rub this
marinade into the chicken. Leave in the fridge for at least 1 hour.
<br />
<br />
Prepare the sauce ingredients now: shred the red pepper and chilli
(discard the seeds) and break the tangerine peel into small pieces.
<br />
<br />
Shake the chicken pieces free of the onion and ginger. Semi-deep-fry
in two batches in a wok, using about 200ml oil. (Semi-deep-frying only
really works in a wok, where you have a deep-enough pool of hot oil in
the middle and you keep turning the chicken pieces and splashing over
the hot oil.) Cook until the chicken pieces are quite brown. (This
might be around 5 minutes. You want to get the internal temperature up
to 70°C.) Put the chicken pieces to one side.
<br />
<br />
Pour out your hot oil into a suitable container. Clean the wok in the
sink and dry it in the usual way. Now make the sauce: heat 2T of oil
in the wok. When hot, add the red pepper, chilli and tangerine
peel. Stir-fry for one and a half minutes over a medium heat. Add the
remaining ingredients and stir together for one minute.
<br />
<br />
Return the chicken pieces to the pan and mix with the sauce. Mix and
turn for two minutes over a medium heat.
<br />
<br />
<b>Discussion</b>
<br />
<br />
This recipe might in some ways be closer to the original than Kenneth Lo's
version, since I've substituted Sichuan pepper and rice wine where he
uses crushed peppercorns and sherry. On the other hand, my
chicken pieces are larger — in his recipe they
are "bite sized" and I'm sure that's more authentic.Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-69721693464074043192013-09-22T10:33:00.000+01:002013-09-22T10:33:00.363+01:00Putting the 'P' in CAPBrewer's CAP Theorem says that in a distributed system you can
guarantee at most two of Consistency, Availability and Partition
Tolerance. So there's a trade-off: when you are designing your system
you will have to decide which two of these three properties you want to
always maintain, and which one you are prepared to drop. However,
there appears to be a bit of confusion about what it would really
mean to drop partition tolerance. Is that even possible? (For example,
see <a href="http://codahale.com/you-cant-sacrifice-partition-tolerance/"><i>You
Can't Sacrifice Partition Tolerance</i></a> by Coda Hale.)
<br>
<br>
In fact you <i>can</i> "trade off" partition tolerance and build a
system that guarantees both consistency and availability. This is
exactly the design decision that was made by the engineers who built
traditional telephone networks. However, this decision wasn't a "trade
off" in the usual sense, where you get to save money on one thing and
spend it on something else — instead they had to spend quite a
lot <i>more</i> money to build the unusually reliable nodes and
communication links that let them drop partition tolerance as a whole-system
property.
<br>
<br>
To see how this works, I'll first give a (very brief) explanation of
what the CAP Theorem says, in order to pave the way for a
(fairly brief) explanation of the techniques you can use to build
reliable sub-systems. If you haven't come across the CAP Theorem before, I
think the nicest introduction is
<a href="http://www.julianbrowne.com/article/viewer/brewers-cap-theorem"><i>Brewer's
CAP Theorem</i></a> by Julian Browne. (Some of what I say here is also
based on
<a href="groups.csail.mit.edu/tds/papers/Gilbert/Brewer2.pdf"><i>Perspectives
on the CAP Theorem</i></a> by Seth Gilbert and Nancy Lynch, which is a more
detailed overview; it's also worth reading
<a href="http://www.infoq.com/articles/cap-twelve-years-later-how-the-rules-have-changed"><i>CAP
Twelve Years Later: How the "Rules" Have Changed</i></a>, which is a
retrospective and commentary by Eric Brewer himself.)
<br>
<br>
<b>Consistency</b> This is close to the distributed systems idea of
"safety". A system is "safe" if it never says anything wrong, if every
response sent to any client of the system is always correct. In
systems of any complexity, this often amounts to saying that every
request must <i>appear</i> to all clients to have been executed
atomically (in a single instant) by some single central node.
<br>
<br>
<b>Availability</b> This is close to the distributed systems idea of
"liveness". A system is "live" if every request from every client eventually
receives a response. In practice there's a lower limit on how quick a
response could be (light-speed delay across whatever fraction of the
distributed system is necessary for that response) and there's an upper
limit, after which clients or people get bored, decide that the system
has failed and decide to take remedial action.
<br>
<br>
<b>Partition Tolerance</b> We say that a system has partition
tolerance if it behaves as intended by its designers in the face of
arbitrary message delay or message loss in the underlying
communications system. Usually this will be because of a "network
partition" where some link or node fails, but in best-effort networks
this can also include congestion, for example due to packets being
dropped on a congested port. A major practical problem with partition
tolerance is that very often the different parts of a distributed
system will disagree about whether or not there currently <i>is</i> a
partition.
<br>
<br>
The CAP Theorem says that you can build a distributed system with any
two of these three properties. Traditional "ACID" SQL databases choose to
drop availability: they delay responses to clients until they are
certain to be consistent. More avant-garde "BASE" NoSQL systems choose
to drop consistency: under pressure they give fast but possibly
out-of-date responses and patch things up later. And old-fashioned
telephone networks drop partition tolerance: they use nodes and
communication links which are so reliable that the distributed system
(almost) never sees message loss or arbitrary delay. But how do you do
that?
<br>
<br>
The usual pragmatic solution in any situation where a component might
fail is to replicate that component. For example, a plane with two
engines should be able to reach its destination if one of them
fails. In our case things are slightly more interesting because if we
replicate nodes, and these check each other, what's to
stop a failed node wrongly accusing a correct node of having failed?
A bad node could shut down a good node! To get over this problem,
we build nodes into fail-stop pairs with a separate checker:
<br>
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-beEUsq5LKxfoMXkakr_mLdzTuLt7yUx2tp22KdEF0ikaGD9JLPlZj_OWVV54mbglMw6I5_ctU7OSeSskya6_fwb1osTJWaD9gC8TLHcqR-I2NHuXi8UlujqXn4Cr-kaKYhyMYVhYnvgg/s1600/fail-stop-nodes.jpg" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-beEUsq5LKxfoMXkakr_mLdzTuLt7yUx2tp22KdEF0ikaGD9JLPlZj_OWVV54mbglMw6I5_ctU7OSeSskya6_fwb1osTJWaD9gC8TLHcqR-I2NHuXi8UlujqXn4Cr-kaKYhyMYVhYnvgg/s320/fail-stop-nodes.jpg" /></a>
<br>
<br>
This sub-system works roughly like this: a request comes into the
checker on one (or both) of the links on right.
The checker forwards this request to both node1 and
node2. These nodes are exact duplicates, and work separately to produce
what should be identical responses. The checker makes sure that these
responses match, in which case it sends that response back to the
client. But if the responses don't match, the checker stops and
refuses to communicate on any of its ports. Making this sub-system run
again is a maintenance action. (When this architecture is
used in a railway-signalling system, the checker might physically blow
a fuse to make certain that it won't work again without maintenance.)
In addition to
making sure that the results from node1 and node2 match, the checker
also sets a time limit for their responses, and similarly fail-stops
if this limit is exceeded. (So at the lowest level, the checker
enforces availability or "liveness" as well as consistency between
node1 and node2.)
<br>
<br>
There are a lot of subtleties here. To defend against software
errors, it is preferable to have two different implementations of the
system in node1 and node2. To defend against hardware failure, it is
preferable to have different hardware in node1 and node2, or at least
to have a different encoding for data on the interfaces to the two
nodes. (In this case the checker ensures that responses are
equivalent, rather than bit-identical.) Each node may also run
"routining" code in
the background which continually checks on the consistency of its
internal data, to guard against bit-errors in memory. If a node finds
such an error it logs this problem and then simply stops itself. (The
checker will then cleanly fail the whole sub-system when
it subsequently doesn't get a response to a request.)
<br>
<br>
And what happens if the checker fails? It should be possible to build
a checker which is more reliable than a node, because it is usually
much simpler than a node. However, it's going to fail sooner or later.
If it completely stops, that's actually
ok, but it might fail in some more insidious way, and not detect a
subsequent failure in node1 or node2. Depending on how paranoid you
are feeling, you might therefore double-up the checker, so that both
responses get passed through the first checker and checked again by the
second checker. (Or more ingeniously, you might apply these same
techniques recursively inside the checker.)
<br>
<br>
With this architecture, we solve one of our most tricky problems:
reliably detecting partitions of one node. We can combine two of these
fail-stop pairs into a master-slave combination continually
exchanging I-am-still-alive signals, usually in the form of the data
updates needed to keep the slave's data-structures in sync with the
master.
If the master fails it will stop cleanly, the slave will
notice this after a short, predictable delay and will take over from
the master. (An alternative architecture which is sometimes used at
the lowest level is to
have three nodes rather than two and to arrange for a two-out-of-three
majority vote at the checker. This requires a more complex and
therefore more error-prone checker, but has the advantage that when a
one node fails, recovery is immediate and the remaining two good nodes
can continue as a fail-stop pair.)
<br>
<br>
In this way we can
build resilient processing nodes and we can use the same techniques to
build resilient
communications nodes which forward data from one link to another. And
then by a combination of
link replication, forward-error-correction, bandwidth reservation and
automatic fail-over from one link to another we can ensure that
failures on a few links cannot impede traffic in the communication
network for more than a short
period. (It is customary to "over-dimension" these systems so that
they have considerably more capacity than their predicted peak load.)
If this architecture is taken to the extremes seen in
traditional telephone switches, it's even possible to completely
decommission and rebuild a switch while all the time it carries its
rated traffic.
<br>
<br>
So you <i>can</i> "trade off" partition tolerance, but it's actually
rather costly. It's rather curious that by making the sub-systems more
fragile, we can make the whole system more robust. There's an almost
biological feel to this — it's a bit like apopotosis or
"programmed cell-death", where a cell detects that it's going a bit
wrong and rather than turn into a cancer it commits
suicide very cleanly. It's also rather curious that the properties we
enforce at
the lowest level of the checker are consistency and availability
— exactly the properties that we want to have at the top level.
<br>
<br>
In practice, as noted by Gilbert, Lynch and Brewer in the papers I
mentioned earlier, in real systems we never trade off all of
consistency, availability or partition tolerance. In practice, we
compromise a little on one to gain a little more of another, and we
make different compromises at different times or for different
purposes. But if you see a system which appears to be getting more
than its fair share of both consistency and availability, look a
little closer: it must be based on low level resilience using the sort
of techniques I've described here.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com3tag:blogger.com,1999:blog-7962217619208800961.post-66610719713069961062013-06-16T08:27:00.000+01:002013-06-23T16:37:31.304+01:00Summer RecessSummer is nearly upon us. When I started this blog in freezing January I had
the idea that it could be a vehicle to help me figure out some half-baked
ideas. I think that's worked out quite well, although my posts have
often been a bit on the long side, more like short essays.
<br>
<br>
But now I need to get some code written and I also need to go on
holiday. Writing essays doesn't really help with either of those.
So I've decided that this blog can have a "long vacation" or
summer recess.
<br>
<br>
See you in the autumn.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-59204756303892284332013-06-09T16:21:00.000+01:002013-07-27T16:23:27.478+01:00The Robots Game
(This post is another follow-up to
<a href="http://onfoodandcoding.blogspot.co.uk/2013/03/learning-to-program.html">Learning
to Program</a>.)
<br>
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTQJ8y89v3XePz0M_R6KTb-CcX3tKqBINoNT-1oXJAcP7VOclpGWUJEDGWVed4b5JPdUX525uSIhiA8qraODKMX7cZBqVNJ4ybyM0o49Fbo0NI-N7gnMg8NSMXQY1WDu7Gc7mwrZka47BR/s1600/robots_finish_closeup.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTQJ8y89v3XePz0M_R6KTb-CcX3tKqBINoNT-1oXJAcP7VOclpGWUJEDGWVed4b5JPdUX525uSIhiA8qraODKMX7cZBqVNJ4ybyM0o49Fbo0NI-N7gnMg8NSMXQY1WDu7Gc7mwrZka47BR/s320/robots_finish_closeup.jpg" /></a>
<br>
<br>
When stage magician James Randi was doing cabaret work, he had the
habit of opening his act with a newspaper tearing-and-reassembly
routine. With the music playing, he would stride out in front of the
audience with a piece of
newspaper folded under his arm. He would unfurl the newspaper and tear it
up into pieces. Then he would shuffle the pile of pieces, give it a
flip and it would all be back together again. The music would stop, he would
throw the newspaper aside and address the audience, saying:
"I don't know how that trick's done and I don't care."
<br>
<br>
Now the funny thing about this, as Randi explains, is that there was
in fact <i>something</i> about the routine that he didn't know.
The rest of the act went
better when he started out this way, but for a long time he
didn't know why. "Most magicians," says Randi, "don't know why
their tricks work. They know they work because they've
done them and done them repeatedly, and sometimes they do things on
stage that they don't quite understand, but they know that they work."
<br>
<br>
What was Randi's opening routine really doing?
"I started doing it and I found it worked very well," he says. "But I
only realised <i>years</i> into it that I was sizing up the audience. I
would be looking around the audience while tearing up the newspaper
and seeing people who were paying attention and others that maybe had
a few too many drinks, or they were distracted in some way and
were talking to the person beside them." Who should he call on from the
audience to take part in subsequent routines? The way the newspaper
routine worked was that it told him the answer to that question and
made the rest of his act work better.
<br>
<br>
I've opened my programming teaching for several years now with "The
Robots Game". It seems to work very well for me, but I'm not entirely
sure why. So, in this post I'll describe the game and its rules and
then I'll speculate on how it might work as the opening routine for a
programming course.
<br>
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNSFxEN-f5Yga-0jTrI-TED7hVRZ5ogf4ub1R-H3MFz11DFsA8JLnwwATu7P_HOcfd_sJWYkHb4Mu0Z-2fD4sRmatnWqD4LP1vNkXXIeaOQj5S2Mh_xPzMsjcSpjdHnlLDO6GtcIHcXRWi/s1600/robots_whole_room.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNSFxEN-f5Yga-0jTrI-TED7hVRZ5ogf4ub1R-H3MFz11DFsA8JLnwwATu7P_HOcfd_sJWYkHb4Mu0Z-2fD4sRmatnWqD4LP1vNkXXIeaOQj5S2Mh_xPzMsjcSpjdHnlLDO6GtcIHcXRWi/s320/robots_whole_room.jpg" /></a>
<br>
<br>
<b>Equipment</b>
<br>
<br>
This is a board game for six players so for each
group of six students you will need:
<br>
<br>
The board, printed out on a large piece of card or foam-board:
<br>
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoLC9pzriKrb6trDnRlRC-oUngkwBXCLdUTIT6CT0NIROcGdcye1POjsFWoC5yfZu6zjwonWSdZHySixq-qihyphenhyphenph54PskKzlWHsUZy4gKzPU8Lcs-K6Fpxr5BjnIyk11yqAp_wPfQrk48t/s1600/robots_whole_board.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoLC9pzriKrb6trDnRlRC-oUngkwBXCLdUTIT6CT0NIROcGdcye1POjsFWoC5yfZu6zjwonWSdZHySixq-qihyphenhyphenph54PskKzlWHsUZy4gKzPU8Lcs-K6Fpxr5BjnIyk11yqAp_wPfQrk48t/s320/robots_whole_board.jpg" /></a>
<br>
<br>
The six "robot" playing pieces, numbered 1 to 6:
<br>
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPFlaJMVSigcNzrReF0hEnELvfF1EyGBEtVNmzTvjTn0MaGGO8ZLH6cfQKN5elfElUeTFU24K2MV0L8_Fvpymgu7JtshNVWxFRSM0DkNiZTcknQxerovGBjvBgsV_rxnqTfWIvhXNou_Zr/s1600/robots_start_closeup.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPFlaJMVSigcNzrReF0hEnELvfF1EyGBEtVNmzTvjTn0MaGGO8ZLH6cfQKN5elfElUeTFU24K2MV0L8_Fvpymgu7JtshNVWxFRSM0DkNiZTcknQxerovGBjvBgsV_rxnqTfWIvhXNou_Zr/s320/robots_start_closeup.jpg" /></a>
<br>
<br>
Printed move-sheets for the players to write directions, and pencils/pens:
<br>
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNXBzyjaUffKdoiWasUhrOCoDhEnPDJxN216SrkTzOjE8EOtAY7iTgMJAG3lQroik1aL_LYk_l-cZA10KcYrL1xB5JIozqbpc12wZs87rMSRJRCRMQPziiotgVb_CR1dEj8J2JbFuC5YuZ/s1600/robots_move_sheet.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNXBzyjaUffKdoiWasUhrOCoDhEnPDJxN216SrkTzOjE8EOtAY7iTgMJAG3lQroik1aL_LYk_l-cZA10KcYrL1xB5JIozqbpc12wZs87rMSRJRCRMQPziiotgVb_CR1dEj8J2JbFuC5YuZ/s320/robots_move_sheet.jpg" /></a>
<br>
<br>
You will also need (as you can see in some of the photos) a normal
six-sided dice.
<br>
<br>
<b>Rules</b>
<br>
<br>
(1) This is a race game played by two teams. The winning team is the
first to get all their "robots" from the start to the finish and
off the board. (Note: the winner is the first team to get <i>all</i>
their robots off the board, not just the first one.)
<br>
<br>
(2) Each team consists of three players and each player controls one
specific robot. Each robot has an identifying number. As you can see
from the photos, my robot playing pieces have the numbers on the top,
with 1, 2, 3 in one colour for one team and 4, 5, 6 in another colour
for the other team.
<br>
<br>
(3) The robots start facing into the board on the six starting squares
on one end. (The pieces must have some way to show what direction they
are facing. My robot playing pieces have arrows on the top, but in a
previous version I used little Lego figures with numbers stuck to
their backs.)
<br>
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitkJrrGYCQRvowfot_38Ij6wp7BytnKAEMrc-cp4r_K74CmYVyEJv56iFh4HWa1jbSJVVKVLaQ7cH-8hkMxl8-IHowAms2mSY18Ak290NxldNyGekF2jCHHSj3uQgHJRdVYucMrk4kMGPf/s1600/robots_from_start_0_move.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitkJrrGYCQRvowfot_38Ij6wp7BytnKAEMrc-cp4r_K74CmYVyEJv56iFh4HWa1jbSJVVKVLaQ7cH-8hkMxl8-IHowAms2mSY18Ak290NxldNyGekF2jCHHSj3uQgHJRdVYucMrk4kMGPf/s320/robots_from_start_0_move.jpg" /></a>
<br>
<br>
(4) Each player starts with their own blank move-sheet on which
they will write directions for their robot. (After your students
arrange themselves into two teams of three, get each student to
write the number of their robot on their move-sheet, so there's no
doubt as to which is which.)
<br>
<br>
(5) The game consists of a series of turns, continuing until one team
has won. Each turn proceeds as follows:
<br>
<br>
(5 a) Every player writes on their move-sheet up to 10 moves for their
robot. As you can see, the move-sheets I use have the numbers 1 to 10 down
one edge, so the moves for each turn can be written vertically down one
column. Valid moves are <b>Forward</b> (F), <b>Back</b>
(B), <b>Right</b> (R) and <b>Left</b> (L). It's fine to not use
all 10 moves. (It's even fine to not use any of your moves, in which
case your robot will just stay in the same place.) Naturally, players
on the same team will wish to coordinate their moves with each other,
but hide their plans from the other team.
<br>
<br>
(5 b) When everyone has finished writing their moves, someone throws
the dice. Depending on what number comes up, the robots execute their
moves in sequence starting with that number. Thus, for example,
if the dice shows 4, then all robot 4's moves will be executed first,
followed by all robot 5's, then 6, then 1, then 2 and finally 3. (Thus
when writing moves, the players cannot be sure exactly where the other
robots will be, even on their own team.)
<br>
<br>
(5 c) To execute the moves for each robot, the player controlling that
robot reads out the sequence of moves for that turn from their
move-sheet. Someone else actually moves their robot (preferably someone from
the other team). The reason for this is that people can make mistakes
writing down their moves, and rather than giving them the opportunity
to correct them, we want to ensure that the robot executes the moves that
they actually wrote down.
<br>
<br>
(5 d) Each move is executed as follows: <b>Forward</b> attempts to move the
robot forward one square in the direction it is facing. This succeeds
if that square is an unoccupied green square or if the shunting rule
applies (see 5 e). Otherwise the move fails. (For example if the
square in front is a brick-wall.) <b>Back</b> attempts to move the
robot one square backwards and succeeds or fails in the same way as
for a forwards move. <b>Right</b> and <b>Left</b> <i>turn</i> the
robot in place through 90-degrees clockwise or anti-clockwise,
respectively. These moves always succeed.
<br>
<br>
(5 e) Shunting. If a robot attempts to move into a square occupied by
another robot, this will succeed provided that (i) the moving robot
has just crossed one empty square ("it
has momentum") AND (ii) there is an empty green square on the other
side of the stationary robot ("it has somewhere to go"). When a
shunting move succeeds, the moving robot afterwards occupies the
square where the stationary robot was, and the stationary robot is
shunted along one square in the obvious way. (Note that part (i) means
that you can only shunt another robot one square. Continuing to move
in the same direction will fail. You can do two shunts in a turn, but
you have to back up and take another run-up at the stationary robot.)
<br>
<br>
(5 f) All moves of a particular robot are executed in order,
irrespective of whether its earlier moves that turn succeeded or
failed. Thus a
robot might use several moves trying and failing to go forwards
("spinning its wheels") then turn and succeed in going forwards in a
different direction. (But probably not end up in the place its
controller intended.)
<br>
<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0o5mRGyHkisiYbeXopgSjwCrEk64Fy5lQKv9hrSizxNs2Cmh-3wqHjCR9sqmEFspVp0AUIh5W86-N0hzbl-xs3dR0HNe_GLUEyaMR38xicrVyMTRBTBPMDErJUeDtxiN9a4qHmXB28jXA/s1600/robots_finish.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0o5mRGyHkisiYbeXopgSjwCrEk64Fy5lQKv9hrSizxNs2Cmh-3wqHjCR9sqmEFspVp0AUIh5W86-N0hzbl-xs3dR0HNe_GLUEyaMR38xicrVyMTRBTBPMDErJUeDtxiN9a4qHmXB28jXA/s320/robots_finish.jpg" /></a>
<br>
<br>
(6) Exit squares and winning. The four squares with
outward-facing arrows at the end of the board are exit squares. When a
robot moves onto one of these squares it is <i>immediately</i> removed
from play, and takes no further part in the game. Moves are made as
normal each turn for the remaining robots, skipping over robots which
have been removed from play. The first team to have all three robots
out of play in this way is the winner.
<br>
<br>
<b>Discussion</b>
<br>
<br>
The game is quite fun and doesn't take very long to play — usually
around a quarter of an hour or less. It's almost always quite close
at the end, because of course it's a race between the <i>last</i> robot in
each team. There's plenty of opportunity for
delaying tactics and clever blocking moves near the exit by the team
which is behind, provided they don't just individually run for the
exit as fast as possible.
<br>
<br>
But turning back to the idea from James Randi, how does this game
work? It seems from my experience to be doing something useful, but
how does it really work as an opening routine for a programming
class? Perhaps first of all, I think it lets me give the impression to
the students that the rest of the class might be fun. Lots of students
don't seem to like the idea of programming, so perhaps playing a team
game like this at the start of the class surprises them into giving it
a second chance.
<br>
<br>
I think also that there is an element of "sizing the audience up"
— it's a way to see how the students interact with one another,
to see who is retiring and who is bold, who is methodical and who
is careless. The people who like clever tricks in the game seem
often to be the people who like clever tricks in programming.
There is also some evidence that facility with mental rotation is
correlated with programming
ability. (See <a href="http://www.humantechnology.jyu.fi/articles/volume4/2008/jones-burnett.pdf"><i>Spatial
ability and learning to program</i></a> by Sue Jones and Gary
Burnett in <i>Human Technology</i>, vol.4(1), May 2008, pp.47-61.)
To the extent that this is true, I might be getting a hint about who
will have trouble with programming from seeing who has trouble making
their robot turn the correct direction.
<br>
<br>
I'm keen to point out to the students, after the games are over, that
the game really has some relation to programming. I point out that
they have been
writing sequences of instructions, little programs for the robots,
which then get blindly executed. I
point out that although computers seem clever, they really have no
more intelligence than the wooden playing pieces in the
game. Computers just execute their moves billions of times faster,
and that makes them <i>seem</i> smart.
<br>
<br>
I also ask if anyone found that
their robot ever did something that they didn't want it to
do. (Inevitably there are a few cases where people just wrote down the
wrong move and their robot trundled off in an unexpected direction.)
I point out that this is an ordinary thing in
programming. It's going to happen again, it happens to the best of
programmers, so don't be embarrassed. Just learn how to play the
detective, to find and fix your inevitable
mistakes. Computers, like the robots, don't do what we
want. They do what we <i>say</i>.
<br>
<br>
(James Randi's explanation of his newspaper routine is from the the first
<a href="http://www.crypto.com/blog/shb08">Security and Human Behavior
Workshop</a> which took place in July 2008.)
<br>
<br>
<i>(Added 27 July 2013.) I've had some requests for an image of the
game board. Here is
<a href="http://www.stuartwray.net/images/robots-game-board.jpg">an
5673 x 4046 pixel image</a>, which should print nicely at any
reasonable size.</i>
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com5tag:blogger.com,1999:blog-7962217619208800961.post-77803210361625700122013-06-02T14:04:00.000+01:002013-06-02T14:04:26.317+01:00Recipe: Vinegar and Pepper Soup with Sliced FishThis sounds a bit bizarre, but it's really nice — though you probably
want to eat it one little bowl at a time, interspersed with other
dishes in a Chinese meal, rather than all by itself. The recipe is
originally from Kenneth Lo.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">250g</td><td>Fish fillet (cod is good, any white fish is ok)</td></tr>
<tr><td>1t </td><td>Salt</td></tr>
<tr><td>1T </td><td>Cornflour</td></tr>
<tr><td>1 </td><td>Egg white</td></tr>
<tr><td>
<tr><td>3 </td><td>Spring onions</td></tr>
<tr><td>1 litre </td><td>Stock</td></tr>
<tr><td>3 slices </td><td>Root ginger (skin removed, about 2mm
thick)</td></tr>
<tr><td>0.5t </td><td>Ground white pepper</td></tr>
<tr><td>4t </td><td>Soy sauce (light)</td></tr>
<tr><td>5T </td><td>Vinegar (white wine vinegar works well)</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Cut the fish into thin slices and rub with salt and cornflour. Then
wet with the egg-white and leave for 30 minutes.
<br />
<br />
Chop the spring onion into 5mm pieces.
<br />
<br />
Put the stock and the root ginger slices in a pan and bring to the
boil. Simmer for 5 minutes.
<br />
<br />
Add the fish slices, chopped spring onion, white pepper, soy sauce and
vinegar. Simmer for another 5 minutes.
<br />
<br />
<b>Discussion</b>
<br />
<br />
I suppose that being a fish soup, we should really use a fish stock,
but I never have. I would use the brown chicken stock that I described
<a href="http://onfoodandcoding.blogspot.co.uk/2013/03/recipe-yet-another-chilli
.html#brown-stock">here</a>. Since this is a clear soup you probably
want to filter the stock through a sieve lined with wet muslin to make
it look more respectable. (If you are really keen, you might want to
try doing this from frozen, leaving it to drip slowly into a bowl in the
fridge. The result is better but it takes a long time: a day or two.)
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-45857700536731050932013-05-26T10:01:00.000+01:002013-07-02T12:13:21.291+01:00Agile is AntifragileEarlier this year I read the excellent
book <a href="http://www.amazon.co.uk/dp/1846141567"><i>Antifragile</i></a>
by Nassim Nicholas Taleb. He's a bit full-of-himself and has a
somewhat quirky writing style, but the ideas in the book are so good
that this is easy to forgive. (And in fact, when I had finished the
book, I turned around and read it through again, which I never
do, so that must say something about the content.)
<br>
<br>
I've been thinking about the connection between Taleb's ideas and
software development for some time — something like five years
in the case of my recent
essay <a href="http://www.stuartwray.net/bugs-with-long-tails-draft.pdf"><i>Bugs
with Long Tails</i></a> — but his previous books don't make it
quite so clear how to put into practice the maxim that one should
"invest in preparedness, not prediction". In the face of uncertainty,
what exactly does it mean to be well prepared?
<br>
<br>
Taleb has invented the new term "antifragile" as a label for those
things which are not merely robust to uncertainty, but actually relish
it and benefit from the uncertainty. For example, a tourist who
follows a schedule is fragile, because if the bus doesn't arrive it's
a disaster. By contrast a "flâneur" who makes no decisions ahead
of time doesn't care. If the bus doesn't arrive, it's an opportunity
to see things and do things that would never have been on any
schedule. Better than robust, they are antifragile: when the
unexpected happens, it's an advantage.
<br>
<br>
Antifragile cherishes "optionality": the ability to do something
if it benefits you without the obligation to do it when it doesn't
benefit you. You don't need to predict what will
happen in the future, provided that you have placed your bets so that
you incur a small fixed loss but in return you have the chance to make
a large gain. (And because you have an option, not an obligation, if
it goes wrong you get to walk away. You never suffer a large loss.)
When losses are certain but small and gains uncertain but large, a
trial-and-error approach will in the long term bring more than
survival: it will bring success.
<br>
<br>
The problem with this approach is that it takes a kind of
moral courage. People hunger for apparent predictability, for a
reassuring chain of small gains even at the risk of a huge loss that
wipes them
out.
Day-to-day it's harder to endure the drip-drip of the
small losses incurred by the antifragile approach, even when you
consciously recognise the long-term benefits.
(See <a href="www.amazon.co.uk/dp/0141033576"><i>Thinking, Fast
and Slow</i></a> by Daniel Kahneman for an explanation of this curious
effect.)
<br>
<br>
In business, the people
responsible for each part of a firm will tend to "play it safe": they
will try to ensure that they usually do make a small gain, even if
they run the risk of a large loss. But from the point of view of the whole
business this is a poor choice: it would be much better if the people
in charge of each part accepted small losses, provided that in return
they had a fair chance of a large gain and <i>no</i> chance of a large
loss. They usually don't make this choice, because they don't want to
be blamed for the small failure if their bet doesn't pay off.
Since they avoid blame, they get to keep their jobs
for now, but maybe not for long, because the business as a whole becomes
fragile.
<br>
<br>
A business which is fragile has no choice but to try to predict the
future. But in many cases, predicting the future or even just estimating
the probability of future events is much harder than most people
think. And as I have argued
in <a href="http://www.stuartwray.net/bugs-with-long-tails-draft.pdf"><i>Bugs
with Long Tails</i></a>, there is evidence that software development is
one of those cases where prediction is too hard. We can't do it. And
if we can't do it, we shouldn't try. We should "invest in preparedness, not
prediction". We should be antifragile. What does that mean in
software? It looks a lot like what people usually call "agile".
<br>
<br>
I'll give just a few examples here, because I'm sure you can fill in
more for yourself:
<br>
<ul>
<li>
Don't try to guess what the customer/product-owner wants. Instead of
trying to predict what you can't predict, insist that they are always
available to <i>say</i> what they want. (Or admit that they don't yet know,
in which case you can help them find out.)
</li>
<br>
<li>
Big projects are known to have worse cost over-runs than small
projects and this is because they rely so much on prediction. So agile
development splits big projects into short iterations/sprints a few
weeks in length, each of which delivers some finished product,
worthwhile on its own. A few of these iterations may fail, but that's
fine. Learn your lesson and move on: small, isolated losses; large
overall gains. To paraphrase Kent Beck: "The purpose of planning is
not to predict the future, but to know that you are working on the
most important thing right now."
</li>
<br>
<li>
In Extreme Programming there are the principles "You Aren't Going
To Need It" and "Do The Simplest Thing That Could Possibly Work". The
least productive development work is building code that is never
needed. But we don't have to <i>predict</i> what code we need right
now, because we
already know. For code that we don't need right now, we have to predict what
people in the future will need our code to do, how efficient it must be in
time and space, and lots of other details that we currently know nothing
about. Very often we are wrong in these predictions. Better to make a
bet that we will never need that code and accept the small loss of changing
the code later if it proves inadequate. The big payoff if we win the bet
is less code and less overall work.
</li>
</ul>
<br>
Another relevant example of antifragilility can be found in
the architectural work of
Christopher Alexander. (Though it's curious that Taleb doesn't mention
Alexander, especially since he does mention
<a href="http://www.amazon.co.uk/dp/0670835153"><i>How Buildings
Learn</i></a> by Stewart Brand.)
It's well known that in the 1990s,
the same people in the
object-oriented programming community who came up with the idea of
agile development also worked on "patterns", inspired by Alexander's
books <a href="http://www.amazon.co.uk/dp/0195024028"><i>The
Timeless Way of Building</i></a> and
<a href="http://www.amazon.co.uk/dp/0195019199"><i>A
Pattern Language: Towns, Buildings, Construction</i></a>.
<br>
<br>
Less well-known in the software development world is that Alexander
became dissatisfied with patterns because they did not reliably
generate the kind of "living structure" of buildings that he describes
in <i>The Timeless Way of Building</i>: buildings that have the
"Quality Without A Name". This was a problem, but a problem with a
happy ending, because he describes the solution in his massive
follow-on work <i>The Nature of Order</i>. (Over 2000 pages in four
volumes:
<a href="http://www.amazon.co.uk/dp/0972652914"><i>Book 1</i></a>,
<a href="http://www.amazon.co.uk/dp/0972652922"><i>Book 2</i></a>,
<a href="http://www.amazon.co.uk/dp/0972652930"><i>Book 3</i></a>,
<a href="http://www.amazon.co.uk/dp/0972652949"><i>Book 4</i></a>.)
<br>
<br>
Alexander has even more to say in this magnum-opus than Taleb in
<i>Antifragile</i>, but the key point for us here is the idea of a "generative
sequence". The patterns are useful, but to do their work properly they
must be used in a disciplined way, in a specific generative sequence
where nothing has to be predicted ahead of time, but decisions only
made based on what is visible right now, in the situation at
hand. For example, Alexander gives a 24-step generative sequence for
building a Japanese tea house (vol. 2, p303-304) starting with a
secluded garden. Within this sequence, step 12 is to lay out a
particular path, step 13 to choose a stone water basin and place
it on this path, and so on. The trick is that having made a decision
at one step it is never necessary to go back and revisit an earlier
decision, nor is it necessary to consider a later decision ahead of
time. There is no planning.
<br>
<br>
It's surprising that this approach works at all. Why should it be
possible to find generative sequences which allow things to be
designed step by step and never go back to revisit an earlier
decision? And yet it does seem to be possible to find these sequences,
and they do seem to be able construct things which have the "Quality
Without A Name". Expert knowledge therefore encompasses not just the
patterns, but the generative sequences that make them work and the
principles used to discover generative sequences. (And most
of <i>The Nature of Order</i> is about these principles.) As
Alexander notes:
<br>
<br>
<div style="margin-left: 2em;">
"The significance of generated structure lies in the concept of
mistakes. Fabricated plans <i>always</i> have mistakes — not
just a few mistakes, but tens of thousands, even millions of
mistakes. It is the mistake-ridden character of the plans which marks
them as fabricated — and that comes from the way they are
actually generated, or made, in time. Generated plans have <i>few</i>
mistakes." (vol. 2, p186)
</div>
<br>
Generated structures don't avoid mistakes
— their construction involves many mistakes. But these are <i>cheap</i>
mistakes, easy to notice and quick to correct. Always corrected before
going on to the next step. Planned structures
probably involve the same number of mistakes, but a plan doesn't give you
any feedback, so every mistake persists and is built into real-life.
<br>
<br>
We borrowed the idea of patterns from Alexander.
We could frame agile development as another borrowing,
an application of Alexander's idea of
generated structure in the world of software
development. We still seem quite a long way from having reliable
generative <i>sequences</i> in software, apart from the tacit
craft-knowledge embodied in
individuals and small groups, but maybe in the future we can do
better. Maybe we could see the agile "movement" as a search for such
generative sequences.
However, I think an even better framing would be to see both agile
development and generative sequences as instances of
antifragility. This perspective emphasises what gives them both their
power: avoiding plans and prediction when we can't know enough to
predict correctly.
<br>
<br>
(I've noticed that I'm not the only one to have seen a link
between Taleb's ideas and agile development:
see <a href="http://www.agile-doctor.com/2013/01/10/agile-antifragile-part-2/"><i>Agile=Antifragile</i></a>.
If you'd like to see Taleb talking about his ideas, you might like to
watch this
<a href="http://www.nypl.org/audiovideo/live-nypl-nassim-taleb-daniel-kahneman">video
filmed at the New York Public Library</a>.
You can also find much better account of how Alexander's ideas
relate to software in Part One of
<a href="http://www.dreamsongs.com/Files/PatternsOfSoftware.pdf"><i>Patterns
of Software</i></a> by Richard Gabriel.)
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com3tag:blogger.com,1999:blog-7962217619208800961.post-75079774865128117392013-05-19T09:30:00.000+01:002013-05-19T09:30:18.514+01:00Recipe: Lamb kebabsThis is really two recipes: the lamb kebabs themselves and a
yoghurt-and-cucumber thing to go with them.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">500g </td><td>Minced lamb</td></tr>
<tr><td>1 </td><td>Egg</td></tr>
<tr><td>1t </td><td>Ground coriander</td></tr>
<tr><td>1t </td><td>Ground cumin</td></tr>
<tr><td>1T </td><td>Paprika</td></tr>
<tr><td>0.5t </td><td>Cayenne pepper</td></tr>
<tr><td>0.25t </td><td>Salt</td></tr>
<tr><td>pinch </td><td>Ground pepper</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Blend all the ingredients except the mince together, then thoroughly
mix this into the mince and set aside in the fridge (for at least 2
hours, but all day if possible).
<br />
<br />
Split the mixture into 6 equal pieces and form each piece into a
sausage shape on a kebab skewer. Grill for 10 minutes, then turn over
and grill for another 10 minutes. (Of course, in summer you can cook
them on the barbecue.)
<br />
<br />
<b>Yoghurt and Cucumber</b>
<br />
<br />
This goes very well with these kebabs. It's a bit like tsatsiki.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">500g </td><td>Greek yoghurt</td></tr>
<tr><td>1 </td><td>Cucumber: peeled, de-seeded and chopped</td></tr>
<tr><td>1T </td><td>Fresh coriander, chopped finely</td></tr>
<tr><td>1T </td><td>Fresh mint, chopped finely</td></tr>
<tr><td>1T </td><td>White wine vinegar</td></tr>
<tr><td>0.25t </td><td>Salt</td></tr>
<tr><td>pinch </td><td>Ground pepper</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Combine all the ingredients and mix well. Chill in the fridge for a
couple of hours. Serve.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-19082392382867630672013-05-12T09:55:00.000+01:002013-06-04T09:19:45.141+01:00A Day at elBulli<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZaTunqhnns9nfKznAvgioaYSYxJK7IceLH4VRZTgrNRxF7YtzcKf1ze_jLWbmcbRjNojszYvjEsIZvHkMzOd3c3qtSBnGUwR2PQ23JE2YJClw9ql6_wx8ai2oA_fPq7-CLwvb5X2ZS8qg/s1600/photo-el-bulli2.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZaTunqhnns9nfKznAvgioaYSYxJK7IceLH4VRZTgrNRxF7YtzcKf1ze_jLWbmcbRjNojszYvjEsIZvHkMzOd3c3qtSBnGUwR2PQ23JE2YJClw9ql6_wx8ai2oA_fPq7-CLwvb5X2ZS8qg/s320/photo-el-bulli2.jpg" /></a>
<style> body {font-family: sans-serif;}</style>
<br>
<br>
I'm looking at my copy
of <a href="http://www.amazon.co.uk/gp/product/0714848832"><i>A
Day at elBulli</i></a>, a very thick book by
Ferran Adrià which gives a minute-by-minute account of a typical
day at the restaurant elBulli. I don't suppose that I get this
book down from the shelf more than once a year, but I think more than
any other book it was this one which convinced me that software
development has a lot more in common with cooking than with
architecture.
<br>
<br>
elBulli was a rather unusual restaurant. (It closed in 2011.)
It opened for only 160 days a year, summer through to
winter, serving one sitting of 50 guests each day. The kitchen staff
of about 40 prepared a fixed "tasting menu" of around 30 miniature
dishes for each guest, served by a front-of-house staff of about
25. (Although tiny, each dish generally took more effort to prepare
than most main courses in most restaurants. Only 50 customers a day
sounds easy. Think of 1500 complex main-courses a day and you have a better
idea how much effort was involved.)
<br>
<br>
They served around 8000 guests a year, but they got many, many more
requests for reservations. Around 2 <i>million</i>. And yet they only
charged around €200 per head. Clearly they could have charged
much more; clearly the main purpose was not to make money, but rather
to research new recipes and techniques. It was a <i>research</i>
restaurant. Who would have thought such a thing was possible?
<br>
<br>
When I first read the minute-by-minute descriptions in the book, I was
reminded somehow of happy experiences working in an Extreme
Programming development team. Everyone doing hands-on work to some
extent, everyone conscious of working <i>together</i> to make
something, always working with one eye on the clock. I
was also struck by the discipline, similar to XP:
<br>
<br>
<ul>
<li>
Simple, direct organisation, with stand-up meetings at the start and end of
the day.
</li>
<br>
<li>
Clear up as you go. Even though it's late and everyone is tired,
everything is left neat and tidy at the end of the day,
ready for a fresh start tomorrow.
</li>
<br>
<li>
Process, timing and organisation are everything. But the physical
artifacts used to track progress are very simple: order-sheets, plans for
mise-en-place, shopping lists.
</li>
</ul>
<br>
What lessons can software developers learn by looking at a restaurant
like this? First maybe that they both have customers, and the
customer's experience in both cases
has very little to do with the essential nature
of producing that experience. What does the customer see? Only the
front-of-house.
<br>
<br>
There are front-of-house staff and kitchen
staff. Though the kitchen is the heart (without the kitchen there is
nothing) most guests don't see it, and know almost nothing about the
production of their food.
This certainly has echoes in software development. The customer is
oblivious to what goes on behind the scenes, and the effort to make
it work. But strangely, in software the front-of-house staff
often set the terms for the kitchen staff despite having little hands-on
knowledge about the production processes.
<br>
<br>
Another lesson is that process is key. It's all about process. But not
the kind of stupid "big process" checklist in some
binder somewhere that everyone ignores. No, the key is the
precise minute-by-minute, hour-by-hour knowledge of how to actually do
things the best way. Sometimes this is written down, but often not.
<br>
<br>
At elBulli, most kitchen staff did "process execution". A few,
particularly Ferran Adrià himself, focused on process
creation, figuring out what dishes to make and how best to make
them. Every day inventing and perfecting processes,
refining recipes and the techniques for making existing dishes.
Experimenting with new ones. This is an <i>obsession</i> with process:
hundreds of trials, failures, tweaks and variations to perfect the
process to make each dish. And from the point of view of the customer,
this long effort and many failures was completely hidden, though the
final dishes could not be served without it.
<br>
<br>
The meta-idea here is to have complete control of process, a process
even for creating processes. Now with software development, for all
our claimed
enthusiasm for process, are we really in the same league as these
guys? I don't think so. We just don't see this kind of perfectionism
very often, and when we do see it (for example in Extreme Programming)
it is thought of as something odd and bizarre. Not like elBulli, a
magnificent example of the art, which others admire, respect, and
aspire to emulate.
<br>
<br>
Have a look at <a href="http://www.amazon.co.uk/gp/product/0714848832"><i>A
Day at elBulli</i></a>. It's worth considering: what if we applied
that kind of attitude to software?
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-64599652059588084672013-05-05T09:51:00.000+01:002013-05-05T09:51:46.662+01:00Recipe: Red-cooked PorkThis recipe was originally based on one from <i>Cheap Chow: Chinese
Cooking on Next to Nothing</i> by Kenneth Lo, but it's diverged a
little bit since then. The result is quite similar and as Kenneth Lo
says: "The combination of meat, fat, skin and gravy is probably about
the most savoury and appetizing thing in the whole realm of Chinese
culinary creation".
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">1.5kg </td><td>Belly pork slices (each
about 1cm thick)</td></tr>
<tr><td>6T </td><td>Sunflower oil</td></tr>
<tr><td> </td></tr>
<tr><td>5t </td><td>Light soy sauce</td></tr>
<tr><td>180ml </td><td>Medium-dry sherry</td></tr>
<tr><td>180ml </td><td>Water</td></tr>
<tr><td>1t </td><td>Five-spice powder</td></tr>
<tr><td>2t </td><td>Sugar</td></tr>
<tr><td>2 </td><td>Star anise</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Preheat oven to 150°C (= gas mark 2 = 300°F).
<br />
<br />
Heat the oil in a wok or frying pan, and brown the belly pork slices
in batches, a few at a time. Place them in a large casserole.
<br />
<br />
Mix all the other ingredients and pour this sauce into the casserole
too. Arrange the belly pork slices so that they are packed closely
together. Cook in the oven for about 4 hours, turning the pieces over
every hour, so that they cook evenly.
<br />
<br />
<b>Discussion</b>
<br />
<br />
I think everyone has a slightly different recipe for red-cooked
pork. The Kenneth Lo recipe in <i>Cheap Chow</i> (p48) takes the meat
in a single piece, rather than sliced, and cooks it for 1 hour with
only a quarter of the sauce in the above recipe, then another 1 hour
30 minutes after adding another quarter of the sauce (and no
five-spice powder). Fucia Dunlop in <i>Revolutionary Chinese
Cookbook</i> (p78) uses fresh ginger, star anise, chilli and cassia
bark for flavour, and simmers the dish in a wok for 50 minutes rather
than in the oven. (Which leaves it a bit chewy for my taste.)
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-49417905980055540312013-04-28T10:02:00.000+01:002013-04-28T10:02:25.279+01:00Completely Reliable Conclusions(This post is another follow-up to
<a href="http://onfoodandcoding.blogspot.co.uk/2013/03/learning-to-program.html">Learning
to Program</a>, which in turn was a kind of follow-up to
<a href="http://www.stuartwray.net/philosophy-of-knowledge.pdf">Not
a Tool, but a Philosophy of Knowledge</a>.)
<br>
<br>
I've been reading
<a href="http://www.ams.org/notices/201201/rtx120100031p.pdf"><i>A
Revolution in Mathematics? What
Really Happened a Century Ago and Why It Matters Today</i></a>
(Notices of the AMS, vol.59 no.1, Jan 2012, pp31-37) and a stack of
other papers by mathematician Frank Quinn. He describes how,
since the early twentieth century, professional
mathematicians have worked in a particular way, the way they found
most effective. Shockingly, Quinn points out that this is not how
students are taught to do mathematics (in the USA) at any level up to
and including a large part of undergraduate material. Instead,
because of a misunderstanding by maths educators, students are taught
outdated and inferior methods from the nineteenth century. This
difference, although it seems both obvious and remarkable once pointed
out, has remained unnoticed by mathematicians and educators until
very recently.
<br>
<br>
Quinn goes on to argue that this unnoticed difference could to a large extent
explain the poor and declining results of mathematics education in the
USA. (And to the extent that other countries use the same poor methods,
we should expect the same poor results elsewhere too.) The problem has
become worse in recent years, says Quinn, largely because those in
control of maths education believe that their methods are just fine, and
believe that success will come with more vigorous application of the
same poor methods. So rather than change these methods, the authorities
have successfully championed "more of the same", leading to a "death
spiral" from which escape appears uncertain.
<br>
<br>
I find Frank Quinn's ideas very convincing. I've done enough maths
tuition that from personal experience I recognise some of the concrete
problems of student understanding that he describes. It's rather
frightening to see these problems explained as merely symptoms of a larger
systemic problem. I think Quinn's ideas are crucial for the future of
maths teaching, but I believe there are lessons here for us too, as we
consider how best to teach programming. It's possible that we too
have been going about things the wrong way, misunderstanding the
fundamentals, and that the problems we face in teaching programming
are <i>exactly the same problems</i> that Quinn describes. If so, the
good news is that we can immediately draw on Quinn's experience and
suggestions of how to do it better. I'll return to this thought later,
but first let's examine more closely what he says about the difference
between nineteenth and twentieth century methods in mathematics.
<br>
<br>
Up until the late nineteenth century, a mathematical proof depended to a
large extent on physical intuitions and on understanding what a
mathematical model "really" meant:
<br>
<br>
<div style="margin-left: 2em;">
The conventional wisdom is that mathematics has always depended on
error-free logical argument, but this is not completely true. It is
quite easy to make mistakes with infinitesimals, infinite series,
continuity, differentiability, and so forth, and even possible to get
erroneous conclusions about triangles in Euclidean geometry. When
intuitive formulations are used, there are no reliable rule-based
ways to see these are wrong, so in practice ambiguity and mistakes
used to be resolved with external criteria, including testing against
accepted conclusions, feedback from authorities, and comparison with
physical reality.
(See <a href="http://www.ams.org/notices/201201/rtx120100031p.pdf"><i>A
Revolution in Mathematics?</i></a>, p31.)
</div>
<br>
The great revolution in mathematics, which took place from about 1890 to 1930,
was to replace intuitive concepts and
intuitive proofs with systems of explicit rules, like the rules of a
game, without worrying about what they "really" meant. To some people,
including philosophers and elite mathematicians with excellent
intuition, this seemed like a loss, but it brought with it an amazing
benefit: arguments based on consistent application of these rules led
to <b>completely reliable conclusions</b>. This meant that
mathematicians could build a much more complex edifice of rules and
proofs than would ever have been possible in the nineteenth century,
safe in the confidence that however complex, it was all still
correct. The new methods also opened up mathematics research to
ordinary mathematicians, not just to super-stars with extraordinary
intuition. Of course, constructing the required proofs still required
imagination and experience, but there was now a systematic way to
proceed when you got stuck:
<br>
<br>
<div style="margin-left: 2em;">
When someone reaches his personal limits of heuristic reasoning and
intuition, the reasons for failure are obscure and there is not much
that can be done about it. This is why advanced mathematics was
limited to a few extraordinary people up through the nineteenth
century, and why students feel stupid when they reach their limits
today. The great discovery of the early twentieth century was that
basing mathematics on disciplined reasoning rather than intuition
makes it accessible to ordinary people. When people reach the limits
of good basic logical skills then the failures are localized and can
usually be identified and fixed. There is a clear, though disciplined
and rigorous, way forward. Experts do eventually develop powerful
intuitions, but these can now be seen as a battery, charged by
thousands of hours of disciplined reasoning and refinement.
(See <a href="http://www.math.vt.edu/people/quinn/education/techkiller.pdf"><i>
Reform Mathematics Education ...</i></a>, p11.)
</div>
<br>
As programmers, we can recognise that debugging a proof under the
twentieth century mathematical regime is very much like debugging a
program: "failures are localized" and so, with disciplined reasoning,
"they can usually be identified and fixed". Twentieth century methods
are "error-displaying", in the sense that if a mathematical argument
produces a false conclusion, then it will be possible to find the
error, because the error will be in the mis-application of some
rule. Mistakes happen; potential proofs usually have errors, in the
same way that programs, when first written, usually have bugs. But if
the steps of a proof are set
out in precise detail (similar to the precise detail you need in a
computer program) then you will always be able to find exactly where a
rule was broken. This in turn will often suggest an alternative
approach or a fix that will mend the proof.
<br>
<br>
(And of course, another link with computing is that it's one thing to
define a system of rules, it's another thing to be sure of applying
them completely reliably, with no mistakes. How can you construct
social and physical systems which guarantee this, given only fallible
humans and unreliable physical artifacts? Nothing in the real world is
perfect. What custom and technique could in practice guarantee
complete reliability? Mathematicians have worked out their own answers
to that question, but that question is <i>exactly</i>
the concern of computer science! That question calls forth all of
computer science from low-level machine design, through compilers, operating
systems, programming and interaction design, to psychology and
organisation theory. It is scarcely co-incidence that the
mathematicians John von Neumann and Alan Turing were computer
pioneers. They wanted to see their method embodied in machinery.)
<br>
<br>
So, standard practice in modern "core" mathematics revolves around
systems of formal rules and the completely reliable conclusions that
people can draw from them.
What about mathematics education? In what sense is
it still using nineteenth century methods and why exactly is that bad?
<br>
<br>
With nineteenth century methods intuition is key, and
mathematics education has concentrated on intuitive
understanding first and skill at applying formal rules second (or
never). One problem with this is that <i>correct</i> intuition in
mathematics comes from working with rules and internalising
them. Trying to hand students an intuition first is very dangerous,
because they will often often get the <i>wrong</i> intuition, or just
be confused. And confusion is perhaps the better outcome, because
intuitions once gained can be very hard to change. Quinn cites
<a href="http://www.utsc.utoronto.ca/~dunbarlab/pubpdfs/dunbarTheoryData.pdf">
<i>Do naïve theories ever go away?</i></a> by Dunbar
et al. (in <i>Thinking with Data: 33rd Carnegie Symposium on
Cognition</i>, Ed. Lovett and Shah, 2007). The problem is that
subsequent
learning doesn't seem to actually <i>correct</i> an earlier
misunderstanding, it only modifies the misunderstanding:
"even when conceptual change appears to have taken place, students
still have access to the old naïve theories and ... these theories
appear to be actively inhibited rather than reorganized and absorbed
into the new theory" (Dunbar et al., 2007, p.202). A bad intuition is
dangerous because it is so sticky and difficult to change.
<br>
<br>
In the USA, with its popular "reform math" curriculum, this emphasis
on "understanding" has gone hand-in-hand with a drastic decline in
the practical abilities demanded of students at every level. Expertise
in disciplined reasoning, with careful step-by-step application of
formal rules, is seen by the nineteenth century educational
authorities as at best a secondary concern.
Since it is unimportant,
the authorities think it can be dropped with
no loss. But this is a mistake which has dire consequences. Quinn
comments that, as a university maths lecturer, he is responsible for
developing the math skills needed by engineering students. However:
<br>
<br>
<div style="margin-left: 2em;">
Our goals for student learning are set by what
it takes to deal effectively with the real world, and can't be
redefined. The problem is that, as compared with fixed real-world
goals, useful preparation of incoming students has been declining for
thirty years. The decline accelerated 10-15 years ago and the bottom
has almost dropped out in the last five years.
(See <a href="http://www.math.vt.edu/people/quinn/education/techkiller.pdf"><i>
Reform Mathematics Education ...</i></a>, p3, written in 2012.)
</div>
<br>
Since rigorous thinking is not emphasised by the educational
authorities, it is scarcely surprising that students have internalised
the principle that precision is not important. Quinn gives an example
of how this typically plays out on the ground:
<br>
<br>
<div style="margin-left: 2em;">
Recently a student came to try to get more partial credit. He had put
a plus instead of a comma in an expression, turning it from a vector
to a real number. "But there was an example that looked like this, and
anyway it is only one symbol and almost all the others are right." He
had never heard the words 'conceptual' and 'error' used together; it
made no sense to him and he would not accept it as a justification for
a bad grade. (See <a href="http://www.math.vt.edu/people/quinn/education/techkiller.pdf"><i>
Reform Mathematics Education ...</i></a>, p4.)
</div>
<br>
What, you might ask, has this got to do with learning to program
computers? Well, first of all, <i>these are the same people we are
trying to teach how to program!</i> Quinn's example is eerily similar to
the experiences I've had with some programming students, people who
seem unable to comprehend that complete precision is necessary. There
is such a gap of understanding that in many cases it seems impossible
to cross it. You can think that you have communicated, but then you
look at what they are doing later and you see that they didn't get it
at all. They are not working precisely to find their error.
They are still just superstitiously shuffling the symbols in
their program, hoping that they will hit the jackpot and their program
will appear to work.
<br>
<br>
What can we do? Maybe, if Quinn is right, not
much. Maybe for them the race is lost. Maybe we would have had to
start a decade or more earlier, with very different maths teaching in
school. And so, if we really think "everyone should learn to code",
maybe that's where we should start today, before it's too late.
<br>
<br>
Secondly, in programming education we may by chance have thrown the
baby out with the bathwater, just as the reform maths educators did
with calculators in schools. In the old days, before calculators,
children had to learn to do long multiplication, for example
431 × 27, using pencil and paper. This was a bit of a
chore, now largely dropped in favour of tapping the problem into a
calculator, which gets the answer more reliably. However, it turns out
that the children were learning a lot more by accident than how to
multiply long numbers. They were learning to set out their working in
an error-displaying form, essentially a twentieth century
proof that their answer was
correct. They had to be absolutely precise in their working, but if
they made a mistake, they could check their working, find the mistake
and correct it.
Their teachers could periodically take in this work and
confirm that their pupils were working accurately and
in a proper error-displaying
way. Not only all that, but children were intuitively learning something
about the mathematical structure of numbers by working with them, so
that when they came to polynomials they found that working out
(4<i>x</i>² + 3<i>x</i> + 1) × (2<i>x</i> + 7)
was not much different to working out 431 × 27. (In
fact it's a bit simpler, because there are fewer carries.) To someone
with a calculator, they are entirely different.
<br>
<br>
I wonder if, in the way we try to teach programming nowadays, we may have
fallen into some similar traps, by not realising what
students <i>accidentally</i>
learned in the past. For example — and here's a heretical
thought — are
languages with GOTO really as bad as we imagine for <i>novice</i>
programmers? Dijkstra claimed that "It is practically impossible to
teach good programming to students that have had a prior exposure to
BASIC: as potential programmers they are mentally mutilated beyond
hope of regeneration". But don't forget this was just a claim: where's
the evidence? Dijkstra
himself obviously first learned to program in a language with only
GOTOs, as I did, and I'm fairly happy that it did <i>us</i> no lasting
damage. In fact I think it forced us to think about our code
and to work with it in a particular detailed
way, and this earlier practice may have served us well later, even when
we programed in structured languages.
<br>
<br>
The question of whether structured languages are better later, for
expert coding, is not
the point. Clearly for doing sums, using a calculator is better later
than using pencil and paper. But for the reasons outlined above, it's
not better earlier. The question in either case should not be just
"can students do the old problems more reliably?". Of course students
with calculators
get the answer more reliably than students without, but they don't
learn those other early skills which support <i>future</i>
learning. Could this, perhaps, be the case with us too? (Although this
view is far from mainstream, I am relieved that I'm not the only
person to suggest
it. See <a href="http://reprog.wordpress.com/2010/03/09/where-dijkstra-went-wrong-the-value-of-basic-as-a-first-programming-language/">Where
Dijkstra went wrong: the value of BASIC as a first programming language</a>.)
<br>
<br>
And finally, whether we are computer scientists promoting "computational
thinking" or core mathematicians promoting twentieth century methods,
it strikes me that we actually want the same thing. Perhaps
we should make common cause. The easiest way to save core mathematics
might be through computer science. After all, since the mathematicians
did us the favour of founding our discipline, the least we could do in
return would be to help them save theirs.
<br>
<br>
<i>
(There's lots more interesting stuff on
<a href="http://www.math.vt.edu/people/quinn/education/index.html">Frank
Quinn's education webpage</a>. Well worth a read.)</i>
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com6tag:blogger.com,1999:blog-7962217619208800961.post-31723023384665796182013-04-21T09:46:00.000+01:002013-04-21T09:46:28.592+01:00Three Good QuestionsGood questions are important. It's often fairly straightforward to
find a good answer, if you're given a good question. It's a lot
harder to find a good question, given nothing.
Over years of doing system design, I found three "meta" questions
particularly useful.
These have sometimes helped me to imagine things
that might go wrong during the construction or operation of a system.
Maybe they could help you too.
<br>
<br>
I was reminded of these "meta" questions by an email from Aaron Sloman
following my post on
<a href="http://onfoodandcoding.blogspot.co.uk/2013/03/learning-to-program.html">Learning
to Program</a>. He said:
<br>
<br>
<div style="margin-left: 2em;">
"I could have added that I noticed something different when teaching
philosophy. Doing conceptual analysis well requires
the ability to dredge out of your vast store of knowledge examples
that illustrate, test or refute, some concept, distinction, or
thesis.
<br>
<br>
"I found over many years of teaching that I could teach some students
to produce examples merely by doing it myself in discussions:
they somehow got the idea and were able to do something similar.
With other students they seemed to lack the ability to access their
long-term memory in an appropriate way, and I was not able to think
up a way of teaching them that helped them to develop that ability. I
suspect this is related to the ability to do well in the Jeopardy
game, but is more complicated, and less a matter of speed.
<br>
<br>
"More importantly it may also be related to some high level
requirements for being a good system designer: too often systems are
designed with flaws that the designer should have noticed without
waiting for users to discover them. That requires the ability to
trawl through what you already know, and I fear some
designers are very bad at that, and design bad systems."
</div>
<br>
So maybe my Three Good Questions help me to "trawl
through what I already know", and to imagine what might be. Anyway,
here are the questions:
<br>
<ul>
<li>
<b>Does it scale?</b>
Usually it doesn't. When you take a prototype system
that works fine in the lab and try to scale it up, you almost always
run into problems. Sometimes these are latency or bandwidth problems.
(A system which works fine in the lab on a lightly loaded local-area
network is going to feel very different to users on a congested
wide-area network.) Sometimes there are problems with algorithms that
have unfortunate growth characteristics. There might even be an
accidental reliance on particular people who are available to make the
prototype system work, but who will not be available in a larger
deployed system. (For example, I am suspicious that the currently over-hyped
"Massively Open Online Courseware" will fail to scale in exactly this way.)
There are lots of ways that a small system can fail to scale and only
one of them has to be true for it to be a fatal problem
for <i>your</i> system.
</li>
<br>
<li>
<b>Does it have a start-of-day problem? </b>
A "start-of-day problem" is a familiar concept to system designers,
but it is not a term in everyday use. A system has a start-of-day problem
if it can reproduce itself once it exists, or keep itself going when
it is going, but which needs an entirely different mechanism to start
it going from nothing. For example, think of the problem of
powering-up a ship from nothing. When its main engines are running,
electricity comes from generators driven by those engines. (In some
ships like the QM2, that's actually all that the main engines do: power
transmission to the propellers is entirely electric.) However, the
control systems and starter motors for the main engines need electricity to
work. What provides that electricity if the main engines are not
already going? This is a start-of-day problem, and it is solved in
this case by having auxiliary generators to provide that electric power.
(But they themselves have their own start-of-day problem, and they need to be
provided with further mechanisms to start <i>them</i> from cold ...)
We see this problem over and over in system design. For example, it is
traditional to write compilers in their own language. But in that case
how do you compile the first compiler for that language? (By
having a bootstrap compiler written in something else, that you run
once then never need again.)
</li>
<br>
<li>
<b>What are the security implications? </b>
If we are doing system design properly, then we think about security
all the way through, not just at the end. We think about
exactly <i>what</i> security guarantees we are going to provide and to
whom. We think about the traditional security properties of
Confidentiality, Integrity and Availability (and maybe a few
others). But this question is asking you to go a step further, and to
consider the unintended consequences which might result from
<i>correctly</i>
implementing the security guarantees that you think you want. For
example, to prevent an online password-guessing attack, it's usual to
lock-out an account after, say, three wrong attempts. That's great for
confidentiality, because a locked-out attacker can't now get access
to your data. However, the unintended consequence is that neither can
you! The lock-out mechanism which delivers better confidentially has
also delivered worse availability: if all the attacker in fact wanted
was a denial-of-service attack, you have handed it to him on a plate.
</li>
</ul>
As I have been writing this, it struck me that the idea of trying to
produce a counter-example is also very strong technique in system
design. To phrase
this as a "meta" question, we might say: <b>If you think it can't work,
can you <i>prove</i> it can't work?</b> Sometimes by trying (and
failing) to prove that it can never work, you can actually solve the original
problem. For example, I was once working on a project with an
apparently insurmountable architectural problem. If we couldn't solve
it, the project we were working on would almost certainly be closed
down. We'd been trying to solve it for a couple of months, but with no
success. So one Friday afternoon, I decided to finally put the issue to
rest and I tried to prove to a couple of colleagues that a solution
was impossible. I didn't manage to do that, because over the space of
about an hour, by trying to construct that proof I was finally
able to find a solution to our problem.
<br>
<br>
System design is always an exercise in imagination.
We often know the answer, but we don't know that we know it because we
need someone to ask the right question, a useful and productive
question which calls forth the answer in a flash of insight.
Good system designers distinguish
themselves by being able to ask exactly those fruitful and
productive questions. Can you teach that? I'm not sure.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-78192567776199028052013-04-14T09:34:00.000+01:002013-04-14T09:34:53.034+01:00Some Useful ThingsLittle things can sometimes make a big difference. Here are a few
things that I've found useful.
<br>
<br>
<b>Food: Kuhn Rikon Epicurean Garlic Press</b>
<br>
<br>
If you are going to use a garlic press, then this is the one to
pick. It's heavy duty, made from stainless steel. It's probably the best
garlic press in the world. To see a demo, have a look at
<a href="http://www.youtube.com/watch?v=1RyfVmTcJUo">America's Test
Kitchen Equipment Review: Garlic Press</a> where they come to the
same conclusion and show off this little device.
(Kuhn Rikon have another garlic press called the Easy Squeeze, which
is a lot cheaper. It has a slightly different action and plastic
handles. It's not nearly as good.)
<br>
<br>
Of course, if you are being macho you can just crush garlic with a
kitchen knife. For example
see <a href="http://www.youtube.com/watch?v=gvBjK9Q5Sg4">this YouTube
video</a>.
(Though the cook in this video makes a bit of a performance of removing
the skin. The trick is to just trim off the ends of the garlic first
with a knife, like you would while topping-and-tailing mange-tout
peas. Then use the flat of your knife and gently lean your whole
weight on the garlic until it just goes "click!". You can then just
peel off the whole of the skin in one go rather than tediously picking
pieces of skin out of the mashed up garlic.)
<br>
<br>
<b>Coding: redemo.py</b>
<br>
<br>
This little Python GUI program is endlessly useful when you find yourself
tweaking a regular expression to make it parse your data correctly. In
fact I would nowadays usually start by copying some of my example data
into redemo.py's
input box and then start writing my regular expression directly into its regexp
box. That way I can check as I go along that the regexp is doing what I
want, and when I make a mistake I'll get immediate feedback. (Redemo.py
highlights the data that currently matches, reacting
character-by-character as you change the data or
the regexp.) When you get your regexp to work, you can just copy
it straight into the
program that's going to use it. And you're finished.
<br>
<br>
(On Windows, you can find redemo.py in the standard Python distribution, under
<i>Tools/scripts</i> or <i>Tools/demo</i> depending on the version you
are using. However, on Ubuntu Linux you have to <i>sudo apt-get install
python-examples</i> or
<i>python3-examples</i>, then find the mysterious place where it's
been hidden, using say <i>find /usr -type f -name redemo.py</i>.
Worth the effort
though.)
<br>
<br>
<b>Food: Star Anise</b>
<br>
<br>
This is a useful ingredient that you might not think of adding to meat
dishes. (I use it in my
<a href="http://onfoodandcoding.blogspot.co.uk/2013/03/recipe-yet-another-chilli.html">chilli
recipe</a>.)
Obviously star anise plays a big part in Chinese cooking — it's
one of the five spices — but it's less common in Western
cooking. But as Harold McGee says
in <a href="http://www.amazon.co.uk/dp/0340831499">McGee on Food and
Cooking</a>, when you cook star anise with onions "the result is the
production of sulfur-phenolic aromatics that intensify the meatiness
of the dish." (p430)
<br>
<br>
<b>Coding: Inconsolata font</b>
<br>
<br>
Earlier this year I switched
to <a href="http://en.wikipedia.org/wiki/Inconsolata">Inconsolata</a>
for all my program editing, command shells and so on. It's not a huge
change, but I think it's just a bit nicer than the alternatives. For
example you get a zero with a slash though it, easily distinguishable
from an uppercase letter "O", and you can quite easily tell the difference
between numeral one, lowercase "L" and uppercase "I".
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-47322587148724243872013-04-07T09:58:00.000+01:002013-04-07T09:58:16.595+01:00Why are variables so confusing?(This post is a follow-up
to <a href="http://onfoodandcoding.blogspot.co.uk/2013/03/learning-to-program.html">Learning
to Program</a>.)
<br />
<br />
For many people, the first stumbling block when they are learning to
program is that they find variables very confusing. Why is this?
<br />
<br />
It doesn't seem quite so surprising that novice programmers find functions
and objects hard to understand.
(These topics seem to form the next two major
stumbling blocks for novice programmers.)
Functions and objects both draw on an understanding of abstraction, and
the idea of abstraction seems to be hard for some people to grasp;
they seem to find it difficult, when presented with particular examples
of abstraction, to understand that these are all illustrations of the same
general concept. It's as though you need to already understand
abstraction before you can see it in the examples.
<br />
<br />
So, functions and objects seem like major ideas, but ... variables?
Why is it so difficult to use variables?
To expert programmers, variables seem entirely
obvious. It's really hard to see what the problem is. I'd like to
suggest a possible explanation, which is that the novices tend to
confuse one variable with another because they are
suffering from a short-term memory overload. Maybe novices can only
hold one or two variables in mind as they think about their program.
<br />
<br />
At first it seems unlikely that this could be the case. We all
know about George Miller's seminal paper
<a href="http://www.musanim.com/miller1956/"><i>The Magical Number
Seven, Plus or Minus Two: Some Limits on Our Capacity for
Processing Information</i></a>
(Psychological Review, 1956, vol 63, pp81-97).
We expect our
short-term memory to be able to hold around five to nine
"things" before we start confusing or forgetting them.
But that number depends upon how easily we recognise the
things, based on "categorical" knowledge from our long-term memory. If
we don't have that knowledge, then all the things tend to look similar,
and the number we can hold in short-term memory can be a
lot less. It can be as low as only <i>one</i> thing!
<br />
<br />
For example, Henrik Olsson and Leo Poom, in their paper
<a href="http://www.pnas.org/content/102/24/8776.full.pdf"><i>Visual
memory needs categories</i></a> (PNAS, 2005, 102(24), pp8776-8780),
describe experiments in which they presented their subjects with visual
patterns which were easy to distinguish when viewed side-by-side, but
which were confusing when viewed one after another because they were
drawn from
the same categories. (For example, differently oriented ovals within
ovals.)
They found that for these kinds of
patterns, the subjects' short-term
visual memory could only hold one thing: the last thing they saw.
This was quite a surprise to the participants in the experiment, who
expected to be able to do a lot better than that.
<br />
<br />
This kind of confusion is not restricted to visual memory.
A similar effect is described by
Malcolm Gladwell in his book
<a href="http://www.amazon.co.uk/dp/0141014598"><i>Blink</i></a>:
<br />
<br />
<div style="margin-left: 2em;">
"Have a friend pour Pepsi into one glass and Coke into another and try
to tell them apart. Let's say you succeed. Congratulations. Now, let's
try the test again, in a slightly different form. This time have your
tester give you <i>three</i> glasses, two of which are filled with one
of the Colas and the third with the other. In the beverage business,
this is called a triangle test. This time around, I don't want you to
identify which is Coke and which is Pepsi. All I want you to say is
which of the three drinks is not like the other two. Believe it or
not, you will find this task incredibly hard. If a thousand people
were to try this test, just over one-third would guess right —
which is not much better than chance; we might as well guess."
(<i>Blink</i>, p185.)
</div>
<br />
Unless you are an expert taster, unless you have practiced and have
the categorical knowledge in your long-term memory which lets you
recognise and distinguish these different tastes, your short-term memory
only holds one thing, only one taste, the last thing you tasted. And
we don't expect that.
<br />
<br />
So what I'm suggesting is that a similar effect might happen with variables
in programs. When experts look at variables, they are applying
categorical knowledge from their long-term memory. They recognise how
variables are used and what their purpose is in the program. They
recognise what each variable is <i>for</i>.
Experts choose much better names for variables than novices.
When an expert chooses a
name for a variable, they tend to choose a name which reflects the
purpose of the variable. Given a poorly written program, when an
expert has understood it, one thing they will certainly do is to
choose better names for the variables.
<br />
<br />
Novices, on the other hand, don't do any of this. They can't. They
don't have the categorical knowledge in their long-term memory about
patterns of variable use. Of course, they can tell one variable from
another, just like people can tell Pepsi from Coke. But if I'm right,
they will find
it extremely hard to understand programs which require them to hold in
their mind more than just a single previous variable. We might
therefore expect that <b>x = x + y</b> would be
just on the limit of understanding for a novice. (There are two
variables, but <b>x</b> actually means two
different things on each side of the assignment, which might push it
over the edge.)
<br />
<br />
If novice programmers cannot understand their programs because they
cannot intuitively distinguish variables, this might explain some
otherwise mysterious features of their code. For example, I'm sure I'm
not the first programming teacher to notice the remarkable enthusiasm
of novices for inventing new variables and scattering their code with
redundant assignments, as if they hope that one more might do the
trick and make their program work. (And by accident, it sometimes
does.) It might also partly explain a frequent misunderstanding when
we come to functions and objects: the idea that every variable with
the same name is actually the same variable. (As experts we have no
problem with the idea that we can use the same name for local
variables in different functions, even ones that call one-another. Or
that <b>this</b> or <b>self</b> in a method is different when invoked
on different objects. But if novices have to fall back on merely
comparing the textual names of variables, they are bound to be
confused when they try to reason about different variables that happen
to have the same name.)
<br />
<br />
Of course, without
intuitive understanding, many novice programmers would just give up,
and many do.
However, if they persist, after a while novices will start to unconsciously
pick up the
long-term categorical knowledge that they need. (Or at least those who
are ultimately
successful must do this.)
But rather than leaving this to chance, there are some
things we can do to help them
on their way: we can at least try to
explicitly teach some categorical knowledge about variables
through worked examples. I have
found that explaining
the <a href="http://www.cs.joensuu.fi/~saja/var_roles/">roles of
variables</a> seems to help a lot. (But just talking about roles is
not quite enough, you have to get students to engage more and to
practice describing the roles of variables in example programs and in
their own programs.)Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com1tag:blogger.com,1999:blog-7962217619208800961.post-53812937803383667802013-03-31T12:25:00.001+01:002013-03-31T12:25:51.076+01:00Recipe: Aubergines stuffed with chickpeasOnly after I wrote this up did I notice a very weak and accidental
pun: this is a recipe for <i>Egg</i> Plant, and today is Easter.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">3 </td><td>Aubergines, about 20cm long</td></tr>
<tr><td> </td><td>Lots of salt</td></tr>
<tr><td> </td></tr>
<tr><td>5t </td><td>Extra virgin olive oil</td></tr>
<tr><td>1 </td><td>Onion, chopped (about 150g)</td></tr>
<tr><td>4 </td><td>Cloves garlic, crushed</td></tr>
<tr><td> </td></tr>
<tr><td>400g </td><td>Tinned tomatoes</td></tr>
<tr><td>400g </td><td>Tinned chickpeas</td></tr>
<tr><td></td><td>(preferably in plain water, drained weight = 250g)</td></tr>
<tr><td>60g </td><td>Fresh coriander leaf, chopped fine</td></tr>
<tr><td>2T </td><td>Tomato purée</td></tr>
<tr><td>3T </td><td>Lemon juice</td></tr>
<tr><td>1t </td><td>Salt</td></tr>
<tr><td> </td><td>Ground black pepper, to taste)</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Cut the aubergines in half and slice out the insides. Leave as little
flesh as you can manage on the skins, but make sure the skins are
still intact. Put the skins
into a colander and liberally sprinkle with salt. Then chop up the
inside flesh into pieces less than 1cm and put them in the colander too,
sprinkling them with salt as you go. The salt draws out the
bitter taste from the aubergines by osmosis, so leave the colander in
the sink or on the draining board to drip while this happens. It takes
about half-an-hour.
<br />
<br />
Thoroughly rinse the salt off the aubergine, then dry it off. (I
would usually pat the skins dry with kitchen paper and centrifuge the
inside flesh in a salad-spinner.) Fry the skins in the olive oil for a
minute or two on each side so that they soften, then lay them them in a
baking tin to fill with the rest of the mixture later.
<br />
<br />
Preheat oven to 200°C (= gas mark 6 = 400°F).
<br />
<br />
Peel and chop the onion. Crush the garlic.
Fry the onion and garlic for 5 minutes or so, until brown. (You may
need to add more olive oil to the pan: the aubergine skins tend to
suck it up.)
<br />
<br />
Add the aubergine flesh to the pan and cook for another 5 minutes.
<br />
<br />
Drain the tomatoes and slice them up (about 5mm thick slices). Add
them to the pan.
<br />
<br />
Drain the chickpeas and rinse them off in the colander. Add them to the
pan.
<br />
<br />
Add the chopped fresh coriander, the tomato purée, lemon juice, salt
and pepper to the pan. Heat the mixture until it is bubbling.
<br />
<br />
Pile the mixture into the aubergine skins and cook in the oven for 30
minutes at 200°C (= gas mark 6 = 400°F).
<br />
<br />
<b>Discussion</b>
<br />
<br />
This recipe is improved by using <i>fresh</i> tomatoes rather than
tinned: remove their skin the usual way using boiling water, then
slice them into 5mm slices sideways. However, that takes the overall
effort just over the edge of what I can be bothered to do, so I tend
to just use tinned tomatoes instead.Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-35926256446451755182013-03-24T09:11:00.000+00:002013-03-24T09:11:19.627+00:00Write-me-a-program(This post is a follow-up
to <a href="http://onfoodandcoding.blogspot.co.uk/2013/03/learning-to-program.html">Learning
to Program</a>.)
<br />
<br />
I'd like to describe a particular teaching technique that has worked
well for me, which I'll call "write-me-a-program". The first time I
tried this, I guess the planets were aligned and it worked
brilliantly. I was so bowled over that I had to call in a colleague,
to show them how much fun we were having. (It's not always
worked out quite so well, but it's worked pretty well and I've used it
for both Python and SQL teaching.)
It's a small-class technique: good for 15-20
students, and I think it would work as well for up to 30. Like a magic
trick, I think that the precise details are important, so I'll try to
give the recipe in sufficient detail that you can replicate it
yourself.
But first I'll give some background, which might be more interesting
than the recipe itself, especially if you don't intend to use the
recipe.
<br />
<br />
When I came up with the "write-me-a-program" idea, I wanted something
that used the "assertive questioning" classroom technique
along with a
sequence of questions that had something of the flavour
of <a href="http://www.michelthomas.com/">Michel Thomas'</a> language
courses, one question building on another, using spacing for reinforcement.
If you don't know about spacing, it's a very good way
to reinforce learning: rather than repeating the same
material immediately, or after a long time, it works best to come back
to it at short intervals, with other material in between. Spacing
has been known about for well over 100 years, but it's been used
very patchily. See for example: <i>The spacing effect: A case study in
the failure to apply the results of psychological research</i> by
Frank Dempster (American Psychologist, Vol 43(8), August 1988, pp627-634).
<br />
<br />
Michel Thomas' language courses are the best examples of spacing I
know, and they take a distinctly different approach to most language
courses. The worst of those make their students remember disconnected
phrases which, if they manage to recall them at all, are not very
useful in everyday life. See
for example <a href="www.youtube.co.uk/watch?v=x1sQkEfAdfY">Eddie
Izzard's comments on learning French</a>
from his show <i>Dress to Kill</i>. (He complains that his school textbook
contained things which were "difficult to get into conversation,
things like: 'The mouse is underneath the table' ".)
<br />
<br />
In contrast, Michel Thomas doesn't give you phrases to memorise. In
fact he insists that you don't <i>try</i> to memorise the
material. Instead he builds tiny piece on tiny piece and asks you to
make, in real-time, translations of increasingly complicated phrases
built from these simple pieces. Worked examples are extended and extended,
earlier material is incorporated with the new, folded together and
repeated with variations. As David Sedaris notes in <i>Easy Tiger: Language
Lessons on the Road</i> (New Yorker, 11 July 2011), after only a few
minutes you graduate from "Give it to me", via "I would like for you
to give it to me" to "I can't give it to you today, because I cannot
find it". This is a long way from "The mouse is underneath the
table". And much better practice for saying genuinely useful things in
real life. As Sedaris says, "You're engaging with another language,
not just parroting it."
<br />
<br />
So I wanted questions that built in the same way, and placed similar
demands on the students. What I describe here is only part way to that
objective, but the feedback that I've had from students has been good
and we've mostly all had fun. Hopefully you can improve on what I've got
here. Let me know! (Oh, and you might also try out
a <a href="http://www.michelthomas.com/">Michel Thomas</a> language
course, if only to experience first-hand the feel of his method.) Here's my
recipe for my write-me-a-program technique:
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
A class of students, not too big. <br />
A computer with a projector. <br />
A set of slides (in e.g. Powerpoint) with the questions, one per slide.<br />
(See end of this post for an <a href="#questions">example set of
questions</a> on Python.) <br />
Printed handouts with all questions + answers.<br />
(N.B. <i>Don't hand out these until the END.</i>)<br />
A whiteboard with pens.<br />
Jotting paper/pens for the students.
</div>
<br />
<b>Method</b>
<br />
<br />
First explain to the class that the lesson is going to be a quiz, with
students divided into teams. The best size for a team is three people
(four is okay) so get the students to divide themselves up. However,
you need to avoid having all the slowest students on one team. It's also
better if the fastest students are spread across different teams. If you feel
that you can simply order the students to join different teams, then
you can sort out any problems afterwards. Otherwise, it might be
better to use some kind of lottery to divide the students into groups, and
rely on randomness to even things out. Students never object to that.
<br />
<br />
Explain to the students that they will each need paper and a pen. (And
wait until they have sorted this out.)
<br />
<br />
Next explain to the students what is going to happen: "I am going to
show you a question on the computer projector. The question will ask
you to write a few lines of program. Each of you will do this on your
own. Do your best and don't copy from your team-mates. I'll give you a
minute or two for this, then I'll ask you to compare your answer
with the ones that your team-mates have written. Try between you to
make the best answer you can. I'll give you a couple of minutes for
that, then I will pick one person to come to the front and write on
the whiteboard their team's best answer."
<br />
<br />
Put up the slide with the first question. I think it's best if this
first question is really trivial, so no-one will have any problem
answering it. That way you can at first concentrate on getting the
<i>process</i> right. For example, an opening Python programming
question might be:
<br />
<br />
<div style="margin-left: 2em;">
Make variable <b>i</b> have value <b>5</b>.
</div>
<br />
Remind the students to write their own answer, don't copy their team
mates. Also tell the students not to bother writing the question
down. Show them your stack of handouts with questions and
answers. "Just concentrate on thinking of your answer and writing it
down. I'm going to hand these out at the end."
(I find that some students seem to use copying down the
question as a displacement activity, so they can look busy when they can't
think what to do. Some of the later questions are much longer and
copying is a waste of their time. They'll still do it, though, if you
don't explicitly tell them not to.)
<br />
<br />
With this simple first question, writing down the answer
should take about 10
seconds, but for some of the later questions people will need a minute
or two. It's worth reminding the students that you want them to practice
answering the questions out of their own head, not by searching
through notes or books. "This is practice at doing programming, and
you practice doing by trying. Don't worry if you can't quite remember
something. Try work it out, and do what you can. But don't go looking
things up."
<br />
<br />
There's a point when most of the students are clearly
finished, but not all. Leave them a bit longer, then tell the students
to now compare their answers with their team-mates and together to
work out their best answer. The precise point to do this is important,
but difficult to describe. It's a bit like in a recipe where it says
"cook until it's done". You don't want to wait for absolutely everyone
to finish, because the faster students will be bored and frustrated,
and the slower ones just embarrassed. But equally, you don't want to cut
students off who are in the middle of writing something, because this
is one point where they are certainly <i>learning</i>, as they practice
pulling information out of their own brains. (After a few questions,
you'll probably find that the faster groups start to quietly confer
when they have all finished, and I think this is ok, but it's one
reason for not wanting all the faster students on one team.)
<br />
<br />
You then need to give the teams of students time to discuss their
answers. For the simple first question this is perhaps only 10
seconds, but for the later questions it will be at least a couple of
minutes, maybe longer. Again, there's a point where most teams seem to
have reached a common verdict, maybe signalled by a lull in the
chatter. Leave it just a moment longer, then select one student from
the class to come to the front and write their team's answer on the
whiteboard. (I would usually walk to them and hand them the whiteboard
marker, while they are in their seat.)
<br />
<br />
They might want to bring their notes, or just write from memory,
either way is fine. While they are writing on the whiteboard, stand to
one side, and when they have finished take back the whiteboard marker
and say "Thank you". (I think that's important.) It's possible that as
they are writing, one of their team-mates will call out a
correction. This is fine. Don't correct them yourself, though.
If they have a minor query, you
can answer that, but if they try to recruit you into co-writing the
answer, just say "Write down what you've got and we'll see if we can
improve it."
<br />
<br />
The student returns to their seat, and you now ask the class "Can we
improve this in any way?" (Again, I think the precise choice of words
is important. You need to show that you are respecting the effort
that's gone into this attempt, but you want the whole class, if they
can, to make it better.) Exactly how to play this next depends on the
question and the answer. Maybe it's perfect, but even so you want to
give the class a chance to come to that conclusion for
themselves. This part of the process becomes a sort of communal
code-inspection.
<br />
<br />
Usually, there are some "typos". In Python there's often an
an opportunity for the "colon police" to call out the location of
missing colons (a frequent mistake). If a student has a simple
suggestion, you can write it on the board. If it's complex (maybe a
whole different way to answer the question) you can get them to come up
and write it themselves. Perhaps a student can see that the answer
isn't going to work, but they are not sure how to mend
it themselves. That's still a valuable contribution.
<br />
<br />
If there are no more suggestions, you might go on to ask "Does our answer
do what the question
asks?" If you see that there's a problem, this phrasing deflects the
blame from the original student's attempt to "<i>our</i> answer". But you can
still ask this even if the answer is right. (Make the students
think!) When you see that something has been misunderstood, take the
opportunity
to explain how it actually works. (But if you find you are doing that
a lot, probably the questions are too hard for this class.)
Note that in all this we are using a
computer only as a slide-projector, to show the question, which is in
view the whole time. Everything else is hand-written.
<br />
<br />
When you've got an answer that works ok, leave it on the whiteboard
and go on to the next question, with the same drill.
(Since the questions build on one-another, it's often the case that
the answer gives a strong hint on how to do the next question. The
problem for the students becomes how to <i>change</i> that answer.)
Select students from around the class to write at the whiteboard in a
way which appears fair and which is sufficiently random. (In order to
maintain the feeling in students that "It could be me".)
<br />
<br />
See the end of this post for a collection of <a href="#questions">Python
questions</a> that have worked well for me.
<br />
<br />
<b>Discussion</b>
<br />
<br />
The students must already have been taken through worked examples of
the material
covered in the questions, and sufficiently recently that they have adequate
recall. It's vital to choose questions at just the right level. Too
easy is better than too hard, because there's a certain pace that has
to be maintained, building from
one question on to the next.
<br />
<br />
It's ok to introduce a slight twist
on material that students already know, but it doesn't work if you
have to break off and introduce a lot of new material,
particularly if it's actually only new to some of the
students. For me, write-me-a-program has worked best as a way to
confirm and reinforce learning in combination with lab-sessions (where
students work though examples and problems in pairs) and small
programming assignments (where students feel there is some pay-off to
knowing how to write code, so they have made some effort out of
class).
<br />
<br />
Where this technique has worked less well for me, I think that it was
because there was too much disparity between the fastest and slowest
students, or because I over-estimated what the students as a whole
were capable of doing.
<br />
<br />
<b>Example set of questions</b>
<br />
<br />
Here's a set of questions which I've used when teaching Python. I've
found that going through this set takes about 3 hours in total. You
might reasonably say that "If your students can do these questions,
then you have no problems". Quite! But see how
the questions build upon each other, and how they
repeatedly call upon earlier material in the answers to later
questions.
<a name="questions"> </a>
<ol>
<li> Make variable <b>a</b> have value <b>5</b>. </li>
<li> Write an <b>if</b> statement that prints <b>"too big"</b> if
variable <b>a</b> has a value more than <b>99</b>, and otherwise
does nothing.</li>
<li> Increment variable <b>i</b> by <b>1</b>.</li>
<li> Use a <b>while</b> loop to print all the integers from <b>1</b>
to <b>99</b>.</li>
<li> Print the <span style="text-decoration:underline;">odd</span>
numbers from <b>1</b> to <b>101</b>.</li>
<li> Define a function <b>odds()</b> which prints the odd numbers from <b>1</b>
to <b>101</b>.</li>
<li> Define a function <b>odds1(x)</b> which prints the odd numbers
from <b>1</b> to <b>x</b>.</li>
<li> Define a function <b>sum_odds(x)</b> which prints the sum of the
odd numbers from <b>1</b> to <b>x</b>.</li>
<li> Define a function <b>sum_odds1(x)</b>
which <span style="text-decoration:underline;">returns</span> the
sum of the odd numbers from <b>1</b> to <b>x</b>. (And does not
print anything.)</li>
<li> Make variable <b>q</b> have as its value the empty list. </li>
<li> Append the integer <b>5</b> to the list <b>q</b>. Print <b>q</b>.
(What <span style="text-decoration:underline;">exactly</span> is
printed?)</li>
<li> Define a function <b>odds_list(x)</b>
which <span style="text-decoration:underline;">returns a
list</span> odd numbers from <b>1</b> to <b>x</b>. (And does not
print anything.)</li>
<li> You are given a function<b>prime</b> which takes an integer
and returns <b>True</b> if it that integer is a prime number
and <b>False</b> otherwise.<br />
Define a function <b>prime_list(x)</b> which
<span style="text-decoration:underline;">returns</span> a list of
all the prime numbers from 2 to <b>x</b>. (And does not
print anything.)</li>
<li> Use the <b>range</b> function to write an expression whose value
is the list <b>[0, 1, 2, 3, 4, 5, 6, 7]</b>.</li>
<li> Use the <b>range</b> function to write an expression whose value
is the list <b>[1, 2, 3, 4, 5, 6, 7, 8]</b>.</li>
<li> Use the <b>range</b> function to and a <b>for</b> loop to print
the integers from <b>1</b> to <b>99</b>.</li>
<li> Use your earlier <b>prime_list</b> function and a <b>for</b> loop
to print all the primes from <b>1</b> to <b>999</b>.</li>
<li> The built-in <b>sum</b> function takes a list and returns the sum
of its elements.<br />
Use the built-in <b>sum</b> function to print the sum of the
integers from <b>1</b> to <b>99</b>.</li>
<li> Print the sum of the primes from <b>1</b> to <b>999</b>.</li>
<li> Define a function <b>vertical(s)</b> which uses
a <b>for</b> loop to print the characters of the string <b>s</b>,
one per line.</li>
<li> The built-in <b>ord</b> function takes a single-character string
and returns the integer which is its Unicode code.<br />
Define a function <b>codes(s)</b> which uses a <b>for</b> loop to
print the Unicode codes of the characters in the string <b>s</b>,
one per line.</li>
<li> Define a function <b>code_list(s)</b> which
<span style="text-decoration:underline;">returns</span> a list
containing the Unicode codes for each character in the
string <b>s</b>.</li>
<li> Print the sum of the Unicode codes of the characters in the
string <b>"hello world"</b>.</li>
</ol>
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com1tag:blogger.com,1999:blog-7962217619208800961.post-60149258482550880192013-03-18T16:41:00.000+00:002013-06-04T09:08:59.595+01:00Recipe: Fish ChowderThis is a very chunky soup, a meal in itself.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">500g </td><td>White fish fillet, in 2cm cubes</td></tr>
<tr><td>8-10 </td><td>Cellery stalks, diced</td></tr>
<tr><td>8-10 </td><td>Spring onions, chopped</td></tr>
<tr><td>400ml </td><td>Brown chicken stock (see
<a href="http://onfoodandcoding.blogspot.co.uk/2013/03/recipe-yet-another-chilli.html#brown-stock">here</a>
for this component)</td></tr>
<tr><td>250ml </td><td>Double cream</td></tr>
<tr><td>1t </td><td>Salt</td></tr>
<tr><td> </td><td>Ground black pepper (to taste)</td></tr>
<tr><td>pinch </td><td>Grated nutmeg (optional)</td></tr>
<tr><td colspan=2>
(1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Put the stock and the diced cellery into a saucepan.
Add the salt and pepper. (I like about 10 turns from
our pepper-mill, which makes about 1/10 of a teaspoon of ground
pepper.) Cover and simmer gently for 50 minutes.
<br />
<br />
Add the double cream and chopped spring onion to the pan, turn the heat to high
and bring to a rolling boil. Now add the fish and cook for a further 2
minutes, stiring very gently. (Stop when the fish is cooked: you can tell
because it changes colour to an opaque white.)
<br />
<br />
If you want to add the pinch of grated nutmeg, stir that in just
before you serve.
<br />
<br />
<b>Discussion</b>
<br />
<br />
A teaspoon of salt may seem like a lot, but salt probably isn't as
bad for you as you have been led to believe. The evidence is
distinctly mixed. Eating more salt may or may not increase your blood
pressure. We really don't know. But there <i>is</i> evidence that
eating more salt makes you <i>less</i> likely to die. (Yes, that's
right: <i>less</i> likely!
See <a href="http://www.scientificamerican.com/article.cfm?id=what-science-on-hypertension-really-shows">Open
Season on Salt: What the Science on Hypertension Really Shows</a>.)
<br />
<br />
Cod is really the fish of choice for this recipe. Using other white
fish the recipe comes out nearly, but not quite as good.
(Cod used to be so plentiful, and now it's sadly nearly wiped out.
There's a lesson for us here about pretend science and real science: listen to what
<a href="http://www.deanbavington.org/">Dean
Bavington</a> has to say about
the <a href="http://www.cbc.ca/ideas/episodes/2009/01/02/how-to-think-about-science-part-1---24-listen/#episode13">Newfoundland fishery</a>.)
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-418928591660744652013-03-10T13:42:00.000+00:002013-03-10T13:42:48.608+00:00Learning to Program
The time has come, I think, to talk about learning to write programs,
and about how we can help people to learn. If you have
ever tried to teach people how to program, you will know that it comes
very easily to some people, and ... I want to say "slowly to others",
but really I should tell the truth and say "not at all to others". Or
at least that's often how it seems.
<br />
<br />
Do you remember when you first learned to program? If you are like me,
it came very easily. I remember sitting at home one weekend reading in
fascination the <i>ICL BASIC Pocket Edition</i>, then rearranging my
A-level physics practicals so that I could be there at the booked
times and use the school's dial-up terminal to run my code on some distant
mainframe. I learned Fortran from McCracken's <i>A Guide to Fortran IV
Programming</i>, and APL from from an <i>APL\1130 Primer</i> that I
begged from IBM. (Though it was a couple of years before I actually
came in contact with a machine where I could use that arcane knowledge.)
In my first year at university, before I officially started studying
computing, I learned BCPL, Z80 assembler and Algol68.
<br />
<br />
Now for you, the precise list of technologies is probably different,
but I bet the outline is the same. It came very easily. You mostly
taught yourself. It was fascinating, addictive even. Like building a
machine out of Mechano parts, all perfect. Like giving
instructions to a magic genie, or writing the rules for a game that
played itself. Surely anyone could do this and have just as much fun?
But consider: could we be making the "false consensus" error? Could we
be wrong when we imagine that what <i>we</i> find easy is typical?
<br />
<br />
The assumption that it's going to be easy underpins a lot of current
efforts. For example, if you haven't seen it already, it's
worth watching the
<a href="http://www.youtube.com/watch?feature=player_embedded&v=nKIu9yen5nc">promotional
video</a>
for the <a href="http://www.code.org/">code.org</a> website.
This is a very dense video — in just over 5 minutes it makes
just about every case for learning to program. It opens with a lofty
quote from Steve Jobs: "Everybody in this country should learn how to
program a computer ... because it teaches you how to think." (Which, if
we take it seriously, gets into dangerously political territory. See
<a href="http://www.stuartwray.net/philosophy-of-knowledge.pdf">Not a
Tool but a Philosophy of Knowledge</a>.)
The video then wheels out a sequence of substantial computer geeks,
including Bill Gates and
Mark Zuckerberg. They enthuse about how great it is
to be able to program; how wonderful and empowering it was when they
first learned. The video wraps up with a starkly utilitarian message,
aimed at those who are still not convinced: people who can program
get better jobs. They get ping-pong tables and free food. At work! The
lesson is clear. For all these reasons, everyone <i>should</i> learn to
program. But "should" depends on "can". <i>Can</i> everybody learn how
to program a computer?
<br />
<br />
The evidence is not very encouraging. For example, in their 2006 paper
<a href="http://www.eis.mdx.ac.uk/research/PhDArea/saeed/paper1.pdf">
The camel has two humps</a> Saeed Dehnadi and Richard Bornat noted that:
<br />
<br />
<div style="margin-left: 2em;">
"Despite the enormous changes which have taken place since electronic
computing was invented in the 1950s, some things remain stubbornly the
same. In particular, most people can't learn to program: between 30%
and 60% of every university computer science department's intake fail
the first programming course. Experienced teachers are weary but never
oblivious of this fact; bright-eyed beginners who believe that the old
ones must have been doing it wrong learn the truth from bitter
experience; and so it has been for almost two generations, ever since
the subject began in the 1960s."
</div>
<br />
This paper caused considerable controversy at the time. Not, however,
because of its thesis that most people found programming too
hard. Few people disagreed with that assertion, because everyone who
has tried to teach programming has been confronted, in their direct
experience, with the same evidence. The controversy concerned
whether a test which the authors proposed could really do what they claimed,
and sort the programming sheep from the non-programming goats. (Such
"programming aptitude tests" have a poor track-record and their
results usually correlate very weakly with subsequent direct measures of
programming ability. The results from Dehnadi and Bornat's test were
mixed, and perhaps all we can say for sure at the moment is that if
the test subject has had any previous exposure to an attempt to teach
programming, <del>this appears to make their test ineffective</del>.
<i>Correction: it doesn't make the test ineffective, but you need to
take previous experience into account. See comment below from Richard Bornat,
and also see
<a href="http://www.eis.mdx.ac.uk/research/PhDArea/saeed/SD_PPIG_2009.pdf">
Meta-analysis
of the effect of consistency on success in early learning of programming</a>.</i>)
<br />
<br />
However, there's a deeper issue here, which has so-far hardly been
noticed. Even if we had a pre-course test for programming ability,
where would that leave us? Sure, it would permit university computing
departments to filter their prospective students and to reduce a lot
of unnecessary suffering by turning away those who would find
programming too hard. But if we really believe <i>everyone</i> should
learn to program, if that's more than just a slogan, then this
approach doesn't help at all, does it?
<br />
<br />
The challenge here is to work out techniques for teaching
programming to those people who do not find that it comes easily. A test
that showed ahead of time who was a "natural" and who wasn't would be
helpful, but not to filter out and discard those who have
difficulty. It would be more akin to a diagnosis of dyslexia. We don't say
to a child "You have dyslexia. You will never be able to read."
Instead, when we find that a child has difficulties with reading we
put extra effort into helping them, and to a large extent we now know
how to be successful. With dedication, it's possible to get
literacy rates in excess of 98%. (Although governments seldom
consider it worth trying that hard, it is possible.) Personally, I
believe that if we wanted, the same could be true of programming.
<br />
<br />
But how? Surely, as Richard Bornat said to me last autumn, "We have
tried everything." What can we do that's different? Now, I'm no
"bright-eyed beginner"
— I've been teaching programming classes for several years
— but I think there are things we could try, but don't, because of who
we are. Mostly, the people who teach programming are first of all expert
programmers, not expert programming <i>teachers</i>, and they mostly aim
their teaching at students who are fundamentally the same as
themselves. The teachers are almost always the people for whom it
came easily. The people who have difficulty — <i>most</i>
people — need a very different approach, and not just an
approach which is louder and slower. It is, in fact, <i>our</i>
experience that is not typical.
<br />
<br />
Now, I'm sure you would like to see some concrete examples,
and I'd like to give them, but I think this post is long enough
already. In a future post I will certainly take the opportunity to
talk about what's worked and what's failed for me, and to put some
teaching materials online. I certainly don't have all the answers but
maybe I can help us get closer.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com4tag:blogger.com,1999:blog-7962217619208800961.post-43429075371875912882013-03-03T10:01:00.000+00:002013-03-03T10:01:55.381+00:00Recipe: Yet Another Chilli
Over the years, I've gone through several chilli recipes. This is the
latest, and I think the best.
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">400g</td><td>Tinned chopped tomatoes</td></tr>
<tr><td>2T </td><td>Tomato purée</td></tr>
<tr><td>4T </td><td>Extra virgin olive oil</td></tr>
<tr><td>450g </td><td>Beef mince</td></tr>
<tr><td>2 </td><td>Chipottle dried chillies, de-seeded and finely
chopped</td></tr>
<tr><td>3 </td><td>Star anise</td></tr>
<tr><td>2 </td><td>Onions, chopped</td></tr>
<tr><td>2 </td><td>Red peppers, de-seeded and chopped into 2cm pieces</td></tr>
<tr><td>100ml </td><td>Brown chicken stock (see
<a href="#brown-stock">here</a> for this component)</td></tr>
<tr><td>75ml </td><td>Red wine</td></tr>
<tr><td>200ml </td><td>Water</td></tr>
<tr><td>400g </td><td>Tinned kidney beans, rinsed</td></tr>
<tr><td>0.5t </td><td>Salt</td></tr>
<tr><td>pinch </td><td>Ground black pepper</td></tr>
<tr><td>0.5t </td><td>Chilli powder (to taste)</td></tr>
<tr><td colspan=2>
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml) </td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Put the tinned chopped tomatoes and the tomato purée in a
saucepan and reduce on a gentle heat.
<br />
<br />
While that's happening, heat the extra virgin olive oil in a heavy
frying pan. When it is hot, add half the mince and brown it. (This may
take 3 to 5 minutes depending on how wet it is. It has to fry, not
just stew in its juices.) Add that browned mince to the tomatoes in the
saucepan, leaving as much oil as you can behind in your frying
pan. Brown the other half of the mince in the same way and add that to
the saucepan too, but again leave the oil behind.
<br />
<br />
Turn the heat on your frying pan to low and add the star anise and the
finely chopped chipottle chillies to the oil. Cook gently for 2
minutes, then turn the heat up to high and add the chopped
onions. Cook for 3 to 5 minutes. (The onion wants to be just brown
around the edges.)
<br />
<br />
Turn off the heat on your frying pan and go look for the star
anise. Remember, there were three of them? Go find them and throw them
away. Then tip all the contents of the frying pan (including the oil
this time) into the sauce pan and mix with the tomatoes and beef.
<br />
<br />
Also add the red wine, brown chicken stock and chopped red
pepper to the saucepan.
<br />
<br />
Now put the frying pan back on a high heat and pour in the water to
deglaze the pan. Bring this to an enthusiastic boil and scrape all the
brown bits in the pan so that they dissolve. Pour this solution into the
saucepan with everything else.
<br />
<br />
Add the final ingredients to the saucepan: the rinsed tinned kidney
beans, salt and pepper. I usually add half a teaspoon of chilli powder
at this point too, because although the chipottle chillies have a
lovely smokey taste, they aren't particularly hot.
<br />
<br />
Stir well and simmer gently for 1 hour with the lid on. Remove the
lid, stir and simmer without the lid for another 30 minutes.
<br />
<br />
<b>Discussion</b>
<br />
<br />
You can use white wine rather than red; this works well too. (You could
also deglaze the pan with the wine rather than water, and just add the
water straight to the saucepan. I tend not to do that because I often
use wine from the freezer, prepared in appropriately sized portions.)
<br />
<br />
You might wonder: why de-seed the chipottle chillis (reducing hotness),
then add chilli powder later (increasing hotness)? Why not just leave
the seeds in? Indeed. That might work out fine, I just haven't
done the experiment.
<br />
<br />
Obviously for a more homespun feel you could use fresh tomatoes, but
peeling and chopping those is too much trouble for me.
<br />
<br />
However, it <i>is</i> worth taking the trouble to use a proper
stock. It's really not at all the same if you use those hopeless
stock-cubes. So, at the risk of making this chilli look more
frightening than really it is, here also is my recipe for a suitable
stock. The stock gets made ahead of time and used in many other
dishes. So in practice, when making the chilli, you just reach into the
freezer and toss a few cubes of stock into the saucepan.
<br />
<br />
<a name="brown-stock"> </a>
<b>Component: Brown Chicken Stock</b>
<br />
<br />
This is a relatively rustic stock, with little effort devoted to
making it clear. It takes a long time, but it's not much work. Using a
slow-cooker helps a lot, because it looks after maintaining a very
gentle simmer for itself and you don't end up with the smell of
chicken stock penetrating to every corner of the house. (Which is
what seems to happen when I make stock in a stock-pot on the top of
the the stove.)
<br />
<br />
<b>Ingredients</b>
<br />
<br />
<div style="margin-left: 2em;">
<table>
<tr><td style="width: 4em;">1.2 kg</td><td>Chicken carcases, bones & scraps</td></tr>
<tr><td>2 </td><td>Onions, quartered</td></tr>
<tr><td>1.6 litre </td><td>Water</td></tr>
</table>
</div>
<br />
<b>Method</b>
<br />
<br />
Preheat oven to 200°C (= gas mark 6 = 400°F).
<br />
<br />
Spread the chicken parts out in a roasting tray with the quartered
onions. Place in the oven for 30 minutes. Turn the pieces over and
place in the oven for a further 30 minutes. They should be a nice
golden brown.
<br />
<br />
Tip the contents of the roasting tray into a pre-heated slow
cooker along with 1.3 litre of boiling water.
<br />
<br />
Deglaze the roasting tray by pouring on 300ml boiling water, heating
on a hob and scraping to dissolve the brown stuff. Pour this into the
slow cooker. Put the lid on and set so that it will maintain a very
gentle simmer. Leave to simmer for around 4 to 6 hours (it's not critical).
<br />
<br />
Strain the contents through a fine sieve into a bowl or pan. You can
strain this again through muslin if you are keen, or if you are lazy
like me, you can just leave it to settle for a while and simply decant
it into another container, leaving most of the fine sediment
behind. (If you want to skim the fat off the top you can do it at this
stage or you can put the stock in the fridge overnight and just peel it off
the top tomorrow.)
<br />
<br />
You end up with about 1.2 litres of stock which you can freeze into useful
sizes: I usually make some ice cubes and fill some small containers.
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com0tag:blogger.com,1999:blog-7962217619208800961.post-60355829331623167782013-02-24T12:46:00.000+00:002013-02-24T12:46:52.210+00:00Meta-II: An Early Meta-CompilerWhat is a meta-compiler? Before answering that question we need to
take two steps back. First, what's a compiler? A compiler reads
a program written in some source language and transforms it into a
(more-or-less) equivalent version expressed in a target
language. For example, a C compiler takes the usual textual
representation of a C program and generates object code in some
target language such as assembler code or virtual machine instructions.
The resulting object code is equivalent (in some sense) to the source
code, but it can be run directly on a physical machine or in an interpreter.
<br />
<br />
A compiler-compiler reads a "program" which specifies the grammar of
a source language and some transformation rules. The object code it generates
is a compiler for that source language.
(So a compiler-compiler is also compiler, it's just that its
source code is your grammar-plus-transformation-rules and its output is
object code which directly executes those rules and transformations.)
The idea is that writing a grammar
and some transformation rules is a lot less work than writing a whole
compiler. Instead you write a more declarative description of what you
want to happen and the compiler-compiler generates the code that deals
with the fiddly details of pattern-matching and code-generation.
<br />
<br />
So now we can answer the question: "What's a meta-compiler?" A
meta-compiler is a compiler-compiler written in its own source
language. So when the meta-compiler reads its own description, it
generates exactly its own object code, a fixed-point if you want to
think of it that way. It's a neat trick, and clearly an
easier way to build a compiler-compiler — provided you already
have a compiler-compiler to start with.
<br />
<br />
I first came across Meta-II when I read
<a href="http://www.vpri.org/pdf/tr2008003_experimenting.pdf">Experimenting
with Programming Languages</a> by Alessandro Warth. In this PhD thesis
Warth explains some interesting implementation details
of the meta-compiler OMeta. (This meta-compiler
has been used to implement many different languages at
the <a href="http://www.viewpointsresearch.org/">Viewpoints Research
Institute</a> and elsewhere. These languages and the systems written
with them are key evidence to support
<a href="http://www.tele-task.de/archive/video/flash/14029/">Alan
Kay's assertion</a> that we can
build systems with orders of magnitude less source code than is
customary today.)
<br />
<br />
Now, OMeta started out as an experiment
based on the much earlier Meta-II, so when I wanted to play with a
meta-compiler, this earlier, simpler program seemed like a good
place to start out. (I figured that by playing with this program I
would come to understand what was wrong with it, what needed
changing to make the more advanced OMeta. That's certainly been the
case, but I'm not entirely sure it was worth the effort.)
<br />
<br />
Meta-II is described
in <a href="http://ibm-1401.info/Meta-II-schorre.pdf">Meta II: A
Syntax-Oriented Compiler Writing Language</a> by Val Schorre (1964),
and although this paper is a nice read, I found that the best place to
start playing is James Neighbors'
<a href="http://www.bayfronttechnologies.com/mc_tutorial.html">Tutorial:
Metacompilers Part 1</a> and the accompanying
<a href="http://www.bayfronttechnologies.com/mc_workshop.html">Metacompiler
Workshop</a>. This "workshop" is a web-page with an extended version
of Meta-II implemented in Javascript, so you can put your grammar
description in one window, and get the code for a compiler in another
window, and then use that compiler in turn to compile a program. If you
want to do what I did, you can work your way through Neighbors'
tutorial and then port a version of Meta-II off the web-page and into a
self-contained program. (You can find the results of my
slightly-too-clever-for-its-own-good port to Python
<a href="https://github.com/stuartwray/meta-ii-experiments">here
on github</a>.)
<br />
<br />
I had decided that I wanted a version very
close to Schorre's original Meta-II, rather than the extended version
constructed by Neighbors. This choice in turn forced me to implement a
virtual machine in my Python runtime, rather than generating native Python
control constructs. That's because the original Meta-II's output
operations are tuned to generating assembler code line-by-line, with
only two levels of indentation. Obviously that's not going to fit well
with Python, where indentation indicates block structure. So instead my
code reads the generated "assembler code" and
effectively assembles, loads and links it into a form where it can be
interpreted directly. Quite a lot of extra work to stay with the
original version of Meta-II, and in the end not worth the effort, other than for
the learning experience.
<br />
<br />
So, what did I learn? And what would I change about Meta-II so that it
was more useful but still simple, without going all the way to the
complexity of OMeta? (Which adds a full programming language to do the
output transformations.)
<ul>
<li> It would be better to have a somewhat more
expressive language in which to write the transformation
rules, and that way avoid having to put so much work into a
virtual machine to interpret the meta-compiler's output code.
(Since Neighbors and Warth both came to the same
conclusion, this does seem blindingly obvious in retrospect.)
Probably the first step would be to follow Neigbors' example and
introduce a mechanism for more general indentation of output, so it
would then be possible to output nicely formatted
representations of a program — for example S-expressions.
<br /><br />
</li>
<li>
Both the original Meta-II and Neighbors' extension only
have access, in their output operations, to the last token matched. OMeta
is a lot more flexible here, since you can give names to the values of
any matching rules and then use the values later in a different order. This
facility would also remove the need for a special-purpose
token-recognition sub-language which Neighbors introduces in his
implementation.
<br /><br />
</li>
<li>
OMeta uses backtracking when a rule doesn't match, but Meta-II has to
make its decisions based only on the next token. In practice, you
can still parse lots of languages, but it's an annoying restriction,
best removed. Fortunately this is relatively
straightforward. Neighbors explains how to do it, though he doesn't
give an implementation. OMeta's implementation also improves
backtracking performance using a caching technique: it's a "packrat
parser". (See for
example <a href="http://pdos.csail.mit.edu/~baford/packrat/thesis/">Packrat
Parsing: a Practical Linear-Time Algorithm with Backtracking</a>
by Bryan Ford.)
<br /><br />
</li>
<li>
Lastly, Meta-II cannot handle left-recursive rule definitions, because
they would not terminate. If you have a grammar that is naturally
left-recursive, you therefore have to rewrite it without the
left-recursion, which you can always do, but this isn't really
very satisfactory. How confident can you be that the
subsequent parse tree and your interpretation of it really is
equivalent to the intent of the original grammar? It's a problem
waiting to bite you later. So a further useful
improvement would be to use Warth's neat technique that makes
<a href="http://www.vpri.org/pdf/tr2007002_packrat.pdf">
left-recursion work in a packrat parser</a>.
</li>
</ul>
You can only really understand things properly by making them
yourself, so my next step will be to implement some of these ideas, and
I'll report on how that went in some
future post. In the mean time I would encourage you to look at the
<a href="http://ibm-1401.info/Meta-II-schorre.pdf">original Meta II
paper</a> and to have a play with Neighbors'
<a href="http://www.bayfronttechnologies.com/mc_workshop.html">Metacompiler
Workshop</a>. It's great fun!
Stuart Wrayhttp://www.blogger.com/profile/00696910341905919852noreply@blogger.com1