Among these neo-Piagetian researchers is a group including Raymond Lister and Donna M. Teague whom applied these theories to the learning of computer science, formulating a theory Lister calls The Developmental Epistemology of Computer Programming. This theory describes the traits of programmers at each of the stages of development. In particular, they use a student’s ability to trace code (explain line-by-line what it does) as a demarcation between stages.

Stage Traits
Sensorimotor
  • Cannot trace code with >= 50% accuracy
  • Dominant problem-solving strategy is trial and error
Preoperational
  • Can trace code with >= 50% accuracy
  • Traces without abstracting any meaning from the code
  • Cannot see relationships between lines of code
  • Struggles to make effective use of diagrammatic abstractions of code
  • Dominant problem-solving strategy is quasi-random code changes and copious trial runs
Concrete Operational
  • Dominant problem-solving strategy is hasty design, futile patching
  • Can establish purpose of code by working backwards from execution results
  • Tends to reduce levels of abstraction to make concepts more understandable
Formal Operational
  • Uses hypothetico-deductive reasoning
  • Reads code rather than traces to deduce purpose

These stages reflect the progress the learner is making through accommodation, creating the mental structures needed to reason about programming. An expert has developed these structures, which reflect patterns in how code is written - that is why an expert no longer traces code - they can see the patterns in the code and immediately grasp its action and purpose. In contrast, the novice must deduce the result of each line of code, put those understandings together, and then deduce what it is doing overall.

Writing a program is similar, the expert begins with a clear picture of the patterns she must employ, and focuses on fleshing those out, while a novice must create the program ‘from whole cloth’, reasoning out each step of the process. They are not yet capable of reasoning about the program they are writing in the abstract.

This also helps explain why learning to program can be so hard. Abstraction is considered a central tool in programming; we use abstractions constantly to simplify and make programs more understandable to other programmers. Consider a higher-level programing language, like C#. Each syntax element is an abstraction for a more complex machine-level process. The statement:

x += 2;

Stands in for machine instructions along the lines of:

PUSH REG5 TO REG1
PUSH 2 TO REG2
ADD REG1 AND REG2
PUSH REG3 TO REG5

Which are in turn, simplifications and abstractions of the actual process of adding the two binary values in register 1 and register 2.

What is interesting is we don’t really need to understand all of that complexity - we just need to understand enough to be able to write the programs we want to create effectively. We’ll talk about that next.