Using coding errors to inspire learning

tagged with Backend Community Developer

So you want to pick up a new programming language, a new technology, or even just adapt to a new paradigm within a language you already know? Or better still, you have someone in your team who needs to do these things and you want to help them, where do you start?

When learning or teaching something new, we are most familiar with a worked example: a correct example of code and a description or step-by-step guide explaining how it was put together. These approaches to teaching are often found in textbooks or coding tutorials and use an explanatory approach with “fading” support as the learner progresses through the material [1]. Makes sense, right?

However, there are some issues with worked examples:

  • Promotes passive and shallow learning, meaning that the learner does not fully engage with the information and may struggle to apply it to similar situations or remember it in the future.
  • Although a description of why something is done a certain way or following a certain pattern is useful, it can be easy to forget the steps before the learner can apply them (especially if there are lots of them!)
  • Don’t necessarily understand why steps are correct, only that they are, so really it’s adding items to the memory bank rather than to the skills and understanding of the individual.
  • Sometimes even if you understand the individual steps, it’s not always clear how they link together to solve the original problem – this requires a deep understanding of both the problem space and the solution space that isn’t necessarily present when starting out

Obligatory XKCD reference to not understanding how steps may reference each other

 

Essentially, relying only on correct, worked examples runs the risk of missing opportunities to identify the limits of your knowledge or the limits of the examples themselves. Correct examples of code promote “I agree because you’ve told me it’s correct and I am learning from you” rather than, “Here’s an area where I don’t understand why this is wrong”, for example.

Enter error-driven learning

You might think that learning something new with an error-driven code example would risk introducing poor understanding of concepts, reinforce existing confusion or even introduce new errors for the student; and you would not be alone in this concern as it is also held by much of traditional curriculum teaching. However, this is only the case if there is no additional learning support – like highlighting where the example is wrong or prompting them to compare with accurate code. I am definitely not proposing you just abandon your new learners with poorly written code; because that’s generally called bug fixing!

Erroneous examples address misconceptions in code directly, by highlighting them instead of focusing on the “correct” code. In a world where “correct” code is an open debate anyway, understanding how something can be wrong is equally as important as understanding how something can be right. Research indicates that misconceptions can be really hard to counteract once they’ve taken root and can often damage learner progress across multiple connected domains if not addressed early [2], so tackling them head-on can be super valuable for learning advanced concepts going forward.

Initiating a learning session with incorrect code from the beginning also opens the learning area into a safe space for errors and mistakes. It gives the learner permission to ask questions and get things wrong and be vulnerable, without expecting perfect understanding from the start. Doesn’t that sound refreshing?

Also, a bit like a “spot the difference” puzzle, leading with an error-driven code example is naturally engaging for the dopamine-driven human brain. The brain thrives on learning new things, and puzzles are one of our favourites; whether it’s playing a game or doing a cryptic crossword (anyone?). A puzzle is engaging, it’s an open question – what’s wrong here? It’s an example of active learning and engages our current domain knowledge or what we think we already know. Also, who doesn’t love correcting someone else?

 

 

Another advantage of error-driven code learning is that it can promote learning by teaching not just the one concept of what is “correct”, but two concepts; what is also “incorrect”. This additional bit of learning is referred to as “negative knowledge” [3] and is helpful for the learner to build up a domain of expectations for what a solution should or should not look like; it will also feed in to an understanding of returned errors from the compiler/code/browser so is doubly useful!

What type of errors?

Obviously this won’t work with all types of errors, and the code needs to include enough accurate and recognisable signposts for the learner to be able to orient themselves i.e. the whole function can’t be a hot mess, there needs to be some seeds of sanity.

When I mention “types” of errors here, I mean that syntactical errors are probably not going to cut it in terms of conceptual learning and development. That is to say that leaving out parentheses, missing semi-colons or mis-spelling variable names count as errors, but aren’t really going to help with learning logical flow – unless of course you’re trying to get the learner to understand what the compiler or IDE notices, in which case fire away.

Realistically, semantic errors where there is a discrepancy in the underlying logic would be most useful when teaching a new concept. But – too many semantic errors, or errors that are too hard at the beginning are likely to just lead to confusion rather than learning! [3]. The trick is to be careful, making sure that learning is still being layered and support offered, so that the learner doesn’t rage quit.

Let’s look at a couple of example semantic errors that could be included for teaching some array manipulation concepts. Essentially leading the learner with an issue (unexpected output) and then opening to floor to a discussion around the concepts involved.


const wordElements = [
  { type: "christmas", word: "wishing" },
  { type: "normal", word: "umbraco" },
  { type: "christmas", word: "you" },
  { type: "christmas", word: "a" },
  { type: "normal", word: "community" },
  { type: "christmas", word: "very" },
  { type: "normal", word: "fun" },
  { type: "christmas", word: "merry" },
  { type: "christmas", word: "christmas" },
];

// GOAL: to filter and print christmas words
console.log(getChristmasWords());
// expected output ["wishing", "you", "a", "very", "merry", "christmas"]

function getChristmasWords() {
  let christmasElements = wordElements.filter(isChristmasWord);
  return christmasElements.map(el => el.word)

  //EXAMPLE SEMANTIC ERROR
  //return christmasElements.map(el => el.type);
  //output = ["christmas", "christmas", "christmas", "christmas", "christmas", "christmas"]
  //(teachable moment on map functionality)
}

function isChristmasWord(element) {
  return element.type === "christmas";

  //EXAMPLE SEMANTIC ERROR
  //return element.word === "christmas";
  //output = ["christmas"]
  //(teachable moment on object properties)
}

Semantic errors example

So, thanks for reading! Hopefully this article has provided a little bit of food for thought. Other use cases of error-driven learning might be using it in talks if you’d like a bit of audience engagement (or to see who’s paying attention), or maybe in workshops where you are facilitating other people’s learning. Research into cognition and programming is advancing all the time, and the more we learn about how we learn the more exciting things become!

 

References

[1]       R. K. Atkinson, A. Renkl, and M. M. Merrill, ‘Transitioning From Studying Examples to Solving Problems: Effects of Self-Explanation Prompts and Fading Worked-Out Steps.’, Journal of Educational Psychology, vol. 95, no. 4, pp. 774–783, Dec. 2003, doi: 10.1037/0022-0663.95.4.774.

[2]       J. E. Richey et al., ‘More confusion and frustration, better learning: The impact of erroneous examples’, Computers & Education, vol. 139, pp. 173–190, Oct. 2019, doi: 10.1016/j.compedu.2019.05.012.

[3]       M. Beege, S. Schneider, S. Nebel, J. Zimm, S. Windisch, and G. D. Rey, ‘Learning programming from erroneous worked-examples. Which type of error is beneficial for learning?’, Learning and Instruction, vol. 75, p. 101497, Oct. 2021, doi: 10.1016/j.learninstruc.2021.101497.


Tech Tip: JetBrains Rider

Check it out here