⚡️ Maven Live · 2 June 2026 · 7pm London · 30 min

Your system design answer is right.
So why aren't they convinced?

At staff level you're not graded on the diagram. You're graded on the reasoning that survives scrutiny. Tonight: the loop that makes a correct answer read as a senior one, run end-to-end on a real system.

Ehsan Gazar
Staff / Principal Engineer · gazar.dev
The moment

"Technically correct.
Still didn't land."

An interview answer that works. An RFC that's sound. Both stall, because being right is invisible until you make the reasoning legible. The boxes were never the bottleneck.

Correct design
the architecture holds up
necessary
?
No reasoning exposed
nothing to grade or trust
the gap
Weak signal
"sound, but not staff yet"
the outcome
The gap

Correctness is table stakes.
Conviction is the differentiator.

Two engineers draw the identical architecture. One is rated staff, the other "needs seasoning." Same boxes. What surrounded them, the constraints, the quantified tradeoff, the failure story, the evolution path, was not the same.

Same diagram
boxes & arrows are equal
→ different level ←
Different reasoning
numbers · tradeoff · failure · evolution
What convincing looks like

Five signals reviewers actually score.

1
Frame + non-goals
Numbers first. Say what you're explicitly not solving.
2
Assumptions explicit
State them so they can be attacked.
3
Tradeoff, then commit
A matrix, a choice, a "because."
4
Quantify
Capacity + a latency budget, not vibes.
5
Failure + evolution
Blast radius now, the path at 10×.
The framework

One loop: Frame → Estimate → Design → Defend → Evolve.

The spine you narrate out loud so a reviewer can follow, and grade, your thinking in real time.

beat 1
Frame
requirements, non-goals, assumptions
beat 2 + 3
Estimate · Design
capacity math → components
beat 4
Defend
tradeoff matrix + failure
beat 5
Evolve
scale regimes, on purpose
Worked example

"Design a rate limiter."

The "right but unconvincing" answer:
"I'd use Redis. INCR a key per user with a TTL. Over the limit, reject."

↑ correct. and a 4/10. watch the same idea become staff-level.

Beat 1–2 · frame + estimate

Put numbers on it before you draw.

Given50k rps peak · 2M users · cap 100 req/min/user · p99 budget < 5 ms
Non-goalglobal exactness across regions — approximate is fine, say so up front
State2M × ~30 B/bucket ≈ 60 MB  →  fits one Redis node's RAM, trivially
Ops50k rps × 1 atomic op = 50k ops/s  →  under one primary (~100k+ ops/s)
Hop+1 round trip intra-AZ ≈ 0.2 ms  →  inside the 5 ms budget
Verdictcentralized Redis works to ~100k rps; the ceilings are primary ops/s and the per-call hop
Beat 3 · design

Token bucket, refilled lazily, mutated atomically.

Why Lua: check-refill-decrement must be one round trip, or two concurrent requests both read N and both pass. Atomicity on the node closes the race, and refill uses the node's clock, so no client skew.

-- KEYS[1]=tokens KEYS[2]=ts  ARGV: now, capacity, refill_per_ms
local tokens = tonumber(redis.call('GET', KEYS[1]) or ARGV[2])
local last   = tonumber(redis.call('GET', KEYS[2]) or ARGV[1])
tokens = math.min(ARGV[2], tokens + (ARGV[1] - last) * ARGV[3])  -- lazy refill
if tokens < 1 then return 0 end                              -- reject, no write
redis.call('SET', KEYS[1], tokens - 1)
redis.call('SET', KEYS[2], ARGV[1])
return 1                                              -- allow
Beat 4 · the tradeoff, made explicit

Token bucket, and here's what it beat.

AlgorithmAccuracyMemory / keyBoundary burstCost
Fixed windowlowO(1)up to 2×trivial
Sliding window logexactO(req)noneheavy
Sliding window countergoodO(1)minormoderate
Token bucketgoodO(1)smooth, tunableatomic refill
Beat 4 · failure is the high-signal part

What breaks, and who it takes with it.

Redis is a SPOF

Replica + Sentinel for failover. The limiter must never be the reason the API is down.

Partition → fail open

Fall back to a local in-process bucket. Bounded over-admission beats a global outage on a soft control. Per-route flag.

Blast radius contained

5 ms timeout + circuit breaker on the Redis call. Limiter degrades; requests still flow.

Hot tenant + clock

One abusive key won't shard; pre-check locally and approximate at the extreme. Refill clock is the node's, not callers'.

Beat 5 · the path you don't build yet

Same design, three scale regimes.

≤ 100k rps
Centralized
one Redis primary + replica
~ 500k rps
Sharded
by user hash across a cluster
global
Cell-local
sidecar buckets, sync to a global budget; per-region budgets, reconcile async

Each hop trades a little exactness for locality, deliberately. That sentence is the difference between "I'd scale it" and showing you know what scaling costs.

The traps

Five tells that cap you at senior.

1
Tech before numbers
Naming Kafka before the load.
2
No capacity math
"It scales" with nothing behind it.
3
Lists, never commits
Options with no decision or "because."
4
No blast radius
Happy path only. What takes down what?
5
No non-goals / evolution
Can't say what you're deferring.
The payoff

Conviction is how staff scope gets granted.

1
Interviews
Same design, a level up, because the loop is the rubric.
offers
2
Design reviews
Your option ships; people adopt what you defended.
influence
3
Org leverage
Others start writing the loop too. That's the multiplier.
scope
this is the senior → staff signal ↑
Cohort 1 · Sep 2026 · waitlist open

Senior to Staff Engineer.

Six weeks of live design under stakeholder pushback, with direct feedback on how you defend, not just what you draw. Small cohort, so the feedback is personal.

Join the waitlist
link is in the chat ↑
Take-home: the loop
Frame · Estimate · Design · Defend · Evolve. Run it on your next RFC.
also in the chat
1 / 14