2.3.1

Defensive design

Anticipating misuse, authentication, input validation and maintainable code.

Learning Objectives

  • 1Understand the issues a programmer should consider to cater for all likely input values
  • 2Understand how to deal with invalid data in a program
  • 3Understand authentication and design simple authentication
  • 4Design input validation for a given scenario
  • 5Understand why commenting and other maintainability techniques are useful

What is defensive design?

Defensive design means building a program that expects users to make mistakes or try to break it, and handles that gracefully instead of crashing or producing nonsense. It is about anticipating misuse before it happens.
Defensive design means designing a program to anticipate misuse, whether accidental (a user mistyping something) or deliberate (a user trying to enter something the program was never meant to handle). Good defensive design reduces bugs, keeps the program behaving as expected regardless of what is typed in, and accounts for likely input errors before they happen.
Anticipating misuse means considering, at the design stage, every realistic way a user could enter unexpected data, not just the "happy path" where everyone behaves correctly. This includes blank input, input of the wrong data type, input outside a sensible range, and deliberate attempts to break the program. Defensive design and input validation are closely linked in mark schemes: a specific validation example is often accepted as a valid expansion of "anticipating misuse".

Authentication

Authentication means checking that a user really is who they say they are, most commonly with a username and password.
Authentication is the process of confirming a user's identity before giving them access to a system, typically by checking a username and password combination against stored records. This stops unauthorised people from accessing an account or its data.
Authentication confirms identity; it is not the same as validation, which only checks that entered data is an acceptable format or value, not who entered it. A password could pass every validation check (right length, right characters) and still fail authentication if it's simply the wrong password for that username.
Python· A simple username and password authentication check
stored_password = "Sc1ence123"
entered_password = input("Enter your password: ")

if entered_password == stored_password:
    print("Access granted")
else:
    print("Access denied")
OCR ERL· A simple username and password authentication check
storedPassword = "Sc1ence123"
enteredPassword = input("Enter your password: ")

if enteredPassword == storedPassword then
    print("Access granted")
else
    print("Access denied")
endif

Input validation

Validation checks that data entered is sensible before the program tries to use it, for example checking a box hasn't been left blank, or that a number is in the right range.
Validation is the process of checking that input data is appropriate for its use, so the program can process it without errors. Common checks include a presence check (data hasn't been left blank), a range check (a number falls within acceptable bounds), and a length check (text is a required minimum/maximum number of characters).
Validation checks that data is a sensible format or value, it does not check that the data is actually true or correct, for example a range check on age would accept 30 as valid even if the real user is actually 25. When combining two bounds in a range check, each part of the condition must reference the variable separately, e.g. total >= 10 AND total <= 20, not total >= 10 AND <= 20.
Validation checks, and what each rejectsPresence checkwas anything entered at all?""RejectedRange checkis the number within 0 to 120?150RejectedLength checkis it at least 8 characters?"abc"RejectedValidation checks data is sensibleIt cannot check the data is actually true
Python· Presence, range and length checks
name = input("Enter your name: ")
if name == "":
    print("Name cannot be blank")

age = int(input("Enter your age: "))
if age < 0 or age > 120:
    print("Age out of range")

password = input("Enter a password (min 8 characters): ")
if len(password) < 8:
    print("Password too short")
OCR ERL· Presence, range and length checks
name = input("Enter your name: ")
if name == "" then
    print("Name cannot be blank")
endif

age = int(input("Enter your age: "))
if age < 0 OR age > 120 then
    print("Age out of range")
endif

password = input("Enter a password (min 8 characters): ")
if password.length < 8 then
    print("Password too short")
endif

Maintainability: sub-programs and naming conventions

Maintainable code is code that is easy for a programmer (including someone other than the original author) to read, understand, fix and improve later. Breaking code into sub-programs and using sensible variable names are two key ways to make code maintainable.
Using sub-programs (functions and procedures) breaks a program into smaller, manageable, reusable chunks, which are easier to test individually and don't need to be rewritten wherever they're needed. Naming conventions means giving variables, functions and procedures names that clearly describe their purpose, e.g. density rather than num3, so anyone reading the code can follow what it does without extra explanation.
Maintainability is a distinct concept from testing, and OCR examiners have specifically flagged confusing the two as a common error, testing is about finding whether a program works correctly; maintainability is about how easy the code is to read, understand and modify afterwards. A program can be fully correct (pass every test) and still be badly written and hard to maintain.
Python· Poor vs clear naming conventions
# Poor: unclear what each variable represents
num1 = float(input("Enter the mass: "))
num2 = float(input("Enter the volume: "))
num3 = num1 / num2

# Clear: purpose of each variable is obvious
mass = float(input("Enter the mass: "))
volume = float(input("Enter the volume: "))
density = mass / volume
OCR ERL· Poor vs clear naming conventions
// Poor: unclear what each variable represents
num1 = real(input("Enter the mass: "))
num2 = real(input("Enter the volume: "))
num3 = num1 / num2

// Clear: purpose of each variable is obvious
mass = real(input("Enter the mass: "))
volume = real(input("Enter the volume: "))
density = mass / volume

Maintainability: indentation and commenting

Indentation lines up code so it's visually clear which lines belong inside a loop or IF statement. Comments are short notes in the code, ignored by the computer, explaining what a piece of code does for anyone reading it later.
Consistent indentation makes the structure of a program (which lines are inside a loop, IF statement, or function) immediately visible, rather than having to trace through carefully. Comments explain the purpose of a line, block or function in plain English; in Python these start with #, in OCR's Exam Reference Language with //.
Comments should explain why something is done, or clarify a non-obvious purpose, not simply restate what the code already makes clear. Adding comments to code that is already well-structured and correctly indented does not itself improve maintainability, if a question gives code that is already well-indented, suggesting "add indentation" is not a valid improvement.
Python· Commenting a function
def add_numbers(num1, num2):
    total = num1 + num2   # Adds the two numbers together
    return total            # Sends the result back to the caller
OCR ERL· Commenting a function
function addNumbers(num1, num2)
    total = num1 + num2   // Adds the two numbers together
    return total            // Sends the result back to the caller
endfunction

Exam Phrasing: Use These Exact Phrases

  • ✓Defensive design means anticipating misuse and designing a program to handle it
  • ✓Authentication confirms the identity of a user, usually with a username and password
  • ✓Validation checks that data is an acceptable format or value before it is processed
  • ✓Maintainable code is easy to read, understand and modify, using sub-programs, sensible naming, indentation and comments
  • 💡Don't confuse maintainability with testing, they are two separate, specifically distinguished topics in past examiner reports.
  • 💡When suggesting a maintainability improvement, refer to the specific code given in the question, not a generic list of techniques.
  • 💡If code shown in a question is already well-indented, don't suggest "add indentation" as an improvement, it must be a genuine improvement to what's shown.
  • 💡A validation example (e.g. a specific range check) can also count as an example of anticipating misuse, these mark points often overlap.
  • 💡In a range check condition, always repeat the variable in both parts, e.g. total >= 10 AND total <= 20.

Wrong:

Leaving the quotation marks off a string, e.g. if answer == yes then

Right:

Put quotation marks around string values, e.g. if answer == "yes" then

Why it matters: OCR examiners flagged this. Without the quotes, yes reads as a variable name rather than a piece of text, so the comparison does something quite different.

Wrong:

Maintainability and testing are the same thing

Right:

Maintainability is about how easy code is to read and modify; testing is about checking a program works correctly

Why it matters: Examiners specifically noted that candidates who did less well on this paper confused maintainability with testing.

Wrong:

if total >= 10 AND <= 20 then

Right:

if total >= 10 AND total <= 20 then

Why it matters: The second part of the condition must reference the variable again, otherwise it has nothing to compare against.

Wrong:

Suggesting "add comments" or "add indentation" as an improvement when code is already well-commented/indented

Right:

Only suggest an improvement that genuinely applies to the specific code shown

Why it matters: Examiners do not credit improvements that have clearly already been done in the code given.

Question:

A program asks the user to enter their age, and should only accept ages from 0 to 120. Write validation code to check the age is within this range, and reject it otherwise. [3]

Python· Model answer
age = int(input("Enter your age: "))
if age < 0 or age > 120:
    print("Invalid age")
else:
    print("Age accepted")
OCR ERL· Model answer
age = int(input("Enter your age: "))
if age < 0 OR age > 120 then
    print("Invalid age")
else
    print("Age accepted")
endif

💡 Attempt this before revealing the answer, practice makes perfect!

Model Answer:

The program takes the age as input and casts it to an integer, then checks whether it is less than 0 or greater than 120 using a range check. If either condition is true, the age is rejected as out of range; otherwise, it is accepted.

Mark Scheme:

  • 1Correctly casts the input to an integer
  • 2Correctly checks age is less than 0 OR greater than 120 (both boundaries referenced correctly)
  • 3Correctly rejects/flags the value when out of range

Tap a card to flip it. Use the arrow keys to move and space to flip.

Known 0 Still learning 0
1 / 12

Exam-style questions. Have a go, then reveal the mark scheme to check your answer.

1.Explain the difference between authentication and validation.

[2]

2.A registration form requires a password of at least 8 characters. Write code to validate this, rejecting passwords that are too short.

[2]

3.Describe two maintainability techniques a programmer could use, other than commenting.

[2]

4.A student describes an algorithm as "not maintainable because it doesn't work correctly for large inputs". Explain why this is an incorrect use of the term "maintainable".

[2]

5.A booking system asks for the number of tickets, which must be between 1 and 4 inclusive. Write validation code to check this, and explain why both boundary values (1 and 4) must be included in your check.

[4]
Python· Model answer
tickets = int(input("Enter number of tickets: "))
if tickets >= 1 and tickets <= 4:
    print("Accepted")
else:
    print("Invalid number of tickets")
OCR ERL· Model answer
tickets = int(input("Enter number of tickets: "))
if tickets >= 1 AND tickets <= 4 then
    print("Accepted")
else
    print("Invalid number of tickets")
endif

6.Explain how a programmer could make a login system robust, referring to input validation, authentication and maintainability.

[6]

The examiners' reports are the most useful and least read of the three: they say what candidates actually got wrong each year. All files are hosted by OCR.

Past-paper questions grouped by topic

The same OCR questions, sorted by topic rather than by year (via Physics & Maths Tutor).

2024
Paper 2

Candidates who did less well on the paper commonly confused maintainability of a program with testing, these are two distinct required concepts (2.3.1 and 2.3.2) and should not be conflated in answers.

Paper 2

When describing how defensive design could be used in a given scenario, examiners noted that many mark scheme points crossed over, for example a specific validation example was accepted as a sensible expansion of 'anticipating misuse'. Candidates needed to both name a technique and describe how it was used, generically or with a specific example, to gain full marks.

Paper 2

A recurring misconception across multiple questions: when a selection statement needs to check that a value is between two bounds, both parts of the condition must reference the variable, e.g. if total >= 10 AND total <= 20 then. Writing if total >= 10 AND <= 20 then is a syntax error, since the second part has nothing to compare against.