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

1 comment:

  1. Very interesting! We used to have a bit similar classes in our programming course but 2 years ago we decided to go for only computer based labs. Your post gave me inspiration to try those "whiteboard labs" again, now with more thought out process.

    ReplyDelete