The missing level
When all unit tests pass and the assembled program crashes at a seam, the missing test is an integration test running the real pieces chained together.
Doubles hide seam disagreements, such as the renamed dictionary key from lesson 6-2. An integration test feeds one component's real output into the next, which is the only level that can catch a broken contract between two green units.
That connects to this unit in a specific way. When a bug does slip through every level of the pyramid, no test tells you where it lives, and finding it becomes a skill of its own rather than a matter of reading a failure report.
Guessing is not a method
Sooner or later a bug arrives that no test predicted. Beginners debug by vibes, changing something, running, changing something else, running, until the error goes away and nobody knows why. That wastes hours and often buries the bug rather than fixing it.
Professionals run a hypothesis loop, which is the scientific method pointed at code:
- Observe the symptom precisely. Not "it is broken" but "total is 6 when 5.0 was expected, for even-length input"
- Hypothesize one specific cause, such as "the median picks the wrong index when the list length is even"
- Predict something checkable, so "then
median([1, 2])should return 2, not 1.5" - Experiment by running exactly that check
- If confirmed, fix it and add the regression test from lesson 4-3. If refuted, return to step 2 with what you learned
One rule makes the loop honest: change one thing per experiment. Change two and you cannot tell which one mattered, so a confirmed prediction teaches you nothing.
Step 1 is the one most often skipped and the one that pays best. A vague symptom admits a hundred hypotheses, while a precise one, naming the input, the expected value, and the actual value, usually admits two or three.
What a refuted hypothesis buys you
When your hypothesis was that the discount is applied twice and the experiment shows it is applied once, the loop bought you a ruled-out cause and a fact you did not have before, narrowing where the bug can hide.
A refuted hypothesis is progress rather than failure, because the search space just shrank. The double-application theory is dead, and so is every fix built on it, which saves you from the worst outcome of vibes debugging, namely a change that alters behavior without addressing the cause.
The fact you gained is reusable too. Knowing the discount runs exactly once means the wrong amount must come from the rate, the base it applies to, or something downstream of the discount entirely, and each of those is a sharper next hypothesis than the one you started with.
This is why the loop is written to require a checkable prediction. A hypothesis that cannot be refuted, such as "something is wrong with the discount logic", produces no fact either way, so the lap costs time and returns nothing.