Techniques for Writing Correct and Robust Programs
Program correctness is the idea that programs should be free from errors.
Why Running Is Not the Same as Being Correct
A program can run from start to finish and still fail the people who depend on it. It can produce wrong results, or it can fail at the wrong moment. Either way, it has not met the central goal of this chapter. Writing a program that executes is only part of the job. The program also has to be free from errors, and getting there takes deliberate effort.
What do you think happens?
If a program runs without crashing and prints a result, can we conclude that it is correct?
Reveal answer
No, a program can run and still produce wrong results
The source is explicit that a program which runs but produces wrong results has not met the goal of being free from errors. Running without crashing and being correct are different things.
Correctness Is Pursued, Not Inherited
Program correctness is the idea that programs should be free from errors.
Correct programs do not just happen. A program does not become correct by default, and writing code is not enough on its own. Correctness has to be deliberately pursued.
The phrase correctness does not happen by accident is the core of this topic. A beginner may assume that careful typing alone produces working software. The source rejects that assumption. Errors are avoided through specific choices, and those choices have to be made on purpose.
Following a Program From Idea to Result
It helps to picture the path a program takes. It starts as an idea, becomes a plan, is written as code, and is then checked. At each stage, an error can enter. The source does not describe this path in detail, but it does say that the two stated means of avoiding errors are planning and attention to detail. Planning comes before and during writing code. Attention to detail is applied while the code is being written and reviewed.
- 1Start with an idea of what the program should do (this is where a misunderstood goal can introduce an error)
- 2Plan the program before and during writing code (planning is one of the two stated ways errors are avoided)
- 3Write the code while paying attention to detail (attention to detail applies during writing)
- 4Review the code while still paying attention to detail (attention to detail also applies during review)
- 5Check whether the result is actually correct, not just whether the program runs
Planning and Attention to Detail as Error Prevention
The source states that avoiding errors takes planning and attention to detail. These are the two requirements it names, and they work at different points in the process. Planning shapes what will be written before and during the writing of code. Attention to detail is the care taken while the code is being written and reviewed. Neither one alone is presented as sufficient in the source, which is why both are named together.
Planning looks ahead to what the program needs to do. Attention to detail looks closely at what the program actually says. A plan that is written carefully can still be undermined by a careless line of code, and carefully written code can still be built on a poor plan.
Tracing a Small Program That Runs but Is Wrong
The following small program is an illustration written for this article. Its job is to compute the average of a list of numbers. It runs without any error message, but it contains a mistake that makes its result wrong. Trace it step by step and watch the values change.
def average(nums):
total = sum(nums)
return total / (len(nums) + 1)
print(average([2, 4, 6]))- 1
sum([2, 4, 6])gives 12, so total becomes 12 - 2
len([2, 4, 6])gives 3, so the divisor is written as 3 + 1, which is 4 - 312 divided by 4 gives 3.0
- 4The correct average is 12 divided by 3, which is 4.0, so the printed result is wrong even though nothing crashed
- The function adds up the numbers in the list
- The divisor should be the count of numbers, which is 3 here
- The divisor is wrongly computed as one more than the count
3.0Finding the Error by Tracing Values
A program prints 3.0 for average([2, 4, 6]). Is this result correct, and where does the error come from?
- 1Compute the correct answer independently
The numbers are 2, 4 and 6. Their sum is 12 and there are 3 numbers, so the correct average is 4.0.
- 2Compare with the program's output
The program printed 3.0, which does not match 4.0. The program ran, but its result is wrong.
- 3Trace the value that causes the mismatch
The sum is correct at 12. The divisor is 4 instead of 3 because of the extra 1 added to
len(nums). - 4Correct the mistake and check again
Changing the divisor to
len(nums)gives 12 divided by 3, which is 4.0, matching the correct answer.
The result 3.0 is wrong. The error is the divisor, and it was only visible because the result was checked against an independently computed answer.
Techniques That Raise the Odds of Correctness
Beyond planning and attention to detail, the source says that programmers have techniques they can use to increase the likelihood that their programs are correct. The wording is deliberate. These techniques increase likelihood. They do not guarantee correctness, and the source does not claim they do.
The source does not name or describe these techniques in this introduction. Its purpose here is to establish that such techniques exist and what they are for. Their specific content is developed in the material that follows. This article therefore covers only the framing: why techniques are needed and what they aim to achieve.
Techniques aim to make correct programs more likely. They are not a substitute for planning and attention to detail, and they do not promise a bug-free result.
Mistakes Learners Make About Correctness
Common mistake Assuming a program is correct because it runs
What it looks likeThe averaging program above prints 3.0 with no error message.
Why it failsThe source says a program that runs but produces wrong results has not met the goal of being free from errors.
Do this insteadCheck results against an independently known answer.
Common mistake Believing correctness happens by default
Why it failsThe source states that correct programs do not just happen and that correctness has to be deliberately pursued.
Do this insteadPlan first, pay attention to detail while writing and reviewing, and use techniques deliberately.
Common mistake Treating techniques as a guarantee
Why it failsThe source says techniques increase the likelihood of correctness but do not guarantee it.
Do this insteadUse techniques as aids that raise the odds, while still checking results.
Common mistake Skipping planning and going straight to code without considering what the program should do
Practice Reasoning About Correctness
Using the averaging example, suppose a different program computes average([10, 20]) and prints 15.0. Without running any code, explain whether the result is correct, and describe which of the two stated means of avoiding errors (planning or attention to detail) would be most useful for catching a mistake of this kind.
Hints
- Compute the correct average of 10 and 20 yourself first
- Consider whether the mistake lies in the plan or in the detail of how the code is written
- Recall that the source says the result, not the absence of a crash, decides whether the program is correct
Key Takeaways
- Program correctness means that programs should be free from errors, and a program that runs but gives wrong results does not meet this goal.
- Correct programs do not just happen; correctness has to be deliberately pursued.
- The source names planning and attention to detail as the means of avoiding errors, with planning before and during writing and attention to detail while writing and reviewing.
- Techniques exist that increase the likelihood that programs are correct, but they do not guarantee it, and their specific content is covered in later material.