(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.
- Make variable a have value 5.
- Write an if statement that prints "too big" if
variable a has a value more than 99, and otherwise
does nothing.
- Increment variable i by 1.
- Use a while loop to print all the integers from 1
to 99.
- Print the odd
numbers from 1 to 101.
- Define a function odds() which prints the odd numbers from 1
to 101.
- Define a function odds1(x) which prints the odd numbers
from 1 to x.
- Define a function sum_odds(x) which prints the sum of the
odd numbers from 1 to x.
- Define a function sum_odds1(x)
which returns the
sum of the odd numbers from 1 to x. (And does not
print anything.)
- Make variable q have as its value the empty list.
- Append the integer 5 to the list q. Print q.
(What exactly is
printed?)
- Define a function odds_list(x)
which returns a
list odd numbers from 1 to x. (And does not
print anything.)
- 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.)
- Use the range function to write an expression whose value
is the list [0, 1, 2, 3, 4, 5, 6, 7].
- Use the range function to write an expression whose value
is the list [1, 2, 3, 4, 5, 6, 7, 8].
- Use the range function to and a for loop to print
the integers from 1 to 99.
- Use your earlier prime_list function and a for loop
to print all the primes from 1 to 999.
- 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.
- Print the sum of the primes from 1 to 999.
- Define a function vertical(s) which uses
a for loop to print the characters of the string s,
one per line.
- 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.
- Define a function code_list(s) which
returns a list
containing the Unicode codes for each character in the
string s.
- Print the sum of the Unicode codes of the characters in the
string "hello world".