Sunday, 31 March 2013

Recipe: Aubergines stuffed with chickpeas

Only after I wrote this up did I notice a very weak and accidental pun: this is a recipe for Egg Plant, and today is Easter.

Ingredients

3 Aubergines, about 20cm long
Lots of salt
5t Extra virgin olive oil
1 Onion, chopped (about 150g)
4 Cloves garlic, crushed
400g Tinned tomatoes
400g Tinned chickpeas
(preferably in plain water, drained weight = 250g)
60g Fresh coriander leaf, chopped fine
2T Tomato purée
3T Lemon juice
1t Salt
Ground black pepper, to taste)
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml)

Method

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.

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.

Preheat oven to 200°C (= gas mark 6 = 400°F).

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.)

Add the aubergine flesh to the pan and cook for another 5 minutes.

Drain the tomatoes and slice them up (about 5mm thick slices). Add them to the pan.

Drain the chickpeas and rinse them off in the colander. Add them to the pan.

Add the chopped fresh coriander, the tomato purée, lemon juice, salt and pepper to the pan. Heat the mixture until it is bubbling.

Pile the mixture into the aubergine skins and cook in the oven for 30 minutes at 200°C (= gas mark 6 = 400°F).

Discussion

This recipe is improved by using fresh 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.

Sunday, 24 March 2013

Write-me-a-program

(This post is a follow-up to Learning to Program.)

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.

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 Michel Thomas' 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: The spacing effect: A case study in the failure to apply the results of psychological research by Frank Dempster (American Psychologist, Vol 43(8), August 1988, pp627-634).

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 Eddie Izzard's comments on learning French from his show Dress to Kill. (He complains that his school textbook contained things which were "difficult to get into conversation, things like: 'The mouse is underneath the table' ".)

In contrast, Michel Thomas doesn't give you phrases to memorise. In fact he insists that you don't try 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 Easy Tiger: Language Lessons on the Road (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."

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 Michel Thomas language course, if only to experience first-hand the feel of his method.) Here's my recipe for my write-me-a-program technique:

Ingredients

A class of students, not too big.
A computer with a projector.
A set of slides (in e.g. Powerpoint) with the questions, one per slide.
     (See end of this post for an example set of questions on Python.)
Printed handouts with all questions + answers.
     (N.B. Don't hand out these until the END.)
A whiteboard with pens.
Jotting paper/pens for the students.

Method

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.

Explain to the students that they will each need paper and a pen. (And wait until they have sorted this out.)

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."

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 process right. For example, an opening Python programming question might be:

Make variable i have value 5.

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.)

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."

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 learning, 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.)

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.)

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."

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.

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.

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 "our 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.

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 change 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".)

See the end of this post for a collection of Python questions that have worked well for me.

Discussion

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.

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).

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.

Example set of questions

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.
  1. Make variable a have value 5.
  2. Write an if statement that prints "too big" if variable a has a value more than 99, and otherwise does nothing.
  3. Increment variable i by 1.
  4. Use a while loop to print all the integers from 1 to 99.
  5. Print the odd numbers from 1 to 101.
  6. Define a function odds() which prints the odd numbers from 1 to 101.
  7. Define a function odds1(x) which prints the odd numbers from 1 to x.
  8. Define a function sum_odds(x) which prints the sum of the odd numbers from 1 to x.
  9. Define a function sum_odds1(x) which returns the sum of the odd numbers from 1 to x. (And does not print anything.)
  10. Make variable q have as its value the empty list.
  11. Append the integer 5 to the list q. Print q. (What exactly is printed?)
  12. Define a function odds_list(x) which returns a list odd numbers from 1 to x. (And does not print anything.)
  13. You are given a functionprime which takes an integer and returns True if it that integer is a prime number and False otherwise.
    Define a function prime_list(x) which returns a list of all the prime numbers from 2 to x. (And does not print anything.)
  14. Use the range function to write an expression whose value is the list [0, 1, 2, 3, 4, 5, 6, 7].
  15. Use the range function to write an expression whose value is the list [1, 2, 3, 4, 5, 6, 7, 8].
  16. Use the range function to and a for loop to print the integers from 1 to 99.
  17. Use your earlier prime_list function and a for loop to print all the primes from 1 to 999.
  18. The built-in sum function takes a list and returns the sum of its elements.
    Use the built-in sum function to print the sum of the integers from 1 to 99.
  19. Print the sum of the primes from 1 to 999.
  20. Define a function vertical(s) which uses a for loop to print the characters of the string s, one per line.
  21. The built-in ord function takes a single-character string and returns the integer which is its Unicode code.
    Define a function codes(s) which uses a for loop to print the Unicode codes of the characters in the string s, one per line.
  22. Define a function code_list(s) which returns a list containing the Unicode codes for each character in the string s.
  23. Print the sum of the Unicode codes of the characters in the string "hello world".

Monday, 18 March 2013

Recipe: Fish Chowder

This is a very chunky soup, a meal in itself.

Ingredients

500g White fish fillet, in 2cm cubes
8-10 Cellery stalks, diced
8-10 Spring onions, chopped
400ml Brown chicken stock (see here for this component)
250ml Double cream
1t Salt
Ground black pepper (to taste)
pinch Grated nutmeg (optional)
(1t = one teaspoon = 5ml)

Method

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.

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.)

If you want to add the pinch of grated nutmeg, stir that in just before you serve.

Discussion

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 is evidence that eating more salt makes you less likely to die. (Yes, that's right: less likely! See Open Season on Salt: What the Science on Hypertension Really Shows.)

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 Dean Bavington has to say about the Newfoundland fishery.)

Sunday, 10 March 2013

Learning 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.

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 ICL BASIC Pocket Edition, 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 A Guide to Fortran IV Programming, and APL from from an APL\1130 Primer 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.

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 we find easy is typical?

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 promotional video for the code.org 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 Not a Tool but a Philosophy of Knowledge.) 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 should learn to program. But "should" depends on "can". Can everybody learn how to program a computer?

The evidence is not very encouraging. For example, in their 2006 paper The camel has two humps Saeed Dehnadi and Richard Bornat noted that:

"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."

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, this appears to make their test ineffective. 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 Meta-analysis of the effect of consistency on success in early learning of programming.)

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 everyone should learn to program, if that's more than just a slogan, then this approach doesn't help at all, does it?

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.

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 teachers, 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 — most people — need a very different approach, and not just an approach which is louder and slower. It is, in fact, our experience that is not typical.

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.

Sunday, 3 March 2013

Recipe: Yet Another Chilli

Over the years, I've gone through several chilli recipes. This is the latest, and I think the best.

Ingredients

400gTinned chopped tomatoes
2T Tomato purée
4T Extra virgin olive oil
450g Beef mince
2 Chipottle dried chillies, de-seeded and finely chopped
3 Star anise
2 Onions, chopped
2 Red peppers, de-seeded and chopped into 2cm pieces
100ml Brown chicken stock (see here for this component)
75ml Red wine
200ml Water
400g Tinned kidney beans, rinsed
0.5t Salt
pinch Ground black pepper
0.5t Chilli powder (to taste)
(1T = one tablespoon = 15ml; 1t = one teaspoon = 5ml)

Method

Put the tinned chopped tomatoes and the tomato purée in a saucepan and reduce on a gentle heat.

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.

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.)

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.

Also add the red wine, brown chicken stock and chopped red pepper to the saucepan.

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.

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.

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.

Discussion

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.)

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.

Obviously for a more homespun feel you could use fresh tomatoes, but peeling and chopping those is too much trouble for me.

However, it is 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.

Component: Brown Chicken Stock

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.)

Ingredients

1.2 kgChicken carcases, bones & scraps
2 Onions, quartered
1.6 litre Water

Method

Preheat oven to 200°C (= gas mark 6 = 400°F).

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.

Tip the contents of the roasting tray into a pre-heated slow cooker along with 1.3 litre of boiling water.

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).

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.)

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.