Chapter 9 — Programming II
Lesson map
Lesson 09 published. Map, example, EX025.
flowchart TD
N0["Learning outcomes"]
N1["9.1 Modules and interfaces"]
N2["9.2 Negative tests"]
N3["9.3 Dependencies"]
N4["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4
N4 --> EX["Worked example"]
EX --> Q["Exercise EX025"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["9.1 Modules and interfaces"]
N2["9.2 Negative tests"]
N3["9.3 Dependencies"]
N4["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> Q["EX025"]
[Learning outcomes]
|
v
[9.1 Modules and interfaces]
|
v
[9.2 Negative tests]
|
v
[9.3 Dependencies]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX025]
Learning outcomes
You will (1) structure programs into modules with clear interfaces; (2) write tests including negative tests for security behaviour; (3) manage dependencies safely.
9.1 Modules and interfaces
In Programming II Sofia builds a small fare-rules engine as several modules: parsing, tariff lookup, discount rules and output. Each module exposes a narrow interface and hides its internals. Daniel explains why this matters for security: narrow interfaces are easier to review, and a module that receives only validated data from the parser need not repeat every check. This is economy of mechanism at the code level. When the discount module later needs a change, Sofia can review only its interface and tests rather than the whole program, which reduces the chance of introducing a flaw elsewhere.
9.2 Negative tests
Sofia writes unit tests for normal fares, then Daniel asks for negative tests: inputs that must be rejected. A child discount must not apply to an adult card; a tariff zone outside the network must raise an error; an amount with more than two decimal places must be refused. Security bugs often live in what a program wrongly accepts, so tests should show that bad inputs fail. She runs the tests automatically on every change. Negative tests also document intent: a later developer can see that rejecting those inputs was deliberate and not an accident to be removed.
9.3 Dependencies
Sofia's program uses a third-party package to read configuration files. Daniel shows her how to pin its version, record where it came from and check for published advisories. NIST SP 800-218, the Secure Software Development Framework, recommends practices such as tracking components and responding to vulnerabilities in them. A dependency is code someone else wrote that runs with your program's privileges. Sofia learns to prefer the standard library where it suffices, choose well-maintained packages otherwise and review how much code each new dependency brings, since every line is part of the system's attack surface.
Worked example
Sofia modularises a fare-rules engine, adds three negative tests that must fail safely and pins and records one dependency per SP 800-218 practices.
Synthetic case. The engine and package are synthetic; SP 800-218 is real.
Errors and limits
Tests show presence of checks, not absence of all bugs. Pinned dependencies still need updates when advisories appear.
Exercises
- EX025 — Narrow interface benefit. How do narrow module interfaces help security review? Rubric: 3 = less to review and validated data need not be rechecked everywhere;; 2 = review;; 1 = vague;; 0 = none.
- EX026 — Negative test example. Give one negative test from Sofia's engine. Rubric: 3 = child discount on adult card rejected, out-of-network zone error or three-decimal amount refused;; 2 = one;; 1 = positive test;; 0 = none.
- EX027 — Dependency practice. What does SP 800-218 recommend about third-party components? Rubric: 3 = track them and respond to vulnerabilities in them;; 2 = track;; 1 = ignore;; 0 = none.
Synthesis
Modular design, negative tests and managed dependencies make programs easier to trust and to keep trustworthy.
Continue studying — chapter 09 of 50
← Chapter 08 (draft) · Course chapter index · Chapter 10 (draft) →