How Software Development ChangedLesson 16 of 87

Contents

How Software Development Changed

Lesson 16 of 87. Sign in to keep your place.

Module 2 · Reading what you did not write

Safety that quietly went missing

9 min read

The highest-yield lines in any diff are the deletions

When a change removes a check, the diff shows a red line and moves on. There is no compiler error, no failing test (the test that would have failed is often the one that was deleted) and no visual signal that anything important happened. In a 700-line review these lines are three of them, and they carry most of the risk.

This is not new. What is new is the mechanism that produces them. Asked to make something work, a generator will make it work, and the shortest path from failing to passing frequently runs straight through a safety check. Nothing in that process is malicious or even careless. The check was in the way and the objective was to remove the obstacle.

The catalogue

Learn these shapes so you see them without looking for them.

The widened net.

Python
-except ValidationError as e:
-    logger.warning("bad payload: %s", e)
-    return 400
+except Exception:
+    pass

Every bug in that block is now invisible. except Exception: pass and its equivalents (catch (e) {}, rescue nil, if err != nil { }) are the single most common way a system loses the ability to tell you what is wrong.

The loosened type.

TypeScript
-function total(items: LineItem[]): Money
+function total(items: any[]): any

Or in Python, # type: ignore; in Rust, unsafe or a fresh .unwrap(); in Java, a raw type or an @SuppressWarnings. Each of these switches off an oracle that was running on every build, for ever, for free.

The disabled rule. // eslint-disable-next-line, # noqa, #pragma warning disable, @ts-expect-error. Sometimes correct. Always deserving of a comment saying why, on the same line.

The skipped or weakened test.

Python
-@pytest.mark.parametrize("currency", CURRENCIES)
+@pytest.mark.skip(reason="flaky")

“Flaky” is doing a great deal of work in that reason string. A flaky test is a defect report about the system or the test, and skipping it is a decision to stop receiving the report.

The relaxed constraint. A NOT NULL dropped, a UNIQUE index removed, a foreign key made deferrable, a CHECK deleted in a migration. These are the most expensive of all, because a constraint removal is followed within weeks by data that violates it, and then you cannot put it back.

The raised limit. A timeout from 5s to 60s. A retry count from 3 to 10. A connection pool doubled. A memory limit raised. Each of these is a real fix in some situations and a way of hiding a problem in most, and none of them should pass review without a sentence explaining which.

The widened permission. A scope added, a role check removed, a bucket policy broadened, a CORS origin set to *, a firewall rule opened. Narrowing takes thought; widening always works.

Make the machine find them

Humans miss deletions because attention follows additions. A pipeline does not have that bias.

Bash
#!/usr/bin/env bash
# flag safety subtractions for explicit review
git diff origin/main...HEAD -U0 \
 | grep -E '^\-' \
 | grep -viE '^\-\-\-' \
 | grep -nE 'assert|raise|throw|validate|NOT NULL|UNIQUE|CHECK |require|permission|scope|@pytest|test_|if .*(None|null|nil)' \
 && echo "^ removed lines above touch validation or safety — explain each in the PR description"

This is deliberately noisy. Its job is not to block; its job is to make a human write a sentence. A rule that produces a short list a person reads is worth more than a precise rule nobody configured.

On the additions side, a matching grep for except Exception, : any, type: ignore, eslint-disable, unwrap(), skip( and sleep( catches the other half.

The norm that makes it work

One line in the contributing guide, and it is worth arguing for:

Any change that removes a validation, widens an exception handler, loosens a type, skips a test, drops a database constraint, or broadens a permission must say why in the pull request description.

Not forbidden. Explained. All of these are sometimes right: the constraint was wrong, the test was measuring the clock, the type is dynamic at that boundary. What is never right is doing it silently, because the silence is what makes it undiscoverable six months later when somebody asks how the null got into the column.

And when the explanation is missing, the question to ask is not “why did you remove this” but the more useful one: what was this protecting against, and what protects against it now?

Every lesson here is open. Your progress is recorded once you pass the AI at Work exam.

Check your understanding

A change makes a failing integration test pass by widening a try/except ValidationError to except Exception. All tests are now green. Why is this worse than the original failure?

Pick the one you would defend. Your answer stays private.

Next lesson · 9 minReviewing a dependency change

Stuck on something?Ask Larissa, your AI tutor

How to cite: Addaly (2026) ‘Safety that quietly went missing’, in How Software Development Changed. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/how-software-changed/safety-that-went-missing (Accessed: 13 October 2026).