Backend Interview Preparation With 3 Years of Experience
Three years is the band where a design round stops being a formality and starts carrying weight. You will be asked to design something small, and the interviewer will push on one part of it until you either justify the choice concretely or change it. Neither outcome is a failure; being unable to do either is.
The other shift is that interviewers stop asking about failure and start expecting you to raise it. A candidate who designs a service and never mentions what happens when the downstream call times out has not demonstrated three years of experience, regardless of what the résumé says. Operating a system teaches you that failure is the normal case, and the interview checks whether you learned it.
Written and reviewed by Sahil Srivastav
What the bar actually is
The bar is end-to-end ownership of a feature including its failure modes and its operational life. You should be able to take a loosely specified requirement, ask the two or three questions that actually change the design, build it, and say what you would monitor once it shipped.
Interviewers also expect calibrated confidence. Knowing that you do not know how something behaves, and being able to say what you would measure to find out, reads as more senior than a fluent guess. At this band a confident wrong answer about isolation levels or delivery guarantees does more damage than an admission of uncertainty.
How the rounds are structured
Machine coding with an explicit extension
The interviewer announces that a variant is coming — a second payment method, a new coupon type — and watches whether your structure absorbs it. Working code is still the entry ticket.
A design round with one point of pressure
Small scope, deep probing. Expect sustained questioning on a single component rather than breadth across a whole architecture.
Debugging from evidence
A symptom plus some logs or metrics. Can you form a narrow hypothesis and name the next measurement, rather than listing everything that could theoretically be wrong?
Deep-dive on your own work, with operational questions
Not just what you built but how it ran: what alerted, what broke in production, what you changed afterwards.
What this interview bar tests
Raising failure unprompted
Timeouts, retries, duplicate delivery, partial writes, a deploy landing mid-transaction. Naming these before being asked is the clearest SDE2 signal available.
Isolation and locking at a working level
What a lost update is and what actually prevents it. Candidates at this band are frequently asked and frequently approximate; precision here stands out.
Reasoning from evidence
Given a slow endpoint, distinguishing "doing too much work" from "waiting on a lock" before touching anything. The habit separates operators from builders.
Monitoring as part of the design
What the first alert would be and what metric would have caught the bug earlier. A design with no observability story is read as incomplete.
A preparation plan that works
- 1Design three small systems out loud and have someone attack one component of each until you concede or justify. The skill being trained is staying analytical when pushed, which is most of what the design round measures.
- 2Nail down the concurrency vocabulary properly — lost update, write skew, what REPEATABLE READ does and does not prevent in the database you actually use. Precision here is cheap to acquire and disproportionately persuasive.
- 3Work two debugging problems where the evidence is given and the cause is not obvious. Practise narrating the narrowing rather than jumping to a fix.
- 4For every system on your résumé, prepare the operational half: what you monitored, what paged you, what the worst incident was.
Questions you should expect
Design a service that charges a card and records the charge. What goes wrong?
The dual-write problem: the charge succeeds and the database write fails, or the reverse, and there is no transaction spanning both. Name the outbox — persist the intent atomically, let a worker perform the charge, make the operation idempotent on a key so a retry cannot double-charge — and then name the consequence, which is at-least-once semantics the consumer must tolerate.
Two requests update the same row concurrently. What does your code do?
Say which strategy you chose and why. Optimistic: a version predicate in the UPDATE and a check of the affected-row count, retry on zero. Pessimistic: SELECT FOR UPDATE, with a consistent lock order if more than one row is involved. Best of all, if the operation allows it: a single atomic conditional update so there is nothing to lock and nothing to retry.
An endpoint is timing out. Walk me through your first five minutes.
Establish whether it is slow or blocked before changing anything — a statement waiting on a lock consumes no resources and looks nothing like one doing excessive work, and only one of those is fixed by indexing. Then check whether cost scales with some users' data volume, which points at an unbounded query rather than a plan regression.
What would you monitor for this feature?
Leading indicators rather than aftermath. Queue depth before rejections, connection-pool pending count before pool timeouts, post-GC old-gen occupancy before an OutOfMemoryError. Naming the metric that gives warning rather than the one that records the outage is the senior answer.
What gets candidates rejected
- Designing without ever mentioning what happens when a dependency fails
- Approximating isolation-level behaviour instead of knowing it for your own database
- Jumping to a fix in the debugging round without establishing slow versus blocked
- Claiming a broker provides exactly-once delivery
- Having no operational story for systems you say you owned
- Folding immediately when pushed on a design decision that was actually defensible
- Treating the announced extension in the coding round as scope creep rather than the test
What to practise, in order
Transactional outbox implementation
The dual-write question made executable: atomic enqueue, at-least-once publish, idempotent consumption, crash recovery mid-publish.
Lock ordering deadlock in a transfer path
Mirrored concurrent transfers that deadlock. Tests assert progress and ledger consistency, so a retry wrapper does not pass.
Database overload under a traffic spike
A missing index, an N+1 loop and an unbounded fetch compounding. Tests assert statements executed and rows visited per request.
Webhook event idempotency and ordering
Duplicate and out-of-order deliveries, with assertions on final state. The practical version of at-least-once delivery.
FAQ
Am I expected to design large-scale systems at three years?
No. Expect a small, concrete design with deep probing on one part, not a globally distributed architecture. Depth on a narrow design beats a shallow tour of a large one, and candidates who reach for scale they were not asked about usually get caught on the fundamentals underneath.
How precise do I need to be about isolation levels?
Precise for the database you actually use. Know what a lost update is, what prevents it, and specifically that PostgreSQL's REPEATABLE READ is snapshot isolation and does not permit phantom reads, unlike the ANSI definition. That detail is asked often and answered badly.
What if I have never been on call?
Say so, and compensate with the evidence-reasoning habit instead. You can demonstrate how you would narrow a failure from a symptom without claiming operational experience you lack. Pretending to on-call experience collapses in one follow-up.
Should I target SDE2 or SDE3?
SDE2, with SDE3 a reasonable stretch at strong companies if you have genuinely owned something ambiguous end to end. The gating difference is whether you chose the problem or were handed it.