Ten working days ago someone handed me a training plan with two graded assessments on it, an EM named Harvey waiting at the end of it, and the words "live defense" doing a lot of quiet menacing in the back of my head. I did not feel ready. This is the record of the two weeks in between, and of the fact that I apparently was more ready than I thought — a claim I will justify with receipts, because "trust me" is not how this blog works.
The setup, or: how to be told "you're good at this, now stop doing it"
Here's a fun way to start a training plan: get told you're already Strong on relational schema, indexing, and transactions — the thing you'd normally lean on — and then get handed a hard rule that the booking domain, the one place all that strength would show off, has to stay almost insultingly thin. Three endpoints. One constraint. No auth, no UI, domain code capped under 300 lines. Anything domain-shaped that started eating more than fifteen minutes got a TODO slapped on it and left to die.
It felt, for about a day, like being benched. It wasn't. Domain work scores zero on this assessment; the instrumentation wrapped around the domain is the entire test. The thin domain wasn't a consolation prize, it was the point — I just hadn't clocked that yet.
Everything lived in one NestJS monorepo that never got thrown away and restarted, which turned out to matter more than I expected. Day 2's logging service is Day 6's tracing target is Day 8's silent-failure crime scene. A few calls I made early followed me around for the rest of the two weeks like they were taking notes:
- Winston over pino — the plan named Winston, and I could have just shipped it and moved on. Instead I made myself sit with why not pino (faster, and
nestjs-pino's request-context integration is tighter) because "the plan said so" is the kind of answer that gets you eaten alive in a follow-up question. AsyncLocalStoragefor correlation IDs, not a request-scoped provider. This one I'm still a little proud of — decided on Day 2, for a reason that wouldn't matter until Day 8, when a cron job needed a correlation ID and had no HTTP request to hang it off. ALS didn't care.Scope.REQUESTwould have cared a lot.trace_idandspan_idin every log line, once OpenTelemetry showed up on Day 6. Maybe ten lines of Winston formatter, and it turned out to be the single highest-signal thing in the whole final walkthrough — I watched the id in a log line match the actual Jaeger trace and felt disproportionately pleased with myself.- Route templates instead of raw URLs as metric labels, because nobody wants ~131,500 metric series when 135 will do.
- Error ratio derived in PromQL, not tracked with a second counter that could quietly drift out of sync with the first one and lie to me forever.
None of these were boilerplate. Boilerplate I was handed freely — Dockerfiles, Grafana JSON, seed scripts, zero learning value, why would I fight for the right to type that myself. These were the ones I had to actually argue for.
The rule that made everything slower, on purpose
The one rule that shaped the whole two weeks: no code until I said my approach out loud first. I'd propose something, get hit with a specific way it would break — never a vague "hmm, are you sure" — and have to actually reason my way out of it before anyone typed a line. If I asked "how should I handle X," the question came right back at me. Nobody was going to answer a design question for me and then expect me to defend it live, alone, in front of Harvey, nine days later.
It was slower. It was occasionally annoying in the way that being right eventually is annoying. And it's the only reason Day 9 — live, no safety net, no agent in the room — went the way it did.
The bugs that actually taught me something
Day 4 stood up Prometheus, Grafana, and Jaeger, and that stack just kept getting reused straight through Week 2 without complaint. Day 6 is where it got interesting: distributed tracing surfaced an Express 5 double-instrumentation bug, and I found it by reading span tags, not by guessing and hoping. That felt like the first genuinely competent thing I did.
Day 8 topped it. I found a silent-failure hole on my own: the booking service claims a desk, marks the queue entry fulfilled, and then dies before it ever publishes the event. The desk sits reserved — looks fine, nothing alerts. The entry says fulfilled — also looks fine, also nothing alerts. Two systems both reporting "all good" while a real person is standing at a desk that was never actually theirs and nobody is ever going to tell them. Finding that a day before I needed it for the design defense did more for my confidence than every dashboard I built combined.
Multi-tenancy was the one that made me sweat. Two sessions, something like eighty minutes, going in circles — until I landed on shared tables with an operator_id column and row-level security, having actually killed the other two models on operational cost rather than vibes. Nobody handed me RLS. I said it out loud before anyone else did.
The live part, which was in fact live
Day 9: a skeptical stakeholder leaning on the waitlist's cost, then re-presenting the whole design from scratch and defending it under follow-up questions I couldn't prep for because I didn't know what they'd be. Day 10: the observability retest and a recorded walkthrough. Both landed against targets set on day one — 7/10 on observability, 8/12 on system design — back when I would have bet against myself on both. Whether I actually hit them is still sitting in Harvey's inbox, which is its own special flavor of anticlimax: you build for ten days toward a number and then you wait.
The thing I want to say to Day 1 me
Somewhere in the middle of this I said out loud that the material felt "way above my current knowledge" and wondered if that was just impostor syndrome talking. Turns out: half right, half wrong, and worth being precise about which half. System design at this scale genuinely is a stretch for where I was — one design drill under my belt at that point, that gap was real and I don't need to be brave about it. But the observability track was never a story about being behind. I root-caused a real bug from trace spans. I killed four hypotheses with actual measurement instead of guessing and hoping nobody asked. I caught three of my own mistakes before they made it into a recording other people would watch.
The weak-spot list only ever records the misses — that's its whole job, and it's a good one, but it is not a self-portrait. Read literally, it makes two weeks of actual progress look like a list of things still wrong with me. It isn't. The finished plan is a much better mirror than the running list of dings ever was, and I'm choosing to believe that on purpose.