Defense in Depth: Prevent, Test, Detect, Recover

Reminders
- DUE TONIGHT: Onboarding: Gradebook Column Groups, Thu Sep 24, 23:59
- DUE TONIGHT: Reading Bid, Thu Sep 24, 23:59
- TEAMS: preliminary teams are on Discord; final teams Mon Sep 28
CS 4535: Software Design & Delivery
Defense in Depth: Prevent, Test, Detect, Recover
©2026 Jonathan Bell, CC-BY-SA
Learning Objectives
After this session, you'll be able to:
- For a possible failure, decide whether it can be prevented and which layers belong on top (test, detect, recover), or accept it, and defend the choice by blast radius rather than by likelihood
- Read a
gradebook-e2erun and say what it proves and what it doesn't - Explain what visual acceptance testing catches that an assertion cannot
Which Defense Would You Add?
January 31, 2017, late at night. A GitLab engineer is fixing a database replica that has fallen behind. The plan: wipe the replica's data and copy it fresh from the primary. They run the delete command in the wrong terminal. By the time they stop it, 300 GB of production data is gone.
GitLab has five backup and replication systems.
Which one missing defense would have made tonight boring?
A. A guard that blocks deletes on the primary
B. More backup copies
C. An alert when a backup fails
D. A regular drill that restores from a backup
Five Backups. None Worked.
Nightly dumps used the wrong Postgres version. The bucket was empty.
The emails reporting that failure were being silently rejected. Nobody saw them.
Cloud disk snapshots had never been turned on for the database.
Replication was already broken. That was what the engineer was fixing.
What saved them: a snapshot someone had taken by hand, six hours earlier, to refresh staging. Six hours of data lost; eighteen hours to copy it back.
B was never the answer. They had five. A defense you haven't tested is a defense you don't have.
It Could Break. Now What?
You've spotted a way your column-groups feature could fail, and it's bad.
What are your options? Not just "write a test."
Prevent First. Then Layers.
Prevent. Can you design it out? A constraint, a type, a foreign key that refuses the bad state. Then ask whether the guard holds, because nothing is impossible until you've checked.
Test. It fails before it ships, and that includes the guard.
Detect. You find out in production, before a user tells you.
Recover. You can undo it. Backups, restore, a flag you can turn off.
Accept. None of the above, on purpose, with the reason written down.
These stack. Blast radius decides how deep the stack goes. Likelihood is the question you reach for first and the least useful.
How Deep Does Each One Go?
| What breaks | Blast radius | How would you find out? | Prevent? | Then | |
|---|---|---|---|---|---|
| A | The backfill puts a column in the wrong group in one course, and it looks plausible | ||||
| B | The gradebook is fine on the seed, and crawls for our biggest course (500 students, 400 columns) | ||||
| C | Two instructors rename the same group within the same second. One rename silently wins | ||||
| D | Deleting a group deletes its columns, and every student's scores in them | ||||
| E | Instructors open the new group editor, get confused, and give up. Nothing errors |
10 minutes, in pairs. You built this feature. For each row: can you prevent it, and if so, how? Then tick every layer it deserves: Test, Detect, Recover, or Accept.
One sheet per pair, in pen. We collect them. Worksheet and details: neu-se.github.io/CS4535-Fall-2026/docs/testing-cost-worksheet
Five Failures, Five Stacks
| Blast radius | How you'd find out | Prevent? | Then | |
|---|---|---|---|---|
| A | Wrong grouping, and nobody can tell | An instructor, weeks later | No. A constraint can't know the right group | Test · Recover |
| B | Our biggest customer can't use the gradebook | From them, loudly, in week 3 | No | Test · Detect |
| C | One group has the wrong name. No scores touched | Whoever looks at the header | Not worth it | Accept |
| D | A semester of grades, gone | Instantly, and too late | Yes. ON DELETE RESTRICT | Test the guard · Detect · Recover |
| E | The feature exists and nobody uses it | Only from watching usage | No | Detect · Recover |
C and D are both rare. C gets one sentence in the PR. D gets every layer there is. Likelihood didn't decide that; blast radius did.
What Ran On Your Pull Request
Every push to your column-groups branch triggered gradebook-e2e. It:
Stands up a throwaway Supabase, then replays every migration, including yours, in order.
Seeds the cs4535 class: students, assignments, a gradebook with real numbers in it.
Builds the app for production and serves it on :3001.
Drives the instructor gradebook in a real browser, on chromium and webkit, and uploads screenshots.
That is a robot doing the staging pass, before staging, on every push, for free.
Your PR Is Green. So What?
From the column-groups handout:
Green means it applies, the types match, and the table still groups something.
90 seconds, with the person next to you. Your column-groups PR is green.
Name a way your feature could still be broken.
Green is a claim with a scope. You are responsible for knowing the scope.
What An Assertion Can't See
Every one of these passes every assertion you would think to write:
The column group header renders, and sits on top of the first row.
The text is present, in gray on a slightly lighter gray.
The table is there, and four columns wider than the viewport.
Everything renders, and the collapse chevron now points the wrong way.
A DOM assertion asks whether it's there. It cannot ask whether it looks right.
Test What Breaks Quietly
Worth a test: wrong numbers, half-applied migrations, permissions that leak, anything where the failure is invisible until it is expensive.
Usually not: restating a label, asserting on the mock, or anything that fails only when you change it on purpose.
And a test you will not maintain is worse than no test, because it teaches the team to ignore red.
A loud failure needs no test. It already tells you.
Up Next
Mon Sep 28, Studio Kickoff: Team Charters, Backlog & Estimation
Final teams are posted Monday morning. You stop being one person with an assignment and become four people with an area, a backlog, and a suite you share.
Before then:
- Onboarding: Gradebook Column Groups, due tonight, Thu Sep 24, 23:59
- Reading Bid, due tonight, Thu Sep 24, 23:59