Guideline 5: Show program structure

In much of programming teaching at school level, the discussion revolves around syntax and statements. I realise that – with young learners – mastering a loop is initially a challenge. But the statement level (and especially syntax) is neither the difficult, nor interesting, nor important part of programming.

Every pupil will learn to write an assignment and an if statement. This is not where the difficulty lies, nor where the important concepts, which we want our students to understand, are illustrated.

The most important part of learning to program is abstraction, and its incarnations in structuring a problem, conquering complexity and guiding our thinking.

In object-oriented languages, this is embodied by classes, objects and methods. In procedural approaches, it manifests in procedures and functions, scope of data and separation of concerns.

It is important to visualise this structure early and often. In the best case, use a programming environment that provides the structure visualisation. Use an environment that de-emphasises syntax, ideally removing the need to memorise where it can.

If you don’t have an environment like this, do it yourself: draw diagrams on the whiteboard. Do what works, but TALK ABOUT STRUCTURE.

The challenge of learning about statements will become meaningless. The challenge of designing program structures will remain – it is an intrinsic part of being a programmer and computer scientist. Make this the centre of teaching your students good programming practice.

Guideline 4: Don’t use “Hello World”

I am now skipping two of the guidelines from the paper, because they are specific to object orientation, and I would like to first concentrate on the general advice. (I might come back to the OO advice later.) Therefore, our Guideline 4 here is actually number 6 in the paper. It tells us not to start with “Hello World” as a first example.

The main problem with “Hello World” (or the only marginally more interesting “Hello <NAME>”) is that it is just so boring!

If you want to show a 15-year old why they should be interested in programming as a discipline, why on earth would you do THIS? Felienne Hermans, in a recent article, described her experience in teaching beginners where a pupil commented “If I want Hello world on the screen, I can type that in Word.” (1) And that student is quite right!

The problem is not restricted to Hello World. When I was a student, we were told to write a program that prints out all the prime numbers from 1 to 100. This is a boring example. There is so much wrong with it.

Firstly, it’s Maths. Maths immediately puts off 80% of your class.

Secondly, if you really wanted to know the prime numbers up to 100, what would you do? No, you would not write a program for it. You would google it. It would take you about three seconds and bang! – there they are. Using a computer to solve this problem is entirely artificial. It makes nobody understand why you would want to learn to program.

Thirdly, the program is finished when it prints exactly what I knew it would print all along! To test my program, I would work out the complete answer myself, and then confirm that the program does it. You learn absolutely nothing from running the program. You might learn the program statements, but not why you would want to write them. It excites no one.

And fourthly, imagine a pupil is really quick, finishes the exercise after five minutes, while everyone else is just getting started. What do they do then? How can they stretch, extend, be creative? Add their own ideas, and grow? Print out the primes to 200?

The problems is that, once the program has run, there is absolutely no reason to ever run it again. A program that you do not want to run twice is not an interesting program.

So my advice is: use examples of programs where you actually need a computer to do the task! Games and simulations are such examples. Visualisation of data, or graphical animations. Use examples that give learners immediate ideas what they want to add!

Of course, you need an environment that supports this, and makes it easy enough to do this from your first hour of teaching. But these exist. Use them!

Every time I see another “What is your name? Hello Michael” program, I could tear my hair out in frustration at how far we have not come.


(1) Felienne Hermans: The Story of Building Hedy: A Programming Language with Cognitive Science in Mind, Informatics in Education, Volume 23, Issue 4 (2024), pp. 791–822

Guideline 3: Read Code

The third guideline of teaching programming is to read code, lots of it, and early.

I have already talked about this in Guideline 2, which was about not starting with a blank screen. While Guideline 2 was aimed primarily at avoiding the empty-screen paralysis (and discussed code reading as a side issue), this one is explicitly about the importance of code reading as a skill, and not limited to the first example.

Many programming courses concentrate solely on code writing, and assume that – somehow – code reading will follow. Either it is assumed that this is an easy skill that exists automatically, or that it is acquired by osmosis somehow. More often teachers do not think about this much at all.

Code reading is, in fact, a valuable and separate skill that should be practiced. And it should be practiced early, since it is of great value to learning to write code.

For the first few projects (spanning weeks, if not months), start each project by handing out to students a partial, half written application, and make the goal to fix/complete/extend. In this way, the first task required is to read and understand the existing code, before working out what to extend and write. Discuss and require code reading explicitly.

A large amount of peripheral learning happens when reading well written code. We get benefits from an apprenticeship approach, where learners can copy the master’s practices at many levels, and learn by example.

This approach is also much more realistic as preparation for actual work: No new programmer joining a software company will, as their first task, be asked to write a new system from scratch. It is always the reading and extending of existing software.

Of course, this requires teachers to show students code that is worth reading, that embodies good practice, from which also techniques can be gleaned that are not the current focus of discussion. It requires teachers to use a significant number of well-written examples that exemplify good practice. Not all teachers will always be able to write such examples, but resources can be shared. Look for resources that support this approach.

Guideline 2: Don’t start with a blank screen

The second guideline from my 23-year-old paper told teachers not to make students start with a blank screen.

Putting learners in front of an empty screen and saying “Today we are going to write a program” always seemed very strange to me. I think programming may be the only discipline that that would ever approach learning this way. It is the equivalent of teaching English Literature, and making students write a story before they have ever read a story. (Or, indeed, heard a story, or know what a story is.)

Imagine French learners writing French before reading it. Or children learning to play the violin being taught to play without ever having heard music before.

Code reading is a skill that is (at least) as important as code writing.

So: Start by giving your students a small program that does something (hopefully interesting! – more on that later), and get them to execute and experiment. Then get them to make small modifications. Let them experiment.

And free yourself from that idea that you have to completely explain everything they see on screen before they are allowed to look at it! Young learners are resilient – they can cope with a bit of intrigue and mystery.

Sitting in front of an empty screen as a beginner can have a paralysing effect. Being able to experiment and play is an easier, less intimidating approach. Bonus: The quick learners can make guesses and experiment.

Starting with a blank screen requires knowledge, planning and design. Tinkering is easier and gets you further quicker. And it makes it easier to show interesting examples early. (More on interesting examples later.)

In your first class, creating curiosity and engagement is more important than teaching the first bit of syntax. At the end of the class, you want them wanting to come back wanting to know more, not running away from a dispiriting experience.

Guideline 1: Objects First

The first of the guidelines for programming teaching from 2001 stated that you should start teaching objects from the start.

This, perhaps, is the least convincing of the guidelines today. In 2001, when I was thinking about teaching beginners, I was thinking about teaching first-year university students. Thus, it was a selective audience who had chosen to become software professionals.

Today, novice programming teaching is mainly an affair happening at school age. And we have to be aware of the difference it creates: most of the pupils do not want to become software professionals, and they do not all have to learn about best practice in software engineering.

Thus, it is a perfectly fine path today to teach an introduction to programming without objects. (More on this in a later post.)

But I would maintain: IF you want to end up with object-orientation, then you should START with objects. Object-based programming is not a language construct that can be added on to procedural programming later. It requires a different structure of the program, a different way of thinking, a different approach to algorithmic problem solving. If it is not done from the start, it would require unlearning habits later, and start again in a new way. This rarely works well.

So, I would maintain my advice from 23 years ago: If you want to teach object-orientation, start with objects on day 1!

Guidelines for Teaching Programming

How to teach programming is a hot topic again. 23 years ago (!) I wrote a paper titled “Guidelines for Teaching Object Orientation with Java” that provided some guidelines (eight, to be exact).

And although, as the title suggests, this was specific to OO and Java, I was wondering how many of these would stand up today. I was surprised to see that almost all of it – I think – is still relevant, and almost all of it we still cannot take for granted.

So I will, over the next few days, revisit the guidelines here, one at a time, and add my comments outlining how much of each I think still applies in “modern times”.

Watch this space over the next week or two for the discussion.

A brief history of programming languages

While I was thinking about the history of programming languages recently, I remembered slides I once made, showing a (simplified) family/influence/history diagram of languages.

Shared he in case it’s useful to anyone.

(It was made many years ago, so not up to date after 2010 – sorry. And I fully expect your comments correcting my interpretations…)

Some programming languages and their relationships (up to 2010)

Languages with C-style syntax

Functional languages (some languages intentionally on the border…)

Object-oriented languages (some languages intentionally on the border)

Here is a PDF file with the same diagrams.

In Honour of Niklaus Wirth

Niklaus Wirth died in Zürich on 1st January 2024. He was one of the great pioneers of programming language design, and specifically design of languages for education.

His languages were a huge influence on me, and on my thinking. Pascal was one of the first languages I learned, and Modula-2 and Oberon also opened worlds to me when I understood what lay behind their design.

The Informatics in Education journal has just published a special edition to honour Wirth’s tremendous contribution to our community. I contributed an article to this edition, titled Principles of Educational Programming Language Design.

I invite you to read it; it might be of interest to you if you are interested in programming language history, in the design of programming languages or in programming education.

The entire special edition is worth a look. It contains many other interesting contributions.


In 2002, I had the honour to introduce Wirth’s keynote address at the ITiCSE conference in Aarhus, and to have dinner with him. One of my treasured memories.

Image of Niklaus Wirth and Michael Kölling, sitting at a table at dinner.

Niklaus Wirth and I (in much younger years), at the conference dinner at ITiCSE 2002, in Aarhus

Sitting at a dinner table, chatting, are (from left to right): Michael Kölling, Niklaus Wirth, Michael E Caspersen, David Gries

At the ITiCSE 2002 conference dinner (left to right): Michael Kölling, Niklaus Wirth, Michael E Caspersen, David Gries

Designing a programming language: Don’t Be Clever

One lesson of programming language design? Don’t try to be too clever!

Here is an example from JavaScript​:

When you compare

0 == ‘0’

the system tries to be clever: “Comparing a number and a string? You probably meant to see whether the string contains the character ‘0’, so let’s just say ‘yes’!”, it thinks. So the result is true.

When you compare

0 == ”

it tries to be even cleverer: “Ahh, perhaps you meant to check whether the length of the string is zero! Let’s just help the user here and not require them to call a ‘length’ function. So tedious. It’s true!”

But of course

‘0’ == ”

“Comparing two strings – got it. Are they the same? No! Returning false.”

The result of all this: The fundamental property of transitivity of equality is broken in JavaScript!

a == b and b == c, therefore a == c ?

Not in JavaScript, it isn’t! How can anyone voluntarily program in a language like this?!

The lessons for me? Give me static typing any day. And don’t try to be clever when designing a language. Spelling things out is a good thing, not a bad thing.

The terrible state of MCQs

In academia – as in many other contexts – Multiple Choice Questions (MCQs) are a fact of life. We have many situations in which we need to assess a large cohort of learners, and MCQs make this easier.

Here, I don’t want to debate the value of MCQs as an examination technique in general, but talk about how they are written. If we accept that they are part of our work, let’s at least make them not terrible.

There are three very common ways in which MCQs can be obviously bad. I see them all the time.

They are:

  1. The question only examines surface knowledge
  2. The distractors are random
  3. The off-by-one way of writing distractors

Let’s look at each briefly.

The question only examines surface knowledge

This is quite an easy and obvious shortcoming to recognise: Often, MCQs just ask questions about terminology. They do not touch on concepts or deeper understanding. This is a very common trap to fall into for people who are not used to writing MCQs. Writing MCQs that test understanding is harder, and it’s easy to slip into the trap of just testing surface issues.

We have probably all seen it.

When you write your questions, examine each question critically in this light. Strive for meaningful questions.

The distractors are random

Another very common gripe of mine is that the distractors (the incorrect options in MCQs) are chosen at random. Let’s consider an example. Assume we have this question:

Question 54:

What is the output of the following segment of code?

        int sum = 0;   
        for (int i=0; i<=5; i+=2) {
            sum = sum + i;
        }
        System.out.println(sum);

If you speak Java, then you can work out that the answer is 6. So we use 6 as one of the possible options, and add a few random distractors:

Answer:

(A) 1
(B) 896
(C) 6
(D) -4
(E) 5

In this case, if students have a common misconception, they may arrive at an answer that is not on the list. For example, a student who does not understand that this definition makes the loop increment by 2 might assume that the answer is 15. But 15 is not on the list. So the student is implicitly told that they are wrong, and they can discard unlikely options (“Negative? – No.” “More then 800? – No.”) and make a random guess between a few remaining options.

This question is even worse in a way: Another common mistake is not being able to correctly distinguish between <= and < in the loop condition, and getting the answer wrong because of this. The way the question is written, however, it is not even possible to expose this misconception, because both variants happen to result in the same output!

A badly written question.

The off-by-one way of writing distractors

The other very common pattern I see all the time has an example in this question.

Question 31:

 Which of the following code segment would execute the stored procedure “getPassword()” located in a database server?

  1. CallableStatement cs = con.prepareCall("{call.getPassword()}");
    cs.executeQuery();
  2. CallabledStatement callable = con.prepareCall("{call getPassword()}");
    callable.executeUpdate();
  3. CallableStatement cab = con.prepareCall("{call getPassword()}");
    cab.executeQuery();
  4. Callablestatement cstate = con.prepareCall("{call getpassword()}");
    cstate.executeQuery();

The way questions like this are written is usually this: The question setter writes the correct response, and then creates three distractors by introducing one error in each.

It is trivial to reverse-engineer the correct answer from this. To do this, we spot the differences, and for each differences discard the odd one out. For example:

  • One difference is that “{call getpassword()}” is written with a dot in the middle once, but without the dot three times. So the dot is the odd one out, we discard Answer 1.
  • Another difference: CallableStatement is written with w capital S three times, with lowercase s once. So we discard answer 4.
  • Last one: The second line calls executeQuery() three times, and executeUpdate() once. Answer 2 is out.

And voilà – there is our answer: 3. We can do this without any knowledge or understanding of the subject matter. Keep your eyes open for this pattern in MCQ tests. It is astonishing how often you will see this question pattern.

A better example

Here is an example of something you could do:

Question 8:

HashMap<Integer, String> myMap = new HashMap<>();

myMap.put(2, "Tiger");
myMap.put(4, "Lion");
myMap.put(13, "Lion");
myMap.put(2, "Elephant");
myMap.put(3, "Chicken");

System.out.println(myMap.get(2));

When you try to compile and run this code, what will happen?

    1. The code has an error, because the value “Lion” is used twice in the HashMap.
    2. The code has an error, because the key 2 is used twice in the HashMap.
    3. The code will run and print “Tiger”.
    4. The code will run and print “Lion”.
    5. The code will run and print “Elephant”.

 In this case, the question tests an understanding of how maps work.

  • Option 1 tests the possible misconception that values cannot appear twice in a map.
  • Keys, on the other hand, are unique in a map. Option 2 tests the misconception that they cannot be replaced by a new entry.
  • Option 3 tests the misconception that the first entry for a given key persists.
  • Option 4 tests the misconception that the get(n)-parameter is an index, mirroring list-behaviour (referring to either the second or third element entered, depending whether the list is zero-based or one-based).
  • And Option 5 is correct.

This is by far not all that there is to say about MCQ writing. But it’s a start. It is the absolute minimum you should consider if ever you find yourself in the position to write and MCQ test.