Revise the key ideas
Defensive design
- Anticipate misuse — A robust program handles invalid data and predictable user mistakes without producing misleading results or failing unnecessarily. Identify required formats and constraints before writing code. Defensive design includes authentication, validation and maintainable structure, not simply testing after everything is finished.
- Authentication — Authentication may compare credentials with an authorised account and require another factor. It answers who the user is; authorisation decides which actions are permitted. A successful login should not automatically allow changing every record.
- Validation — Validation checks acceptability, such as an age being an integer in a permitted range. It cannot prove that the entered age is factually true. Use rules tied to requirements; rejecting all input is not useful robustness.
- Range length and presence — A range check can require 0 <= mark <= 100. A length check can require a code of six characters. A presence check rejects an empty required field. One check cannot establish every property: a six-character value may still contain forbidden characters.
- Type and format — A type check ensures a numeric entry can be treated as the required number type; a format check examines a pattern such as required letters and digits. Converting invalid text may fail, so handle that before calculation. State the permitted format instead of assuming all similar-looking entries are valid.
- Validation loops — Request input, check it and repeat when invalid. Give a useful explanation and a way to correct the entry. Validate before indexing an array or dividing; otherwise a bad value may cause failure before the check can protect the operation.
Python validated integer input def read_mark(): while True: text = input("Integer mark 0 to 100: ") try: mark = int(text) except ValueError: print("Enter a whole number.") continue if 0 <= mark <= 100: return mark print("The mark must be from 0 to 100.") mark = read_mark() print("Accepted:", mark)Try 42, 0, 100, -1, 101 and banana in separate runs. Invalid entries reprompt, while an accepted integer returns. Validation does not prove the real mark is true.
- Maintainable code — Meaningful identifiers explain data roles; consistent indentation reveals structure; useful comments explain purpose or non-obvious decisions. Subprograms isolate tasks. A comment does not correct a defect, and misleading comments can make a program harder to maintain.
Testing and refinement
- Purpose of testing — A test provides input or actions and an expected result, then compares actual behaviour. Testing can reveal defects but cannot prove every possible case correct. Use a plan derived from requirements rather than selecting only inputs that the author already knows will work.
- Iterative and final testing — Iterative testing checks and corrects work as it develops, helping isolate defects early. Final testing checks the complete program against requirements, including interactions between modules. A module passing in isolation does not ensure every combined workflow is correct.
- Normal data — For an integer mark permitted from 0 to 100, 42 is normal valid data. Record the expected acceptance and resulting calculation, not simply 'works'. Use representative cases across branches rather than many examples taking the same path.
- Boundary data — For the inclusive range 0 to 100, test 0 and 100 and values immediately outside, such as -1 and 101. Boundaries expose mistaken < versus <= conditions. Label whether each value should be accepted; the word boundary alone does not determine that.
Use the labels alongside the associated explanation. - Invalid and erroneous data — An out-of-range number and text where an integer is needed are different invalid cases. OCR distinguishes invalid values of the correct type from erroneous values of an inappropriate type. Explain the data and expected rejection clearly rather than relying only on the label.
- Syntax errors — A missing required colon in Python or an unmatched bracket can prevent code being parsed. Correct the syntax according to the chosen language, then retest. Successfully parsing a program says nothing about whether its algorithm produces the right answer.
- Logic errors — Using price + quantity instead of price × quantity can run successfully but calculate the wrong total. A wrong comparison or loop bound can omit an item. Trace values and compare with an independently calculated result to locate the defect.
- Runtime errors — Dividing by zero, accessing an out-of-range index or opening a missing file can fail while the program runs. Handle expected problem cases and validate inputs. This is different from a syntax defect that prevents execution beginning.
- Test plans — For each test state its purpose, data, expected behaviour and actual result. If they differ, explain the fix and repeat the test; also check related working cases to avoid a regression. Expected outcomes must come from the requirements, not simply copy the observed output.
- Refining an algorithm — If a total loop skips the final array item, correct its bound and test one-item and multi-item lists. If an input loop never updates its variable, add the missing input in the right place. Test termination as well as the final numeric output.
- Practical task — Implement a fictional booking or score-processing task with specified constraints. Plan normal, boundary and invalid inputs, record results and justify corrections. The course requires opportunities for practical programming; an online short-answer bank does not replace actually writing and testing code.