A question that is frequently asked is, “what is an effective method of teaching programming when all my students have different levels of understanding?”
After 20 years of trying many methods all with different levels of success, here is our view. Like all aspects of teaching we acknowledge that there is no magic formula. There is no one method that can be proven to be better than all others. Over the years we have found many paths to success, so what we present here is what we think works best for the majority of learners and is therefore the most comprehensive method of addressing the challenges in teaching today.
Lessons with programming should:
- Enable all learners to make progress from different starting points.
- Allow students to work at their own pace with appropriate challenge, and in doing so find engagement.
- Allow learning to continue away from the classroom as much as possible, and allow students who are absent to easily continue or catch up.
- Not hold students back.
- Provide appropriate scaffolding.
- Allow students to take some ownership of the learning journey so it isn’t simply, “learning on rails”.
- Allow students to tackle small real-world problems that are similar to those they may find in exams.
- Allow the high ability students to expand beyond the scheme of learning with study relevant to the specification or future ambitions.
- Give you time as a teacher to interact with individual students as much as possible and not be tethered to the front of the classroom.
How did you learn to program?
Have you ever stopped and thought how you learned to program? Could this be emulated with success with students?
Dave has fond memories of learning to program in the 1980s. Typing in programs from Amstrad Action magazine to see what they would do. Inevitably, at 10 years old, he wasn’t very accurate in transcribing the listings and there were errors. He had to study the program carefully, and correct his mistakes.
The programs would eventually run, and he would be delighted that the computer did something it couldn’t do before. The programs were very simple, so he began experimenting with changing a few variables (not that he understood what they were) to see what would happen. This was intriguing, and having picked up the “Programmers guide” and “Programming keywords” for Locomotive Basic that had come with his Amstrad CPC464, began to experiment with adding in extra little bits to the code to see what would happen. Gradually he became more confident and wanted to know how to do something, to solve a particular problem he had set himself. Using the programming keywords as a handy reference he learned the commands he could use, their syntax, and gradually memorised them.
As he became more confident he began setting himself bigger challenges, writing code from scratch, and learning more through the process. He began to learn of more appropriate techniques, and the programs became more sophisticated. It took practice, practice, practice and perseverance, perseverance, perseverance!
The Craig’n’Dave approach to teaching programming
We don’t lead programming from the front of the class with all students learning the same concepts at the same time. Delivering a lesson this way may satisfy a teacher’s desire to teach, but inevitably some students will glaze over, some will find it useful and some will already know what you are teaching them! Why teach to only one proportion of the class when an independent learning approach would enable students to take ownership and the teacher to spend more time with individuals?
Therefore students in our classroom are self-taught. This method has proven to work in a diverse range of secondary schools for many years. We provide students with all the resources they need to learn to code for themselves by giving them learning tasks and problems to solve. We then intervene with individuals and sometimes take a pause to illustrate something to the whole class.
- Learning tasks:
- Typing up code from examples and seeing what happens: giving students the confidence of not starting programs themselves from a blank screen when they lack confidence and need support.
- Modifying the code to do something different: allowing students to begin to understand what the code means by a try and see approach.
- Studying syntax guides of the commands, but limiting these to prevent information overload.
- Attempting a variety of small challenges using only the commands learned: enabling student to apply new knowledge gained from the learning tasks.
- Beginning to write bigger programs with less support: becoming independent.
- Looking at the program a student has written when they have completed a solution to a problem. Discussing terminology, the approach taken, comments, sensible variable names and indenting. Asking the student to explain how it works.
- Helping the less able understand what they are trying to achieve. By relieving yourself from the front of the class you have more time to support those who need it without boring those who don’t!
- Stretching the more able to make their programs more robust and with extended features.
- Looking at code a student has produced as a whole class to identify different approaches, misconceptions, fix bugs and highlight learning points.
Our students learn to program by building up their knowledge of commands one step at a time. We ensure the solutions to our problems only ever require the knowledge gained in the current and previous learning tasks:
- Objective 1: learn to output text strings.
- Objective 2: learn to input strings and numbers into variables.
- Objective 3: learn string manipulation functions.
- Objective 4: learn how to use selection statements.
- Objective 5: learn how to use arithmetic operations and random numbers.
- Objective 6: learn counter controlled iterations.
- Objective 7: learn condition controlled iterations.
- Objective 8: learn subroutines, procedures and functions.
- Objective 9: learn arrays and lists.
- Objective 10: learn serial files.
- Objective 11: learn to handle exceptions.
At A’level we look at event driven approaches and object-oriented methods.
Giving students a variety of problems to solve
We provide students with lots of little problems to solve and some bigger challenges too. However, there is no need for all learners to solve all problems. Students have ownership of the task within scaffolded boundaries. This gives you differentiation by task without you having to do any additional work! All students complete the learning tasks in an objective, and once complete attempt some of the problems for that objective. Each problem has a difficulty rating between 1 and 4. We recommend students typically attempt to achieve 6 points in an objective (except for objective 1). This means they could attempt three of the two point problems, or two of the three point problems, or indeed two of the one point problems plus two of the two point problems. Lots of combinations allows students to have ownership and for you to differentiate very easily.
Less able students may want to complete more of the lower point problems to gain 6 points. This gives them plenty of practice with the basics. Whereas higher ability students could just solve three or four point problems to gain 6 points. Some students may also want the marathon challenge of completing as many problems as possible!
When students complete a problem, as a teacher you can then review their code, discussing techniques adopted, command words like “concatenation”, “parameter” etc. Giving them this individual and timely oral feedback is far more effective than any other type of feedback for programming work. Put a progress chart on the board if you want to motivate students to keep pace!
Mixing it up with other approaches
From time to time you can mix up our core approach with other ideas to add variety. For example, put the output from a problem on the board and ask students to write a program to produce that output. For example:
Hi, please enter your name: David Please enter your date of birth: 20/5/03 Hello David. I think you are 16 years old.
Tasks like this are extremely open ended because there are many ways to solve the problem and many potential improvements to add stretch and challenge. This approach works great with paired programming. Not just getting students to work in pairs, but getting one student to write the code whilst another reviews it and adds ideas into the problem solving. After ten minutes swapping roles.
Parsons Problems (invented by Dale Parsons at Otago Polytechnic, New Zealand) gives students all the lines of code to correctly solve a problem, but the lines of code are broken into code blocks and mixed up. This is a great strategy and really helpful for supporting students that are struggling with writing larger programs and understanding problem decomposition.