You are viewing a free preview of this lesson.
Subscribe to unlock all 10 lessons in this course and every other course on LearningBro.
This lesson introduces defensive design as required by OCR J277 Section 2.4. Defensive design is a programming approach that anticipates potential problems and builds safeguards into the code to prevent errors, misuse, and security vulnerabilities. This topic is distinctive to OCR and is central to producing robust programs.
Defensive design means writing code that anticipates things going wrong and handles them gracefully. Instead of assuming the user will always provide valid input or that the system will always work perfectly, a defensive programmer plans for errors.
The key principles of defensive design include:
| Principle | Description |
|---|---|
| Input validation | Checking that data entered by the user is reasonable and correct before processing it |
| Authentication | Verifying the identity of users before allowing access |
| Planning for contingencies | Handling unexpected situations (e.g. file not found, network errors) |
| Maintainability | Writing code that is easy to read, understand, and modify |
flowchart TD
DD[Defensive design] --> AM[Anticipate misuse]
DD --> IV[Input validation]
DD --> AU[Authentication]
DD --> MA[Maintainability]
AM --> AM1[Plan for empty / wrong type / out-of-range / malicious input]
IV --> IV1[Range / Type / Presence / Format / Length / Lookup checks]
AU --> AU1["Username + password<br/>limited attempts + lockout"]
MA --> MA1["Comments, meaningful names,<br/>indentation, subroutines, constants"]
AM1 --> R[Robust program — handles errors gracefully]
IV1 --> R
AU1 --> R
MA1 --> R
Programs interact with users, files, networks, and other systems — all of which can produce unexpected data or behaviour. Without defensive design:
OCR Exam Tip: When the exam asks about defensive design, always link it to the idea of making programs more robust — meaning they can handle unexpected situations without crashing or producing incorrect results.
# Dangerous — no validation, no error handling
age = int(input("Enter your age: "))
print("In 10 years you will be", age + 10)
What could go wrong?
OCR Pseudocode:
do
age = input("Enter your age: ")
if NOT age.isNumeric() then
print("Error: please enter a number")
elseif int(age) < 0 OR int(age) > 150 then
print("Error: age must be between 0 and 150")
endif
until age.isNumeric() AND int(age) >= 0 AND int(age) <= 150
age = int(age)
print("In 10 years you will be " + str(age + 10))
Python:
while True:
age_input = input("Enter your age: ")
if not age_input.isdigit():
print("Error: please enter a number")
elif int(age_input) < 0 or int(age_input) > 150:
print("Error: age must be between 0 and 150")
else:
break
age = int(age_input)
print("In 10 years you will be", age + 10)
This version handles:
Always assume users may enter unexpected data — either accidentally or deliberately. Design your program to handle:
When something goes wrong, the program should:
| Stage | Defensive Design Activity |
|---|---|
| Design | Identify potential inputs, edge cases, and risks |
| Implementation | Add validation, error handling, and authentication |
| Testing | Use normal, boundary, and erroneous test data |
| Maintenance | Write clear, well-commented, maintainable code |
OCR Exam Tip: Defensive design questions often ask you to identify what could go wrong with a piece of code and suggest improvements. Look for: missing validation, no error messages, potential crashes from bad input, and lack of authentication. Each improvement you suggest should be linked to a specific problem.
A science club is collecting daily temperature readings. A programmer has written a quick program to read temperature values from the user and store them. The prototype has no defensive design and several problems.
Prototype (no defensive design):
temps = []
for i = 0 to 6
t = int(input("Day " + str(i+1) + " temp: "))
temps.append(t)
next i
total = 0
for t in temps
total = total + t
next t
print("Average: " + str(total / 7))
Trace table for inputs 15, 18, "warm", 20, 22, 19, 21:
| Step | i | input | action |
|---|---|---|---|
| 1 | 0 | 15 | stored |
| 2 | 1 | 18 | stored |
| 3 | 2 | "warm" | CRASH — int() fails |
Bugs identified: (1) no type check — non-numeric input crashes the program mid-way through data collection; (2) no range check — a typo of 900 instead of 9.0 would distort the average silently (logic error hidden by bad data); (3) no authentication — anyone can run the script and overwrite yesterday's readings; (4) no feedback after a successful read; (5) magic number 7 appears twice.
Refactored pseudocode applying defensive design:
const DAYS = 7
const MIN_TEMP = -30
const MAX_TEMP = 50
// Simple authentication
storedPin = "4242"
attempts = 0
authenticated = false
while attempts < 3 AND NOT authenticated
pin = input("PIN: ")
if pin == storedPin then authenticated = true
else attempts = attempts + 1 endif
endwhile
if NOT authenticated then
print("Access denied.")
exit
endif
// Validated input collection
temps = []
for i = 0 to DAYS - 1
do
raw = input("Day " + str(i+1) + " temp: ")
valid = true
if raw == "" then valid = false
elseif NOT raw.isNumeric() then valid = false
else
t = float(raw)
if t < MIN_TEMP OR t > MAX_TEMP then valid = false endif
endif
if NOT valid then print("Enter a number between " + str(MIN_TEMP) + " and " + str(MAX_TEMP)) endif
until valid
temps.append(t)
print("Recorded: " + str(t))
next i
total = 0
for t in temps
total = total + t
next t
print("Average: " + str(total / DAYS))
Test plan:
| Test | Inputs | Type | Expected |
|---|---|---|---|
| 1 | 15,18,20,22,19,21,17 | Normal | Average printed |
| 2 | -30 and 50 included | Boundary (valid) | Accepted |
| 3 | -31, 51 | Boundary (invalid) | Rejected, re-prompt |
| 4 | "warm" | Erroneous (type) | Rejected, re-prompt |
| 5 | "" | Erroneous (presence) | Rejected, re-prompt |
| 6 | Wrong PIN x3 | Security | Access denied |
The refactor shows all four principles of defensive design working together: anticipating misuse (PIN, attempt limit), input validation (presence + type + range), authentication (PIN check with lockout) and maintainability (named constants, clear prompts).
Misconception: Defensive design is not just "add some if statements". Many students think printing an error message is enough. Defensive design means preventing the bad state — rejecting input that would cause a crash before the dangerous operation runs (e.g. check isNumeric before int()), not catching the crash afterwards. A program that displays a nice error but still corrupts its data is not robust.
Exam question (6 marks): "Explain what defensive design means and describe how it could be applied to a program that reads weekly temperature readings."
Grade 3-4 answer: "Defensive design is when you stop the program going wrong. You check the user's input is ok. If they type letters instead of numbers you show an error. You should not let anyone use the program who shouldn't."
Examiner commentary: General understanding is present but no specific techniques are named and no example is worked through. No mention of validation, authentication, or maintainability. Marks: 1-2 out of 6.
Grade 5-6 answer: "Defensive design means writing programs that anticipate errors. For a temperature logger, input validation would check each entry is numeric (type check) and within a sensible range such as -30 to 50 (range check), rejecting bad input with an error message and asking again. Authentication with a PIN prevents unauthorised people overwriting the data. Comments and meaningful variable names make the program easier to maintain. Testing with normal, boundary and erroneous data confirms the program is robust."
Examiner commentary: Correct terminology (input validation, type check, range check, authentication, maintenance, test data classes), each linked to the scenario. Missing: explicit mention of attempt limits, why rejecting before the dangerous operation matters. Marks: 4-5 out of 6.
Grade 7-9 answer: "Defensive design produces robust programs by anticipating misuse, validating input, authenticating users and structuring the code for maintenance. For a temperature logger: authentication requires a PIN with a three-attempt lockout so unauthorised users cannot overwrite data. Input validation applies a presence check (non-empty), a type check (isNumeric before int conversion to prevent a runtime error) and a range check (-30 ≤ t ≤ 50) on every reading; bad input is rejected and re-prompted rather than allowed to propagate. Maintainability uses named constants (DAYS, MIN_TEMP, MAX_TEMP), meaningful identifiers and comments so a future developer can change the valid range in one place. Testing exercises the validation with normal (20°C), boundary (-30, -31, 50, 51) and erroneous ('warm', '') data, plus authentication attacks (wrong PIN three times). Each technique targets a specific failure mode: validation prevents crashes and data corruption; authentication prevents misuse; maintainability reduces the cost of future change; testing confirms all three are effective."
Examiner commentary: Full-mark response — names every OCR technique, links each to the scenario, references test data classes, explains why validation must run before the dangerous operation. Marks: 6 out of 6.
Top-performing answers typically add at least one of the following extensions: (a) a trace table showing the fault before and after the defensive change; (b) a reference to syntax, logic and runtime errors and which each technique prevents (validation prevents runtime errors on bad types; defensive design against misuse prevents logic errors from unsanitised input; structured code prevents syntax errors creeping in during maintenance); (c) a statement about the cost of repair — catching errors early via defensive design is cheaper than patching them in production; (d) a reference to iterative testing during development alongside final testing of the complete program. Weaving two of these extensions into a paragraph typically pushes an answer from 4-5 marks into the full-marks band.
A strong exam technique is to briefly quote the code and identify the specific line where the defensive technique would be applied — for example, "the line t = int(input(...)) should be preceded by a validation loop using isNumeric() and a range check". This demonstrates applied understanding, which is what the mark scheme rewards.
Use these short questions to confirm you have grasped the key ideas before moving on.
Sample answers:
This content is aligned with OCR GCSE Computer Science (J277) specification section 2.3 Producing robust programs. For the most accurate and up-to-date information, please refer to the official OCR specification document.