Defensive design and validation
Anticipating misuse; presence, type, range, length, format and look-up checks.
Covers OCR J277 2.3.1 Defensive design · AQA 8525 3.2.11 Robust and secure programming · Edexcel 1CP2 3.2.3 Robust software · Edexcel 1CP2 6.4.3 Validation
Do this lesson in the simulatorPrint it: worksheet (PDF) · answers (PDF) · as a web page
Every program so far has trusted its user. Type twenty where a number is wanted and it crashes; type 500 and the robot drives off the table. Real users mistype, misunderstand, and sometimes try to break things on purpose. Defensive design means writing programs that expect this and cope with it. The first line of defence is validation: checking input before using it.
What goes wrong without it
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
far = int(input("How far shall I drive, 1 to 50 cm? "))
forward(60, distance=far)
print("drove", far, "cm")
Run it four times, typing 20, then nothing (just press Enter), then lots, then 500. Two of those crash with a ValueError. With 500 the robot hits the far edge of the mat after about 8 seconds and keeps grinding along it until the 60 second time limit stops the program, so it never even prints drove. None of them is the user's fault in a way the robot can blame them for: the program should have checked.
The validation checks
| Check | Question it asks | Example |
|---|---|---|
| Presence | Was anything entered at all? | the answer is not empty |
| Type | Is it the right kind of data? | it is a whole number, not lots |
| Range | Is it between sensible limits? | it is from 1 to 50 |
| Length | Does it have the right number of characters? | a robot name of 3 to 12 letters |
| Format | Does it match a pattern? | a class code of six capital letters and digits |
| Look-up | Is it one of the allowed values? | the colour is red, green or blue |
Validation checks that data is sensible, not that it is correct. A range check accepts 30 when the user meant 20; it only rejects answers that could never be right.
Checking in order
Some checks only make sense after others: you cannot check the range of something that is not a number. So check presence, then type, then range:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
answer = input("How far, 1 to 50 cm? ")
if answer == "":
print("you must type something")
elif not answer.isdigit():
print("that is not a whole number")
elif not 1 <= int(answer) <= 50:
print("it must be between 1 and 50")
else:
forward(60, distance=int(answer))
print("drove", answer, "cm")
isdigit() is True only when every character is a digit, so it is False for "", "lots", "-5" and "2.5". Only after it passes is int() safe to call.
Asking until it is valid
Rejecting bad input is only half the job. A friendly program asks again, which is a while loop around the checks:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
def ask_distance():
"""Keep asking until the answer is a whole number from 1 to 50, then return it."""
while True:
answer = input("How far, 1 to 50 cm? ")
if answer == "":
print("you must type something")
elif not answer.isdigit():
print("that is not a whole number")
elif not 1 <= int(answer) <= 50:
print("it must be between 1 and 50")
else:
return int(answer)
tone(220, 0.2)
far = ask_distance()
forward(60, distance=far)
print("drove", far, "cm")
Putting the validation in a function means the rest of the program can rely on getting a good value, and the same checks can be used every time the program asks.
Length, format and look-up
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
name = input("Robot name, 3 to 12 letters? ")
if not 3 <= len(name) <= 12:
print("length check failed")
elif not name.isalpha():
print("format check failed: letters only")
else:
print("hello,", name)
colour = input("Light colour? ").lower()
if colour in ["red", "green", "blue"]:
led(colour)
else:
print("look-up check failed: choose red, green or blue")
.lower() before a look-up check means Red and RED are accepted too: being defensive also means not rejecting answers for no good reason.
Anticipating misuse
Validation deals with the input you expect. Defensive design also asks: what could a user do that you did not expect? Type a thousand characters? Give a negative speed? Keep the robot driving towards a wall? For a robot, some checks belong in the program even when the input is valid: never drive when distance() says there is a wall 5 cm ahead, whatever the user asked for.
Task: a validated drive
Write a program that asks How far, 1 to 50 cm? until the answer is valid, then drives that far forward. For an empty answer print you must type something; for one that is not a whole number print that is not a whole number; for a number out of range print it must be between 1 and 50. The task types an empty answer, then fifty, then 500, then 30.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
far = int(input("How far, 1 to 50 cm? "))
forward(60, distance=far)
Challenges
- Accept distances with a decimal point, such as
12.5, while still rejectingtwelve. - Add a check that refuses to drive if
distance()shows a wall closer than the distance asked for, plus 5 cm. - Validate a class code: exactly six characters, only capital letters and digits.
Past paper questions on this
Real exam questions that test this, each worked through with a program you can run.
- AQA 8525 June 2025 Paper 1, Question 4: Validate a name by length until it is accepted, test data, and a username flowchart 13 marks
- AQA 8525 June 2023 Paper 1, Question 4: Trace a Python function with three sets of inputs, then make it robust 4 marks
- AQA 8525 June 2023 Paper 1, Question 13: Validate a grid reference until it is correct 6 marks
- AQA 8525 June 2022 Paper 1, Question 13.1: Keep asking until a number is between 1 and 100 4 marks
- AQA 8525 Sample Paper 1, Question 18: Go-kart braking distance: validate the speed, divide by 5, wet ground 8 marks
- OCR J277 June 2025 Paper 2, Question 1: Normal, boundary and invalid test data, and a 1 to 100 range check 9 marks
- OCR J277 June 2025 Paper 2, Question 5(d): Validate a 4 character PIN that must not be 1234 or 4321 6 marks
- OCR J277 June 2024 Paper 2, Question 9(c): A range check that outputs VALID or NOT VALID, and its test data 7 marks