Tutorials taught me how to make things work.
They never taught me how to notice when nothing happens — or when something quietly goes wrong.
Tutorials taught me to make things work
The happy path is the product
A tutorial is a guided tour through a world where outcomes are known in advance. Inputs are curated. Versions match. The API behaves. The dataset is clean. When you follow the steps, the screen changes in the expected way.
That’s not a flaw. That’s the point.
Copy/paste confidence
I used to confuse “I can reproduce the result” with “I understand the system.” Copy/paste gives you momentum. It also hides the most important part of engineering: making choices under uncertainty.
- Predictable inputs, predictable outputs.
- No consequences, no uncertainty.
They never taught me to notice weak signals
When nothing happens
Real systems fail quietly. A job runs but writes to the wrong place. A queue backs up slowly. A feature flag is on in staging but off in prod. The worst problems don’t announce themselves.
In distributed systems, this is practically the default: you don’t “see” the system. You infer it from symptoms, dashboards, logs, and user complaints that arrive late and incomplete. The craft is learning what to watch—especially when the signal is weak. Google’s SRE guidance on monitoring is blunt about this: monitoring isn’t about graphs, it’s about detecting and diagnosing failure modes early enough to act.
When it “works” but is wrong
My most educational bugs weren’t crashes. They were “green checks” that shipped bad assumptions.
- Silent failures and partial success that look like progress.
- Wrong assumptions hiding inside defaults.
If a tutorial teaches you anything about errors, it’s usually the loud kind: a missing import, a syntax issue, a 404. The real work lives in the quiet: it ran, but did it do the right thing?
The real work is debugging your own thinking
Hypotheses over hunches
When I’m stuck, I’m usually not stuck on the code. I’m stuck on a story I’m telling myself about the code.
The fix starts when I turn the story into a testable claim: “I think the request is reaching the server,” or “I think the model is reading the newest file,” or “I think this timestamp is in UTC.” Now I can prove or disprove it.
Evidence you can trust
Two habits changed everything for me:
- Change one variable at a time. If you change three things and it works, you learned nothing.
- Write down what you expect before you run it. If you can’t predict the result, you’re not debugging—you’re gambling.
Engineering skill grows in small experiments
Make the scope tiny
Big builds create big ambiguity. When the outcome is unclear, you need experiments that narrow the uncertainty fast.
I aim for tests that take minutes, not days. A tiny probe that answers one question beats a half-built castle that answers none.
Measure something real
“Real” can be embarrassingly small: one log line, one counter, one file written, one request observed.
- Build probes, not castles.
- Prefer reversible decisions.
This maps cleanly onto established experimental discipline: small, controlled changes and clear response variables. Even outside labs, the logic holds—reduce confounders, learn quickly, iterate. The NIST/SEMATECH overview of designed experiments captures the spirit: structure your tests so you can attribute effects to causes.
Build imperfect tools that touch reality
Real users (even if it’s you)
The fastest way to outgrow tutorials is to build a tool you actually rely on. Not a demo. Not a clone. Something that has to keep working tomorrow.
Even if you’re the only user, your future self is ruthless: they don’t care about your architecture diagram. They care whether it breaks at 11:40 PM when you need it.
Real constraints
Reality shows up as friction:
- Time pressure and messy inputs.
- Deployment weirdness.
- Edge cases that force understanding instead of imitation.
This is where “cargo cult” learning collapses—the imitation without comprehension that Richard Feynman warned about. When your tool meets the world, you can’t bluff. The system either behaves or it doesn’t.
A simple practice: the ‘signal checklist’
When you feel yourself sliding into tutorial mode—searching for the exact steps—pause and run this instead.
Before you run
- What outcome do I expect? Write it in one sentence.
- What would failure look like? Name at least two failure modes.
- What did I assume “for free”? Versions, permissions, timezones, network access, defaults.
After you run
- What changed? A file, a row count, a metric, a response code—something observable.
- What stayed invariant? Identify one thing that should not have changed.
- What evidence would convince a skeptic? Logs, traces, checksums, counts.
When you’re stuck
- What is the smallest test that could disprove my theory?
- Can I reduce the system? Run the component alone, stub the dependency, replay a single input.
- What signal am I missing? Add one log line, one metric, one assertion—then rerun.
Information is abundant; judgment is scarce
Stop consuming, start iterating
I still use tutorials. I just stopped expecting them to produce judgment.
Judgment comes from a loop: predict, test, observe, explain. And the loop only gets sharp when the outcome is unclear and the stakes are real—even if “real” just means you’ll lose an hour tomorrow if you don’t fix it today.
The goal: reliable intuition
- One imperfect tool shipped beats ten tutorials watched.
- Keep a tiny lab notebook: date, hypothesis, test, result, next step.
Over time, you stop needing the perfect instructions. You start trusting your own ability to detect weak signals, separate coincidence from cause, and move from “it runs” to “it’s correct.”