var a = prompt(“Enter a number”); var b = a * a; alert(b);
Or they might write:
var n = prompt(“What is your number?”); alert(“The answer is: “ + (n ** 2));
These code snippets do exactly the same thing, for practical purposes, but as you can see they’re pretty different. So, considering this complexity, most teaching systems don’t try to control exactly what the student writes. Instead, they run checks called unit tests on the student’s code. In this case, as long as the correct number is included somewhere in the output, the code is considered correct, and the student is allowed to move on to the next task. If the student has trouble, they can ask for a hint.
As long as the code stays very simple, this approach works fine, but as the code gets more complex, all the program can do is tell the student that their program’s not working -- and they knew that much already.
Of course, we can also solve the whole task for them. That’s OK while tasks are simple: the student can see the solution, and next time they can do it on their own. But when the tasks get more complex, there’s a pedagogical problem with this approach. Students need complex material to be broken down into small, simple pieces; a task may have a number of pieces, but each piece is fairly simple on its own.
So solving an entire task for them is likely to backfire. The student may well look at the solution, and not understand how it works -- and certainly not be able to replicate it. Seeing another, similar solution to a similar problem won’t help very much. There’s something in there they don’t understand -- and, critically, we, the system designers, don’t know what it is. So we can’t help them understand that specific piece. The student is likely to move forward to the next topic, hoping that something they see in that next lesson will give them an idea about how to solve this one; so it doesn’t take long before they’re completely stuck.
So we decided to write a system that would create multiple versions of each line of code. Consider this one:
var a = b + c;
This is equivalent to:
var a = c + b;
It’s not hard to write a program that finds the second variation. But as the line of code gets more complex, there are more types of variation, and in some cases there can be thousands of equivalent versions of a single line of code.
But once we had set up a system which could generate all those versions, it became possible for us to check a specific line of student code, and help them with just that one line; so we were able to build our system on a much sturdier pedagogical foundation.
It’s true that to use this approach, it is necessary for us to make certain restrictions on how students write their code:
We need to choose variable names (such as a, b, and c in the example above).
We have to decide what line of code does what; we determine the structure of the solution, and the student fills in the blanks.
As a consequence, our directions are generally more detailed than those of our competitors; but we’re able to keep them from getting too long and complicated by keeping tasks short.
(Some people in the field tend to feel that, because we’re controlling the structure of the code, we’re depriving the student of an important learning opportunity. We respectfully disagree: Beginners aren’t ready to create structure. They first need to absorb it, then, once the the mental pathways are established, they can can recreate it on their own; later still, when they have used it many times, they can create their own structures.)
Another consequence of our approach, which turns out to be vital, is that we know exactly which line of code is which, so we’re able to decide which lines of code can be edited at any given time. This granular control of student code makes it possible for us to approach the problem of teaching coding in a new and much more effective way, as we’ll explore in upcoming posts.