# Defensive Programming and Debugging

Computer Science I · Programming II · https://tryals.app/learn/computer-science-i/defensive-programming-and-debugging

## Programming for a Hostile World

Real programs face bad inputs and imperfect environments. **Defensive programming** anticipates these problems so code behaves safely instead of crashing or outputting garbage.

| Term | Definition |
| --- | --- |
| **Input validation** | Checking that inputs meet assumptions before use. |
| **Assertions** | Statements of a condition that must be true ($assert\ n \ge 0$). |
| **Failing fast** | Detecting errors close to their source to stop propagation. |

Rejecting bad input at the boundary with a clear error prevents silent state corruption deep inside the program.

## Contracts and Pitfalls

Functions require clear **preconditions** (what inputs are needed) and **postconditions** (what outputs are guaranteed). Handle **errors explicitly** via exceptions rather than ignoring them.

| Contract Aspect | Purpose |
| --- | --- |
| **Preconditions** | Document and enforce valid inputs. |
| **Postconditions** | Guarantee correct output state. |

> **Common pitfall:** Trusting that inputs will always be valid because "no one would ever pass a negative here." Unvalidated assumptions break production code. Validate at boundaries and fail fast.

## Practice questions

4 of this lesson's 11 practice questions, with answers. The full set is in the app.

### 1. A function takes a list and an index and returns the element at that index. Select every check that belongs in it as input validation.

A. That the returned element is itself a number
B. That the index is less than the number of elements
C. That the list is not empty
D. That the index is at least 0
E. That the caller will use the result

**Answer:** B. That the index is less than the number of elements; C. That the list is not empty; D. That the index is at least 0

**Why:** Emptiness and the two index bounds are all assumptions about the inputs that can be checked at the boundary. What type the stored element has is not the function's business, and what the caller does afterwards is unknowable. Validating things you cannot see is as much a design fault as validating nothing.

Page: https://tryals.app/practice/computer-science-i/defensive-programming-and-debugging/a-function-takes-a-list-and-an-index-and-returns-the-element-at-that

### 2. Assertions are usually compiled out of release builds, and input validation never is. Why treat them differently when both check conditions?

A. Because an assertion checks the code's own assumption, not outside input
B. Because assertions cannot express conditions about user input
C. Because validation is required by law in most jurisdictions
D. Because assertions are slower than validation checks

**Answer:** A. Because an assertion checks the code's own assumption, not outside input

**Why:** An assertion says 'this cannot happen' and firing means a bug; validation says 'this might happen' and firing is normal operation. Compiling out assertions is defensible because a shipped program should not contain the impossible, compiling out validation would mean trusting the outside world, which is how security holes are made.

Page: https://tryals.app/practice/computer-science-i/defensive-programming-and-debugging/assertions-are-usually-compiled-out-of-release-builds-and-input

### 3. Order the steps by which an assertion turns a distant, mysterious failure into a local, obvious one.

**Answer:**

1. State the condition you believe must hold at this point in the code
2. Write it as an assertion immediately before the code that relies on it
3. Run the program on the input that used to fail far downstream
4. The assertion fails at the exact moment the assumption is first violated
5. Fix the code that produced the offending value, not the code that tripped over it

**Why:** Assertions work by making an implicit assumption explicit and checkable, so the program halts where the assumption first breaks rather than where the corrupted value later causes visible nonsense. The last step matters most: the assertion identifies the victim, and the bug is in whatever produced the bad value.

Page: https://tryals.app/practice/computer-science-i/defensive-programming-and-debugging/order-the-steps-by-which-an-assertion-turns-a-distant-mysterious

### 4. Defensive programming favours failing loudly at the point of the error over continuing with a plausible substitute. Why is crashing sometimes better than carrying on?

A. Because loud failures are easier for users to understand than substituted values.
B. Because crashes are always preferable to any form of error handling.
C. Because continuing after an error is impossible without corrupting memory.
D. Because a fault that surfaces immediately is localised and diagnosable.

**Answer:** D. Because a fault that surfaces immediately is localised and diagnosable.

**Why:** A function handed a negative length that quietly returns 0 has moved the failure elsewhere and removed the evidence, the wrong value flows on and surfaces in innocent code. It is not a rule about production behaviour: a web server should return an error, not exit. The distinction is between expected conditions, handled deliberately, and bugs, where an assumption is false.

Page: https://tryals.app/practice/computer-science-i/defensive-programming-and-debugging/defensive-programming-favours-failing-loudly-at-the-point-of-the
