Learn · GCSE Computer Science · Component 2
OCR-GCSE-CS-ROBUST · Producing robust programs

Producing robust programs.

Written for OCR J277 Official specification ↗ Updated 2026.07.06

HookThe rocket that a data-type error destroyed 37 seconds after launch

On 4 June 1996, 37 seconds after lift-off, the European Space Agency's Ariane 5 rocket veered off course and blew itself up on its very first flight, taking about 370 million dollars of hardware with it. The cause was not a hardware fault. Software carried over from the older Ariane 4 tried to squeeze a large number, held as a 64-bit value, into a 16-bit space. The value did not fit, the conversion overflowed, nothing in the code was written to handle that possibility, and the guidance system failed. The new rocket had never been tested with its own real flight data.

You will not be launching rockets at GCSE, but Ariane 5 is the whole of this section in one disaster. Two ideas would have saved it, and they are exactly what 2.3 assesses. Defensive design means writing code that anticipates what could go wrong — unexpected values, misuse, malformed input — and copes gracefully instead of falling over. Testing means proving, before release, that the program does the right thing not only for sensible input but for the awkward, boundary and downright wrong input real users will throw at it. A robust program is simply one that keeps working when the data, or the person, misbehaves.

ModelDefensive design — anticipating misuse

Defensive design starts from a pessimistic assumption: users will do the unexpected, whether by accident or on purpose. The main weapon is input validation — checking that data is reasonable before the program acts on it. OCR expects several types: a range check (a month must be 1 to 12), a type check (an age must be a number), a length check (a password of at least eight characters), a presence check (a required field is not blank), and a format check (an email address contains an @). Validation usually sits inside a condition-controlled loop that keeps re-prompting until the input is acceptable.

Validation is not the only defence. Sanitisation cleans input by removing or neutralising characters that could cause harm — for example stripping out symbols that might be used in a database attack, or trimming stray spaces. Authentication confirms that a user is who they claim to be, most commonly through a username and password, so that only the right people reach sensitive features. And where validation cannot prevent every failure, defensive design also means handling errors that do slip through rather than letting the whole program crash — precisely the step Ariane 5 was missing.

Worked example

Validating an age that must be between 1 and 120, re-asking until it is acceptable:

age = int(input('Enter your age')) WHILE age < 1 OR age > 120 PRINT 'Invalid age, try again' age = int(input('Enter your age')) ENDWHILE

Trace three inputs. Entering 200: 200 > 120 is true, so the loop body runs and re-prompts. Entering -5: -5 < 1 is true, so it re-prompts again. Entering 17: 17 is neither below 1 nor above 120, so the condition is false, the loop ends, and the program continues with a value it can trust. This is a range check; a fuller version would also wrap the input in a type check so that typing 'twelve' does not crash the cast to int.

MechanismMaintainability — writing code others can fix

Most software outlives the moment it was written and is later changed by someone else — or by you, months on, having forgotten how it works. Maintainability is designing code so that future editing is quick and safe, and OCR lists concrete techniques for it. Comments explain why a section exists or how a tricky part works, without repeating what the code obviously does. Indentation makes the structure of selection and iteration visible at a glance, so a reader can see instantly which statements sit inside a loop. Sensible naming conventionstotalScore rather than x, a consistent style throughout — mean the code half-documents itself.

The biggest maintainability gain is the one that overlaps with decomposition: breaking a program into subprograms. A named function or procedure can be understood, tested and fixed on its own, and reused rather than copied, so a bug needs fixing in only one place. Cryptic, unindented, comment-free code with copy-pasted blocks may run perfectly today and still be a liability, because the next person cannot change it without breaking it.

Worked example

Compare two versions that do the same job. Hard to maintain:

d = p * 0.9

Easy to maintain:

// apply 10% loyalty discount CONST loyaltyRate = 0.9 discountedPrice = price * loyaltyRate

Both compute an identical result. The second tells the next programmer, in a comment, why the number 0.9 appears; replaces the mystery literal with a clearly named constant that can be updated in one place; and uses full, descriptive variable names. Nothing about how the computer runs the line has changed — but the cost of safely editing it later has fallen dramatically, which is the entire point of maintainability.

ModelTesting — purpose, types and kinds of error

The purpose of testing is to find errors before users do, and to give evidence that the program meets its requirements. OCR distinguishes two moments for it. Iterative testing happens throughout development: you build a small piece, test it, fix it and only then move on, so bugs are caught while they are cheap and easy to locate. Terminal (final) testing happens once the program is complete, checking that all the parts work together and that the whole thing meets the original specification.

Testing hunts two kinds of error. A syntax error breaks the rules of the language — a missing bracket, a misspelled keyword — and it stops the program from running or translating at all, so it is usually easy to spot because the computer refuses to proceed. A logic error is far more dangerous: the program runs perfectly happily but produces the wrong result, because the instructions, though valid, do not do what was intended. Logic errors do not announce themselves; the only way to catch them is to test with input whose correct output you already know, and compare.

Worked example

This code should output the average of three marks, but it contains a logic error:

marks = [4, 8, 6] total = 0 FOR i = 0 TO 2 total = total + marks[i] NEXT i average = total / 2 PRINT average

The program runs without complaint — there is no syntax error — so a careless glance would pass it. Trace it with a known answer: the loop correctly builds total = 4 + 8 + 6 = 18, but the final line divides by 2 instead of 3, giving 18 / 2 = 9 when the true average of three marks is 6. Because you knew the expected result in advance, the wrong output exposes the logic error; changing the divisor to 3 (or better, to the number of items in the array) fixes it.

DataChoosing test data — normal, boundary and erroneous

Good testing is not about running lots of random inputs; it is about choosing a small set of deliberate ones that between them exercise every path. OCR names three categories. Normal (valid) data is typical, sensible input the program should accept and process — a value comfortably inside the allowed range. Boundary (extreme) data sits right on the edge of what is allowed, on both sides, because edges are where off-by-one mistakes hide — this is the most productive category for finding bugs. Invalid and erroneous data is input the program should reject: values outside the range, or the wrong type entirely, such as letters where a number is expected.

For each test you write down the input, what you expect to happen, and what actually happens; a mismatch is a bug to fix, after which you refine the algorithm and re-test. Choosing the categories thoughtfully means a handful of tests can give real confidence, whereas a hundred 'normal' inputs may never touch the edge case that brings the program down — as with Ariane 5, whose fatal value was one its tests never fed it.

Worked example

A field must accept a whole number from 1 to 120 (the age validation from earlier). A strong test plan chooses just a few targeted values:

Normal: input 45 — expected: accepted. Boundary (lower valid): input 1 — expected: accepted. Boundary (upper valid): input 120 — expected: accepted. Boundary (just invalid): input 0 — expected: rejected. Input 121 — expected: rejected. Erroneous: input 'abc' — expected: rejected without crashing. Input left blank — expected: rejected.

The pairs 0/1 and 120/121 are doing the heavy lifting: they check that the condition uses the correct comparison and does not slip by one. If 121 were wrongly accepted, this plan would catch a >= that should have been >, whereas testing only 45 never would.

VocabularyKey terms the mark scheme pays for

Defensive design
Writing programs that anticipate misuse and unexpected input and cope gracefully, so the program stays robust instead of crashing when data or users misbehave.
Input validation
Checking that input is reasonable before acting on it — range, type, length, presence and format checks — usually inside a loop that re-prompts until the input is acceptable.
Sanitisation
Cleaning input by removing or neutralising potentially harmful characters (such as trimming spaces or stripping symbols used in database attacks) before it is used.
Authentication
Confirming a user is who they claim to be, most often with a username and password, so only authorised users reach sensitive parts of a program.
Maintainability
Designing code so it is quick and safe to change later, using comments, indentation, sensible naming conventions and subprograms.
Syntax error
A break in the rules of the language, such as a missing bracket, that stops the program running or translating at all — so it is usually easy to spot.
Logic error
A fault where valid code runs but produces the wrong result because the instructions do not do what was intended. Only found by testing against known expected outputs.
Iterative vs terminal testing
Iterative testing checks each piece throughout development so bugs are caught early and cheaply; terminal (final) testing checks the finished program against the whole specification.
Boundary data
Test values sitting right on the edge of what is allowed, on both sides, chosen because off-by-one errors hide at edges. The most productive category for finding bugs.
Erroneous data
Invalid input the program should reject — values out of range or of the wrong type, such as letters where a number is expected — used to test that rejection works without crashing.

TrapsMisconceptions that cost marks

“If a program runs without crashing, it has no errors.”
Actually: That only rules out syntax errors. A logic error runs perfectly and still gives the wrong answer — like dividing by 2 instead of 3. The only way to catch it is to test with input whose correct output you already know.
“Validation proves the data is correct.”
Actually: Validation only checks that data is reasonable and in the right form, not that it is true. A birth year of 1990 passes every range and type check yet may still be the wrong year for that person. Valid is not the same as accurate.
“Testing is a single job you do at the end.”
Actually: Iterative testing runs throughout development so bugs are caught while they are cheap to fix; terminal testing at the end checks the whole system. Leaving all testing to the end makes errors far harder and more expensive to locate.
“More test data always means better testing.”
Actually: A hundred typical inputs can miss the one edge case that breaks the program. A few well-chosen normal, boundary and erroneous values test every path and catch far more — boundaries especially, where off-by-one errors live.

ExamWhat examiners want

The 2.3 material is a favourite for the higher-tariff, banded questions that reward AO3 — making reasoned judgements about design and testing. For these, do not just list techniques; explain what each one prevents. 'Use validation' is a weak point; 'a range check rejecting values above 120 stops the later calculation receiving an impossible age' is a mark, because it links the technique to the misuse it defends against.

When asked to identify an error, name the type precisely — syntax or logic — and justify it: a syntax error stops the program running, a logic error lets it run but gives the wrong output. If you can, quote the fix. On testing questions, the phrase examiners look for is a completed test plan: for each test give the input, the expected result and the reason for choosing it, and make sure your chosen values span normal, boundary and erroneous categories rather than three near-identical 'normal' inputs. Boundary values, quoted in pairs either side of the limit (0 and 1, 120 and 121), are the ones that earn credit.

For maintainability, tie each technique to the future programmer: comments explain intent, indentation reveals structure, meaningful names remove guesswork, and subprograms mean a bug is fixed in one place. And where a question offers a real-world framing, an honest answer admits that no design is perfectly robust — you reduce risk by anticipating and testing, exactly the discipline whose absence destroyed Ariane 5.

Retrieve

Test yourself

Question 1 of 6

Vofti has 14 questions on OCR-GCSE-CS-ROBUST — every one hook-first, every one mapped to this section of the OCR spec.

Last updated · 2026.08.09 OCR GCSE Computer Science · Spec OCR-GCSE-CS-ROBUST