Interviewing well
The skill that converts all the others into an offer.
Interviewing well is a separate skill from the engineering being tested, and it is made of specific, practisable habits: narrating your reasoning aloud instead of going quiet, asking what the constraints are before designing anything, checking your own answer before declaring it finished, and arriving with about eight short true stories ready, covering a conflict, a failure, an ambiguous brief and something you would now do differently.
The interviewer cannot see you think; they can only hear what you say. A silent candidate who reaches a correct answer scores below a talkative one who gets most of the way, because only one of them showed how they work. Strong engineers are rejected on this far more often than on a technical gap, and the note on the rejection tends to read communication.
It sits across every other topic here, since it is the channel through which all of them are assessed, and none of it substitutes for the substance underneath. It pairs most closely with AI system design and product judgement, the rounds that are graded almost entirely on how you reason out loud.
An interviewer can only assess the thinking you make audible.
In more detailNarrating your reasoning while you work, asking clarifying questions before designing, and having eight concrete stories ready about conflict, failure and ambiguity. Being able to say what you would do differently is read as seniority, not weakness.
Communicating while you work
By the end: Interviewers can see your reasoning, which is what they are actually assessing.
- Thinking out loud
- Clarifying before solving
- Handling being stuck
- Talking about your own work
Interviewers cannot assess reasoning they cannot hear, and a silent candidate solving the problem correctly still scores badly. This section is about working out loud: stating what you think the question is before answering it, narrating the approach as you go, and saying where you are stuck instead of freezing. It also covers talking about work you have already done, which is a different skill and is tested just as often.
Silence is scored as absence#
An interviewer cannot see you thinking. Careful consideration and having no idea look identical from the outside. Strong engineers fail loops for this reason more often than for gaps in knowledge.
Instead of a pause, say what the pause is:
"I'm weighing two approaches. A hash map is O(n) time and O(n)
space. Sorting first is O(n log n) but constant space. Given the
input sizes you mentioned, I'll take the hash map."The useful reframing is that the interviewer is not scoring your answer, they are filling in a form about how you work, and they can only write down what reaches them. Every second of silence is a second in which nothing is being written. This is why a candidate who gets two thirds of the way with continuous commentary routinely scores above one who arrives at the full answer in silence: the first produced evidence and the second produced a result.
Twelve minutes, annotated#
Read this as a script and then as a clock. The times are what a good pace looks like; the lines in brackets are what the interviewer is writing on the form. It is the opening of an ordinary design round, and it deliberately contains a thing the candidate does not know.
00:00 INT We want to add semantic search over our help centre.
Maybe eight thousand articles. How would you build it?
00:12 YOU Let me make sure I have the shape of it before I design
anything. Who is searching -- customers, or support
agents? And is this replacing the existing keyword
search or sitting next to it?
[two questions, both of which change the answer]
00:25 INT Customers. Replacing it.
00:30 YOU Then the failure I care most about is returning nothing
useful for a common question, because that is a support
ticket. How often do the articles change, and is there
a latency number I should be designing to?
00:45 INT Articles change a few times a week. Under 300ms.
00:52 YOU Good, that rules some things out. Eight thousand articles
is small -- that is the main thing shaping this. I am
going to say the sizes out loud because they decide the
design: chunked at a few hundred tokens, that is maybe
fifty thousand vectors, which is tens of megabytes. It
fits in memory on one machine. So I do not need a
distributed vector database, and I would push back on
one if it were proposed.
[does arithmetic unprompted, and states what it rules out]
01:30 INT Go on.
01:35 YOU Embed the chunks offline, keep them in a single index,
embed the query at request time and take the nearest
twenty. I would run keyword search alongside it rather
than instead of it, because exact terms -- error codes,
product names -- are where embeddings are weakest and
where help centre queries actually live. Then combine
the two lists.
02:20 INT How would you combine them?
02:24 YOU The standard answer is reciprocal rank fusion. I know
the shape of it -- you score each document by one over
its rank in each list and add them, so a document that
is fifth in both beats one that is first in one and
absent from the other. What I do not remember is the
constant that goes in the denominator, and I would not
guess it in a design round. I would look it up, and I
would also try the dumbest version first, which is a
weighted sum of the two scores, and see whether fusion
beats it on our own queries.
[the strongest thirty seconds in the transcript: knows
the mechanism, names the gap precisely, says what they
would do about it, and proposes a baseline]
03:10 INT Most people just say "reciprocal rank fusion" and stop.
03:14 YOU It is the kind of thing that is easy to name and easy to
get subtly wrong. I would rather tell you where my
knowledge ends than have you find out at line forty.
03:25 INT Fair. What about re-ranking? I would put a cross-encoder
in front of this.
03:32 YOU I would not start there, and I want to say why rather
than just disagreeing. A cross-encoder scores every
candidate against the query, so twenty candidates is
twenty forward passes inside a 300ms budget, and it adds
a second model to operate. The reason to pay that is
when retrieval is returning the right document outside
the top few, and I do not know yet whether it is. So I
would ship without it, measure recall at twenty against
a set of real queries, and add the re-ranker if the
document is being found but ranked badly. If you have
seen it be necessary at this scale, though, I would
want to hear that -- it would change my order.
[disagrees with a cost, a condition and a measurement,
then leaves the door open. Scored as senior, not as
difficult]
04:30 INT No, that is reasonable. Where does this break?
04:35 YOU Two places. Articles change a few times a week, so
something has to re-embed them, and the version I just
described has no story for that -- I would want a job
that re-embeds changed articles and an index that can be
rebuilt from scratch in minutes, because at eight
thousand documents rebuilding is cheaper than being
clever about updates. The second is that I have no way
to tell whether it is working. Before any of this I
would want fifty real queries with the article that
should come back, so that every change after today
produces a number.Clarify first, always#
Questions are deliberately underspecified. Asking is not a stall, it is part of the assessment, and candidates who start coding immediately lose marks before they write anything. The test for whether a question is worth asking is whether the two possible answers lead to different designs. If they do not, you are performing curiosity rather than reducing uncertainty, and experienced interviewers can tell the difference.
question what it changes
who is the user? tolerance for a wrong answer
how much data? whether one machine is enough
how often does it change? batch or streaming, cache or not
what is the latency budget? how many model calls you can afford
what happens when it is wrong? whether you need a human in the loop
is this replacing something? what the baseline to beat is
what does success look like? what you are allowed to measureOne habit doubles the value of the answers: repeat back what you heard in the form of a constraint. Saying that eight thousand articles fits in memory so a distributed store is not needed turns a fact you were given into a decision you made, and the second is what gets written down.
Saying you do not know#
Every loop contains at least one question you cannot answer, by design. It is there to see what you do. The failure is not the gap, it is the bluff, and interviewers detect bluffing with unpleasant reliability because they ask a second question and the answer stops being specific.
The shape that works, in four parts:
1. name the boundary precisely "I know how it works, not the
exact formula"
2. give what you do have "it scores by one over the rank
in each list"
3. say what you would do "I'd look it up before using it"
4. offer the baseline "and I'd check the simple version
beats nothing first"
Bad Why it fails
"I'm not sure" stops there. Nothing to score.
"I think it's probably..." a guess wearing a hedge. The
follow-up exposes it in one turn.
"I haven't used that" true and useless. Say what you
would do instead.
confident invention the worst outcome available. It
converts a small gap into a
question about trustworthiness.There is a real asymmetry here worth internalising. An admitted gap costs you a fraction of one question. An invention that is caught costs you the interviewer's trust in everything you said before it, including the parts that were true, because they now have no way to tell which those were. The expected value is not close.
Disagreeing well#
Interviewers propose things they do not believe in, to see whether you will agree with a senior person for social reasons. Agreeing to something you think is wrong is scored as a failure, and so is digging in. What is being looked for is whether you can hold a position with a reason and update it with evidence.
A disagreement that scores well has four parts:
acknowledge the reason it was proposed "a cross-encoder would
improve ranking, yes"
name the cost concretely "twenty forward passes
inside 300ms, plus a
second model to run"
give the condition that would change "if recall at twenty is
your mind fine and ranking is bad,
it becomes the right call"
propose how to find out "I'd measure that first"
And then actually update if they give you evidence. Changing your
mind when given a reason is a separate positive signal from having
had the position, and you only get it by having had the position.Say the words that mark it as a disagreement rather than leaving it implicit. Something as small as saying you want to push back on that, and here is why, tells the interviewer you know you are disagreeing and have chosen to, which is a different thing from not having understood the suggestion.
Being stuck is normal#
What is being assessed is how you behave when stuck, not whether it happens. Say where you are, state what you have ruled out, and propose the next thing to try.
"I'm stuck on the update step. I know the brute force is O(n²)
and I need better. I don't think sorting helps because the order
changes. Let me try working backwards from the end and see if
that gives me something incremental."Three sentences: where I am, what I eliminated and why, what I will try next. It also makes it possible for the interviewer to help you, which they usually want to do and cannot do for someone who has gone quiet. Take the hint when it comes, say what it unlocked, and carry on. Taking a hint well is scored positively; arguing with one is the most expensive thirty seconds available in an interview.
Talking about your own projects#
Deep-dive rounds reward specifics. Vague ownership claims collapse under two follow-up questions, and interviewers ask exactly two follow-up questions.
- Name the actual problem and why it mattered, not the technology used.
- Name a decision you made, the alternative, and why you chose as you did.
- Give a number: latency, cost, volume, error rate. Numbers signal you measured.
- Say what you would do differently. This reads as seniority, not weakness.
- Be exact about what you personally did when the work was shared.
what you say what it is heard as
"we built a RAG pipeline" you were in the room
"I owned retrieval; someone you did the retrieval work
else built the ingestion"
"it was much faster" you did not measure it
"p95 went from 4.1s to 900ms" you measured it
"we chose Postgres" someone chose Postgres
"I chose Postgres over a you made a decision and can
vector database because 50k defend it
vectors fit in one table"
"it worked well" no failures, therefore no
learning, therefore junior
"it worked until the index you ran it in production
went stale on a Friday"Prepare eight stories, not one
Conflict, failure, ambiguity, influencing without authority, a hard technical decision, a time you were wrong, a time you disagreed with a manager, something you shipped that mattered. The same underlying project can supply several, but rehearse them separately.
Where people go wrong
Claiming broad ownership of team work. Two follow-up questions expose it, and the recovery is much worse than having been precise in the first place.
Build this: Record yourself solving a problem out loud for thirty minutes. Watch it back and mark every silence longer than ten seconds. Those are the moments an interviewer had nothing to assess.
Open this section on its own pagePreparing stories and practising for real
By the end: You have a bank of real stories that answer the common questions, and a practice routine that exposes your weak spots.
- A story bank
- Structure without sounding rehearsed
- Numbers and your own role
- The questions behind the questions
- Mock interviews that help
Behavioural questions come from a short and predictable list, and the reason capable engineers answer them badly is that they improvise. This section builds a bank of six to eight real stories from your own work, each written so it can answer several of those questions, with a number in it and your own part separated from the team's. The second half is the practice routine: out loud, recorded, fixing one thing at a time. The gap between knowing a story and telling it well is larger than it feels from the inside.
Build a story bank#
Behavioural questions repeat: a hard technical problem, a disagreement, a failure, a time you led, a time you changed your mind. Write six to eight real stories from your work, each of which can answer several of these.
Story: RAG answers going stale
Situation support bot cited archived articles, 17 of 48 failures
My part found it in trace review, proposed excluding archived docs
Result held-out pass rate 10/24 -> 17/24, cost +8%
Answers hard problem, using data, influencing without authorityWrite each one on a single index card in that format, and keep the cards. The point of the format is that it is too short to hide in: if you cannot name your part in one line, you do not have a story, you have a project you were near. Six to eight cards covers the question list with redundancy, which matters because a loop will sometimes ask two questions that your best story answers and you cannot tell it twice.
A bank that covers the list, with no story used twice:
card answers
index went stale hard problem, data, influence
argued against the rewrite disagreement, changed my mind
I shipped a bad migration failure, ownership, what I changed
took over the on-call rota leadership without the title
the eval nobody wanted persuading, long-horizon work
the feature we cancelled judgement, saying no
the intern's first PR mentoring, giving feedback
the Friday outage pressure, communication under stress
The gaps in that table are what to go looking for. Most people
have four cards that are all "hard technical problem" and
nothing at all for disagreement or for feedback.Structure, and what each part is for#
Context in two sentences, what you did in most of the time, the result with a number, what you learned. The most common mistake is spending two minutes on context and thirty seconds on your actions. Interviewers are scoring what you did.
part length what it must contain what it is for
situation 2 sent. why this was hard makes the rest legible
and who cared
task 1 sent. what you specifically establishes ownership
were on the hook for before any actions
action 60-70% decisions, alternatives, this is the part being
what you rejected and why scored. All of it.
result 1-2 a number, and what it makes it verifiable
meant for someone
reflection 1 sent. what you do differently reads as seniority
Three minutes total. If your situation is longer than thirty
seconds, you are explaining your old company rather than
answering the question.One story, written out#
Here is the card above told properly, at the length it should actually take, with what each part is doing beside it. Read the right-hand column first if you want to see the machinery.
"Our support bot was answering confidently SITUATION. Two sentences,
from articles we had archived two years and it names who was hurt
ago. Customers were getting instructions rather than what the stack
for a product page that no longer existed, was.
and we found out from a complaint rather
than from a dashboard.
I owned retrieval quality. Nobody had asked TASK. "I owned" in the
me to look at this -- the ticket was filed first four words. Note the
against the support team." second sentence: it says
the work was not assigned,
which is the whole reason
this answers "influencing
without authority" too.
"I started by counting rather than guessing. ACTION, and it opens with
I pulled the last hundred conversations the a method, not a fix. This
support team had flagged and read the traces, is the sentence that most
and 17 of 48 failures cited a document that candidates skip.
was archived. That made it the largest single
cause, ahead of the retrieval problems I had A number, and what the
assumed were dominant. number displaced. The
comparison is what makes
it a finding.
I proposed the cheap fix first: exclude Decision, with the
archived documents at index time. The alternative named. An
alternative was a freshness score in the interviewer is listening
ranker, which is better in principle and for exactly this.
would have taken a sprint. I argued for the
exclusion because we could ship it in a day And the reason for the
and measure whether staleness was really the choice, which is a
problem before building the ranking work. reason about evidence
rather than about effort.
The part I got wrong was that I assumed the
archive flag was reliable. It was not -- about Volunteers a mistake
a tenth of the archived set had been unprompted, inside the
mis-flagged during a migration, and my first story. This is worth more
version dropped good articles. I caught it than the fix is.
because the eval score went down, not up,
so I added a check that the article had not Caught it with a
been viewed in six months as a second signal." measurement, not by
noticing. That is the
detail that makes the
story true.
"Held-out pass rate went from 10 of 24 to 17 RESULT. A number, and the
of 24. Token cost went up eight per cent cost of getting it. Giving
because the retrieved documents were longer. the cost is what stops this
We shipped the freshness ranker a quarter reading as a sales pitch.
later, on evidence rather than on my hunch.
What I would do differently: the reason we REFLECTION. Names a
learned about this from a customer is that change to the system, not
we had no measure of answer staleness at a promise to be careful.
all. I would put a cheap check on document
age into the eval set on day one now."Nothing in that story is impressive on its own. The archived-document bug is mundane, the fix is a filter, and the whole thing took a week. That is the point: a good behavioural answer is not made of a good project, it is made of visible reasoning applied to an ordinary one. Candidates who believe they have no stories almost always have this and have discarded it as too small.
The two ways a story fails#
Both failures are invisible to the person telling the story, because from the inside both feel like modesty or like staying on topic. Here they are side by side with the same underlying week of work.
NO CONFLICT
"We noticed some answers were citing old articles, so we filtered
out archived documents at index time and the pass rate improved."
What is missing: nothing was hard. No decision was made, no
alternative was rejected, nothing went wrong, nobody had to be
persuaded. There is no conflict, so there is nothing to score.
What the interviewer writes: "worked on retrieval. Could not
identify a decision. Ask again with a harder prompt."
The fix is not a bigger story. It is naming the fork: the
sprint-long ranker you did not build, the flag you trusted that
was wrong, the person who wanted to do it differently. Every
real week contains at least one.
NO PERSONAL CONTRIBUTION
"We were seeing stale answers, so we reviewed traces and found
archived documents were the main cause. We decided to exclude
them, we validated it against our eval set, and we got the pass
rate up to 17 out of 24."
Every sentence is "we". The story is good and the candidate is
invisible. Worse, it now sounds like a hedge: an interviewer
who hears seven "we"s in a row starts wondering which parts
were not yours, and will spend the follow-ups finding out.
What the interviewer writes: "strong project, unclear role.
Probe ownership."
The fix is one pass over the story replacing "we" with "I", "a
colleague" or "the team", whichever is true. Naming what
somebody else did is what makes the "I" believable -- a story
where you did everything is its own warning sign.Say 'I', and be exact#
'We built a pipeline' tells the interviewer nothing about you. Say what you personally did, what others did, and what you decided. Be honest about the parts you did not own; follow-up questions will find them anyway.
Exactness applies to the numbers too, and in the other direction from what people expect. A figure you are sure of is worth more than a bigger one you are guessing at, because the follow-up is always how you measured it. If you genuinely do not remember, say the shape and say that: it roughly halved, and you can describe the query you ran to know that. Inventing a precise number you cannot defend is the fastest way to lose a round you were winning.
What they are really asking#
- 'Tell me about a failure' asks whether you take responsibility and learn, not whether you have failed.
- 'A disagreement' asks whether you can disagree with evidence and still work together. The ending matters: a disagreement where you were persuaded is a better answer than one where you won.
- 'Something you are proud of' asks what you consider good work.
- 'A time you had to make a decision without enough information' asks whether you can act under uncertainty and say what would have changed your mind.
- 'Tell me about a conflict with a colleague' asks whether you can describe someone you disagreed with fairly. Describing them unfairly is the whole answer.
- 'Why this company' asks whether you have thought about it for more than five minutes.
Notice how many of these are asking about the same thing from different angles, which is whether working with you would be pleasant when things are going badly. That is most of what a behavioural round is for, and it is why the details people leave out as unflattering are usually the ones that score.
Mocks that help, and mocks that comfort#
Most mock interviews are useless in a specific and predictable way: a friend who likes you asks a question, you answer it, they say that was good, and you both feel prepared. A useful mock is uncomfortable on purpose, and the discomfort comes from structure rather than from the person being harsh.
Rule Why
They do not know the story A friend who already knows the
beforehand. project fills in your gaps
silently. A stranger cannot.
They must interrupt twice. Real interviewers do. Being
interrupted mid-story and
recovering is the skill.
They must ask two follow-ups The first answer is rehearsed.
on your weakest claim. The third is where you actually
find out what you know.
They write, and do not react. No nodding, no "great". Silence
is what the room feels like.
Timed, and stopped at time. A story that needed five minutes
is a story you have not finished
writing.
Feedback is three sentences, More than one thing to fix is
one of which is what to fix. nothing to fix.
Recorded, and you watch it The recording is where the
alone afterwards. learning is. The mock is only
how you generate it.Weekly is the right cadence in the final month, alternating coding, design and behavioural rather than doing your favourite one three times. Exchange with someone at a similar level and take both roles, because interviewing somebody else for forty minutes teaches you more about what reads as competent than being interviewed does. Sit through one silence as the interviewer and you will never let one happen as the candidate.
One fix per session
After each mock, write down a single thing to change and change only that in the next one. Lists of six improvements produce none, because under pressure you revert to habit and habit changes one item at a time. Filler words, then the missing numbers, then the ratio of context to action, then the pronouns -- four sessions, four fixes, and the answers are unrecognisable.
Practise out loud, with feedback#
- 1.Answer every story out loud and record it. Listen back; you will hear the filler and the missing numbers.
- 2.Do mock interviews with another person at least weekly in the final month, for coding, system design and behavioural rounds.
- 3.After each mock, write down one thing to fix, and fix only that in the next one.
- 4.Practise coding while talking. Silence is the most common reason a correct solution scores poorly.
- 5.Time one telling of each story. Anything over three and a half minutes is being cut by the interviewer, and they will cut the part you cared about.
Where people go wrong
Memorising answers word for word. They sound rehearsed, and they break at the first follow-up question.
Build this: Write six stories in the format above from your own work or projects. Record yourself answering five common behavioural questions using them, listen back, and rewrite the weakest two.
Open this section on its own pageThe coding round where the spec keeps changing
By the end: Your first version survives the third change to the requirements, and you can say why you chose to refactor or to bolt on.
- The shape of a levelled problem
- Making version one extensible without over-building it
- Naming your assumptions so they can be corrected
- Refactor or bolt on
- A worked rate limiter through four levels
One problem, revealed in roughly four levels, each adding a requirement to the last, and you are not told the later ones in advance. This section is about what that format measures, which is whether your first version survives the third change rather than how clever it was. The working rule is a budget: at level one you buy extensibility that costs a line, such as an injected clock or a keyed state, and refuse anything that costs a structure. A rate limiter is taken through all four levels so you can see which early decisions paid and which cost.
One problem, four levels#
The dominant live-coding format at frontier labs, and increasingly elsewhere, is one problem in roughly four levels. Each level adds requirements to the last, or layers an extension onto a base problem. You are not told the later levels in advance. Some loops run this as a timed assessment, others as a live pairing session with an interviewer reading the next requirement out when you finish the previous one.
What is judged is whether your first design survives the third change, not asymptotic cleverness. A candidate who reaches level four with an ugly but coherent design scores above one who wrote an elegant level one and then rewrote it twice.
The tension is real, so say it out loud#
You are told to write extensible code and also not to over-engineer, and those instructions pull against each other. The resolution is not a principle, it is a budget: at level one you may buy extensibility that costs a line, and nothing that costs a structure.
- Cheap and worth it: inject the clock instead of calling the system one, so the tests you write are not sleep-based.
- Cheap and worth it: put the decision in one method rather than inline at the call sites, so there is one place to change.
- Cheap and worth it: key your state by something, even if there is only one key today.
- Expensive and not yet: a strategy interface, a plugin registry, an abstract base class with one implementation.
- Expensive and not yet: a configuration object for parameters that have one value.
The test for whether an abstraction is cheap is whether removing it would make the code shorter than one screen of reading. If the answer is that it would need explaining, you bought a structure at level one.
Name your assumptions out loud#
Every underspecified problem has three or four assumptions that decide the design, and the interviewer knows which ones the later levels will break. Saying them aloud gives them the chance to correct you before you build on the wrong one. This is the highest-value thing you do in the first five minutes.
"I am going to assume single-threaded and single-process for
now, and I will keep the state behind one method so I can change
that later. I am also assuming keys are opaque strings and that
we do not need to evict them yet. Tell me if either of those is
wrong."Level one: a rate limiter that works#
Take a rate limiter, one of the most commonly reported problems at this tier. Level one is usually the plain version: allow at most a fixed number of calls per key per window.
import time
class RateLimiter:
"""Fixed window: at most limit calls per window seconds, per key."""
def __init__(self, limit: int, window: float, now=time.monotonic):
self.limit = limit
self.window = window
self._now = now
# key -> (window start, calls used in it)
self._state: dict[str, tuple[float, int]] = {}
def allow(self, key: str) -> bool:
t = self._now()
start, used = self._state.get(key, (t, 0))
if t - start >= self.window:
start, used = t, 0
if used >= self.limit:
self._state[key] = (start, used)
return False
self._state[key] = (start, used + 1)
return TrueThe injected clock also means you can test it without sleeping, which matters when you have forty minutes for four levels. A test at this point is not ceremony, it is the thing that tells you whether level three broke level one.
def test_fixed_window():
clock = [0.0]
limiter = RateLimiter(limit=2, window=10, now=lambda: clock[0])
assert limiter.allow("alice")
assert limiter.allow("alice")
assert not limiter.allow("alice")
assert limiter.allow("bob") # keys are independent
clock[0] = 10.0
assert limiter.allow("alice") # window rolled overLevel two: several limits at once#
The usual second level is more than one rule per key: five per second and a hundred per hour, or a per-endpoint limit on top of a per-user one. This is where hardcoded solutions die, because a single limit and window baked into the constructor has no room for a second rule.
It is also where the first genuine design question appears, and it is not about data structures. If a call passes the per-second rule and fails the per-hour rule, the per-second budget must not have been spent. Checking and consuming have to be separate passes.
import time
from dataclasses import dataclass
@dataclass(frozen=True)
class Rule:
limit: int
window: float
class RateLimiter:
"""All rules must pass. A rejected call consumes no budget."""
def __init__(self, rules: list[Rule], now=time.monotonic):
self.rules = rules
self._now = now
# (key, rule index) -> (window start, calls used in it)
self._state: dict[tuple[str, int], tuple[float, int]] = {}
def _window(self, key: str, i: int, rule: Rule, t: float):
start, used = self._state.get((key, i), (t, 0))
if t - start >= rule.window:
return t, 0
return start, used
def allow(self, key: str) -> bool:
t = self._now()
pending = []
for i, rule in enumerate(self.rules):
start, used = self._window(key, i, rule, t)
if used >= rule.limit:
return False # nothing written, so nothing was spent
pending.append(((key, i), (start, used + 1)))
for slot, value in pending:
self._state[slot] = value
return TrueSay the all-or-nothing decision out loud when you make it. It is the part an interviewer is watching for, and a candidate who spends the per-second budget on a call that was then rejected has a bug that only shows under a specific ordering.
Levels three and four#
Level three is usually one of two things. Either the caller needs to know how long to wait, which means allow returns a retry-after rather than a boolean and every caller changes; or several threads share the limiter, which means the read-check-write in allow is a race and needs a lock around the whole of it. Both are contained by the level two design, because there is exactly one method doing the deciding.
Level four is usually distribution: several processes sharing one budget. Nothing about the rules changes, but the dictionary has to become a store that another process can read, and the read-check-write has to become atomic in that store rather than in your process. The honest answer under time pressure is to extract the two lines that touch self._state into a small store interface, implement it in memory, and describe the backing implementation rather than write it.
Level 1 one limit per key
Level 2 several rules, all-or-nothing consumption
Level 3 retry-after, or thread safety
Level 4 shared across processes, atomic in the store
What changed each time: the state key, and the inside of one
method. What never changed: allow(key).Refactor or bolt on#
Both are correct answers at different moments, and the failure is doing neither deliberately. Refactor when the new requirement contradicts a shape you chose, because bolting onto a contradiction produces a second code path that the next level will have to be added to twice. Bolt on when the new requirement is additive and the shape still holds.
- Refactor when you would otherwise write a second branch that duplicates an existing one.
- Refactor when the fix is a flag threaded through three methods.
- Bolt on when the change is one new field and one new check.
- Bolt on when you have under ten minutes left, and say that is why.
Announce it either way: 'this contradicts the single-window assumption, so I am going to spend three minutes restructuring rather than special-casing it' is a sentence that scores. Quietly rewriting for eight minutes while the interviewer watches is the same work with none of the credit.
The clock, as a habit#
Almost every levelled problem at this tier has a hidden dependency that later levels vary: the clock in a rate limiter, the storage in a key-value store, the transport in a batch processor, the random seed in a sampler. Passing it in at level one costs one parameter and buys you the next three levels.
If level two made you delete level one, you did not have a design
The point of the format is that the first version is a claim about what will vary. If the first requirement change forced a rewrite rather than an edit, the claim was wrong, and the fix is not to build more at level one but to keep the decision in one place. Equally, if you spent level one building an interface that level four never needed, you traded working code for a guess.
Where people go wrong
Building a beautiful abstraction at level one and running out of time, or building something so hardcoded that level two requires starting again. Both fail for the same reason: version one was written as if it were the final answer rather than the first of four.
Build this: Give yourself forty minutes and a timer. Build the rate limiter above through all four levels, revealing each requirement to yourself only when the previous one passes its test. Note the minute at which each level started, and afterwards work out which single decision at level one cost you the most time later.
Open this section on its own pageBeing drilled on your own work
By the end: You can be questioned three levels deep on a project you actually did, including its failures, without collapsing or performing.
- Choosing which project to present
- The question chain that always comes
- Depth: the same answer, shallow and properly
- Talking about a failure
- Handling 'why didn't you just'
There is a round where someone takes a project off your CV and asks about it until you run out of answers, and it goes about three levels deeper than most people prepare for: what you built, why that way, and what you considered and rejected. This section prepares the third question, which is the one that decides the round, because it asks about paths you did not take and so cannot be answered out of familiarity with the code. It also covers choosing which project to present, and how to describe a failure without either minimising it or performing remorse.
The round people most underestimate#
Near-universal at frontier labs and big tech, and reliably underprepared, because candidates assume that familiarity with their own work is preparation. It is not. You know what you built; the round asks why, what you rejected, and what you would change, and those are different memories.
The formats vary. Some organisations ask for a written statement of your best work submitted up front and question you on it. Some ask for a slide presentation to several people. Some run it as an hour with a hiring manager and no artefact at all. The mechanic underneath is identical: three levels deeper than you expect, on anything your CV claims.
Level 1 What did you build? everyone prepares this
Level 2 Why that way? most people manage this
Level 3 What did you reject, and why? this is where it decidesChoosing the project#
Pick the one where you made real decisions, not the one with the biggest name attached. A minor feature you owned end to end beats a famous system you were adjacent to, every time, because the questions are about decisions and you only have answers for decisions you made.
- Did you choose the approach, or implement someone else's choice? Only the first survives three questions.
- Can you name something you considered and rejected? If not, you were executing rather than deciding.
- Do you know a number about it? Latency, cost, volume, error rate, or how long it took.
- Do you know what went wrong? A project with no problems is a project you did not run.
- Can you explain it to someone outside your team in two minutes? If not, you will spend the round on context.
Scale is not the criterion. Interviewers at this level have seen large systems described by people who could not say why a queue was there. A small project with real decisions in it reads as stronger than a large one you can only narrate.
The chain that always comes#
- 1.What did you do, as opposed to what the team did?
- 2.Why that approach?
- 3.What did you consider and reject, and what would have changed your mind?
- 4.What went wrong?
- 5.What would you change if you did it again?
Prepare the chain, not the story. Written out, each project should have five answers rather than one narrative, because you will be asked them in this order and interrupted between them.
The same answer, shallow and properly#
The difference is not length. A shallow answer describes what exists; a deep one describes the decision, including the thing it was chosen over and the evidence that settled it.
Shallow:
"We built a retrieval system for our support docs. I used a
vector database and chunked the documents, and it worked well.
Users were happy with it."
Nothing here can be followed up except by asking the same
question again. There is no decision, no alternative and no
number.At depth:
"Support answers were citing archived articles. I owned
retrieval; a colleague owned the answer generation.
I started with fixed-size chunks because it was an afternoon's
work and I wanted a baseline. It scored 10 of 24 on a held-out
set of real questions I had labelled.
I considered fine-tuning, and rejected it: the failures were
wrong facts, not wrong form, and fine-tuning does not reliably
install facts. The cheap fix was metadata filtering on the
archived flag, which took two hours and moved us to 17 of 24.
Cost went up 8% because the filter reduced cache hits.
What went wrong: I labelled the held-out set myself, so it
encoded my idea of a good answer. Two of the remaining failures
were questions support staff would not have marked wrong.
If I did it again I would have someone from support label the
set before I started tuning anything."Talking about a failure#
There are two failure modes and interviewers see both weekly. Minimising turns the failure into a success with an obstacle in it. Performing contrition turns it into a display of how seriously you take things, which reads as avoiding the technical content.
The shape that works is flat and factual: what happened, what it cost, how you found out, what you did, and what changed so it cannot recur. Deliver it in the same tone you would use for a design decision, because to an interviewer that is what it is.
Minimising "There was a small issue but we caught it quickly
and it was mostly a process problem."
Performing "I still think about it. It taught me how much
responsibility I carry and I have never stopped
being careful since."
Flat "I shipped a change that dropped retrieval quality
for a fifth of queries. Nobody noticed for nine
days because we had no eval running in CI. A
support lead reported it. I reverted it that
afternoon, then spent two days building the eval
gate that should have existed first."Note what the third version does not contain: an adjective about how the candidate felt. The regret is carried by the facts, and the interviewer can see the judgement without being told it is there.
'Why didn't you just...'#
Sometimes the honest answer is that you did not think of it. That answer is safe, and every alternative to it is not. An invented justification is detectable in one follow-up because you are reasoning about a design you never considered, and the interviewer has usually watched several people try it.
"I didn't consider that. Thinking about it now: it would have
avoided the filtering step entirely, and the cost would have
been re-indexing whenever the archive flag changed. Given how
often that happened, it would probably have been the better
call."The other case is that you did consider it and had a reason. Then give the reason and the evidence, and be willing to concede if the interviewer's version is better. Defending a decision past the point where it has been shown to be wrong scores far worse than changing your mind out loud.
If you cannot name what you rejected, you are presenting the wrong project
A project where you made no choices has no answer to the third question in the chain, and no amount of familiarity with the codebase substitutes for one. The collapse usually happens at the second follow-up: the candidate explains the system fluently, is asked why it was built that way, and has to say that it was already like that. Choose a smaller project you actually decided.
Where people go wrong
Presenting a project you did not personally make decisions on, usually because it is the most impressive thing on your CV. It collapses at the second follow-up, when 'why was it built that way' has no answer but 'it already was'.
Build this: Write the five-question chain out for your strongest project, in full sentences, and give a number in at least two of the answers. Then have someone who does not know the domain ask you the chain and interrupt with 'why didn't you just' at least twice. Mark every point where you reached for a justification you had not thought before.
Open this section on its own pageThe rounds that are not about code
By the end: You can hold a specific position on AI risk under pushback, and you know the rules on assistant use in each round because you asked.
- Mission and values rounds, and why strong engineers fail them
- Holding a position under pushback
- Consistency across the whole loop
- AI-assisted rounds, where the rules genuinely differ
- Directing an assistant while someone watches
Two parts of a hiring loop contain no code and still decide outcomes: a values round about how you actually think about AI risk, and the question of whether you may use an AI assistant in a given round. This section covers both. The first cannot be rehearsed, because what is assessed is whether the position is yours and holds up over three exchanges of pushback, and a borrowed one does not. The second is not something to infer from the room: the rules differ by company and by round, so you ask the recruiter beforehand, in writing.
Two underprepared rounds#
Both of these are non-technical in the sense that no code is written, and both decide outcomes. Candidates prepare for neither, because neither looks like an interview.
Mission and values#
At least one frontier lab runs a standalone non-technical round on ethical reasoning and a candidate's actual relationship to AI risk, and it is reported as a round where technically strong engineers fail. Big tech runs a structurally similar thing against a published set of principles, sometimes with an interviewer who can veto the loop on their own.
What is being assessed is not a conclusion. It is whether you have thought about the question at all, and whether the position you hold stays the same when it is pushed on. Two answers fail equally: performed doom, which is a position adopted for the room, and dismissiveness, which reads as not having engaged with why the organisation exists.
This section does not tell you what to believe
Nothing here is an argument for a view about AI risk, and a page that supplied one would be supplying exactly the borrowed position that fails this round. What is assessed is that you have thought it through and can hold it under pushback. If you are reading this hoping to be told the answer that passes, that is the failure mode.
So the preparation is real work rather than rehearsal. Read what the organisation has published about why it does what it does, and form an actual response to it: which parts you find convincing, which you do not, and what would change your mind. That last one is the question most people have no answer to, and it is asked.
Where you disagree is a real question#
When you are asked where you disagree with the organisation, it is not a trap and it is not a modesty prompt. The expected answer is a disagreement. A candidate who says they agree with everything has either not read anything or is managing the room, and both are visible.
Weak "I agree with the whole approach, that's why I applied."
Weak "I think this technology could end humanity and that
terrifies me." (if you do not in fact think this)
Weak "I don't really buy the risk stuff, I just want to build."
Stronger A specific position, held for stated reasons, that you
can defend for three follow-ups and revise if the
interviewer supplies something you had not considered.Being pushed on is the point. Expect the interviewer to argue the other side, including a side they may not hold, and to keep going for two or three exchanges. Holding a position is not refusing to move: conceding a specific point while keeping the position is a strong answer, and abandoning the whole position under mild pressure is not.
Consistency across the loop#
The values round is not the only place this is checked. What you say about why you want the job in the recruiter screen, what you say about a trade-off in a design round, and what you say in the values round are compared afterwards, particularly where hiring decisions go through a committee or a debrief rather than one manager.
A candidate who describes careful deployment as their central concern and then, in a design round, proposes shipping a model to users with no evaluation gate has answered inconsistently, and the debrief will notice. Say the thing you actually think, in every room, and this problem does not arise.
The AI-assisted round#
The rules on using an assistant genuinely differ by company and by round within one company. Some AI-native companies now require you to use one and judge how well you direct it. At least one frontier lab publishes candidate guidance on where assistants are and are not permitted in its process. Some organisations ban them in the first screen and allow them later, and some ban them in live rounds while explicitly allowing them on a take-home.
None of that is stable enough to assume, in either direction. The only safe move is to ask beforehand, of the recruiter, in writing, for each round.
To the recruiter, before the loop:
"Can you confirm the policy on AI assistants for each round?
I want to make sure I am set up the way you expect, including
whether it differs between the screen, the live rounds and
any take-home."Being watched while you direct an assistant#
Where use is expected, what is assessed is direction rather than output. The interviewer is watching how you frame the request, whether you read what came back, and what you do when it is wrong.
- State the intent before prompting: what you are asking for and why this part rather than another.
- Ask for the piece you have decided on, not for the problem. Handing over the whole question is the clearest signal of not having a design.
- Read the output aloud and say what you are checking: the edge case, the type, the assumption it made silently.
- Catch the wrong answer. An assistant that produced a plausible bug and a candidate who noticed is the best possible version of this round.
- Say when you are not using it, and why. 'This part is twenty lines and I know exactly what I want, so I will type it' is a decision, not a refusal.
The failure that reads worst is accepting output you have not read, particularly when it is subtly wrong and the interviewer can see it. The second worst is silence: pasting a prompt, waiting, pasting the result, and never saying what you expected. That is the same silence problem as any other round, with a second participant.
Being unable to work without an assistant is as visible as being unable to work with one. Both are tested, sometimes in the same loop: a screen with tools banned followed by a take-home where they are allowed measures exactly these two things, and a candidate weak at either end shows it.
If you assumed the policy, you have already failed the round you assumed about
Both directions end badly. Using an assistant where it was disallowed is treated as dishonesty rather than a misunderstanding, and at several organisations it ends the process. Refusing to use one where it was expected reads as not being able to, in a role where the work involves it daily. There is no reading of the room that substitutes for the question.
Where people go wrong
Assuming a policy rather than asking, in either direction: using an assistant where it was disallowed, which is treated as dishonesty, or refusing one where it was expected, which reads as being unable to work with the tools the job uses daily.
Build this: Write one page on what you actually think about AI risk, including one thing you disagree with at an organisation you are applying to and the evidence that would change your mind. Have someone argue the opposite for ten minutes without letting you off. Separately, send the recruiter the assistant-policy question for every loop you are in, and write the answers down per round.
Open this section on its own pageNow actually do it
Reading a topic is not learning it. These are the hours that count, and each one tells you when you are finished.
1Eight stories, rehearsed separately
6hConflict, failure, ambiguity, influence without authority, a hard technical decision, a time you were wrong, disagreeing with a manager, something shipped that mattered. Each with a number in it and a what-I-would-do-differently.
Done when: You can tell any of the eight in two minutes without preparation, and each contains a specific number.
2Three timed system designs, out loud
4hDocument question answering, an agent acting on a customer account, and a moderation pipeline. 45 minutes each, recorded. Cover failure handling, cost arithmetic and evaluation without being prompted.
Done when: On the recordings you raised failure, cost and evaluation yourself in all three.
3Four AI-assisted coding rounds
6hUnfamiliar problems with an agent, narrating scoping, iterating the plan before executing, reviewing every diff aloud, writing tests unprompted. Then close the tool and defend the code cold.
Done when: You can explain every line without the agent open, and the recordings show visible process rather than silence.
4Deep-dive grilling on your flagship
4hHave someone adversarially question your project for an hour: every design choice, every number, what breaks, what you would change. Or record yourself answering the twenty hardest questions you can invent.
Done when: No question makes you retreat to vagueness, and you can name three things you would do differently.
20 hours of practice
Interview questions
14 questions, grouped by the section that teaches the answer. An answer you have read is not an answer you can give, so use Test yourself and say it out loud first.
Communicating while you work
Tell me about a technically difficult project.
Lead with the problem and why it mattered, not the stack. Name one hard decision, the alternative you rejected and why. Include a number that shows you measured. Finish with what you would do differently, which reads as judgement rather than doubt.
Tell me about a time you were wrong.
Pick something genuinely wrong with a real consequence, say how you found out, what you did immediately, and what changed afterwards so it could not recur. Avoid the disguised strength, which every interviewer recognises instantly.
What do you do when you are stuck in an interview?
Say so, state what has been ruled out and why, and propose the next thing to try. Interviewers expect candidates to get stuck; they are assessing how you behave when it happens.
Preparing stories and practising for real
Tell me about a time you were wrong about a technical decision.
Pick a real one where the decision mattered. Say what you believed and why it was reasonable at the time, what evidence showed you were wrong, what you did about it, and what you do differently now. The learning is the point of the answer.
Then they push further
What would you do differently if you faced that decision today?
Name a concrete change in how you decide, such as prototyping before committing, or setting a measurable check that would have caught it earlier. A general 'I would be more careful' scores poorly.
What gets marked up. Strong answers own the mistake without excuses, show the evidence that changed their mind, and end with a specific change in behaviour.
Walk me through a project you are proud of.
Two sentences of context, then the hardest problem and how you solved it, your decisions and the alternatives you rejected, and the result with numbers. Be ready to go deep on any part, because the interviewer will choose one.
The coding round where the spec keeps changing
How do you write the first version of a problem you know will get harder, without over-engineering it?
Spend only on extensibility that costs a line rather than a structure: inject the clock or the store, key the state even when there is one key, and keep the decision in one method. Refuse anything that needs explaining, such as a strategy interface with one implementation. Then say the assumptions out loud so the interviewer can correct the ones the later levels will break.
Then they push further
The next requirement contradicts your design. Do you refactor or special-case it?
Refactor when the alternative is a second branch duplicating an existing one, or a flag threaded through several methods, because the level after this will then have to be written twice. Special-case it when the change is additive, or when there is not enough time left, and say out loud that time is the reason.
How do you avoid breaking the earlier levels as you add to them?
Write a small test per level as you finish it, using an injected clock so it does not sleep. Re-running them after each change takes seconds and is the only thing that tells you the third requirement did not break the first.
What gets marked up. Strong answers give a concrete budget for what extensibility is worth buying early, name the hidden dependency they would inject, and treat refactoring as an announced decision rather than something done silently.
Design a rate limiter that supports several limits per user at once.
Keep one allow(key) entry point and key the state by key and rule. Check every rule before consuming any budget, so a call rejected by the hourly rule does not spend the per-second one. That all-or-nothing pass is the part that has a bug in most implementations.
Then they push further
Now make it safe under concurrent callers.
The read-check-write inside allow is the race, so the lock goes around the whole of it rather than around each dictionary access. If the state moves out of process, the same operation has to become atomic in the store instead, which is why it was worth keeping in one method.
You are twenty minutes in and realise the design will not take the next requirement. What do you do?
Say so, immediately, with the reason and a time estimate: what the requirement contradicts, what the restructure is, and roughly how long it takes. Then do it. Recognising it early and out loud is read as judgement; discovering it silently at the last level is read as not having noticed.
Being drilled on your own work
Walk me through the piece of work you are proudest of, and be ready for me to stop you.
Two sentences of context, then the decision you owned, the alternative you rejected and the evidence that settled it, then a number, then what went wrong and what you would change. Say explicitly which parts were yours and which were a colleague's, before being asked.
Then they push further
What did you personally do, as opposed to the team?
Name your part exactly and name what other people owned. Precision here costs nothing and buys credibility for everything else; vague ownership is found by the next question and the recovery is worse than the admission would have been.
What would you do differently?
Give one concrete change in how you would decide, not a resolution to be more careful. The strongest version names something you would do earlier, such as agreeing the evaluation set with the people who use the system before tuning anything.
Why didn't you just do it the other way?
If you considered it, give the reason and the evidence, and concede if theirs is better. If you did not, say so and then reason about it out loud: what it would have avoided, what it would have cost, and whether it was probably the better call.
What gets marked up. Strong answers are specific about personal ownership, name a rejected alternative unprompted, include at least one measured number, and treat a failure as a fact rather than a confession.
Tell me about something in your work that did not work.
State what happened, what it cost, how you found out, what you did immediately, and the change that means it cannot recur. Keep the tone flat. Minimising and performing remorse both read as avoiding the technical content, which is what the question is actually after.
How do you decide which project to present when you are asked for your best work?
The one where you made real decisions, not the one with the most recognisable name attached. The questions are about why you chose an approach and what you rejected, and you only have answers for choices you made. A small owned project beats a large one you were adjacent to.
The rounds that are not about code
What do you think the most serious risk from this technology is, and what would change your mind?
Give a specific position with the reasons you hold it, then answer the second half honestly, because it is the half most candidates have nothing for. Name the evidence that would move you. What is assessed is that the position is yours and survives being pushed on, not which position it is.
Then they push further
Where do you disagree with us?
Give an actual disagreement, specifically, about something you have read. Agreeing with everything reads as not having engaged or as managing the room. Concede a point if the interviewer supplies one you had not considered; that is not losing the exchange.
Then why work here at all, if you think that?
The honest reconciliation, whatever it is. This is the consistency check: the answer has to fit what you said in the screen about why you applied, and what you will say in a design round about shipping carefully.
What gets marked up. Strong answers are specific, consistent with the rest of the loop, and hold under two or three exchanges of pushback while conceding individual points. Performed alarm and blanket dismissal both fail.
Are we allowed to use an AI assistant in this interview?
Ask this of the recruiter before the loop, in writing, for each round, because the rules differ by company and by round within one company. Asking on the day is fine but late; assuming in either direction is the actual risk.
Then they push further
You are told to use one and the interviewer is watching. What does good look like?
State the intent before each prompt, ask for the specific piece you have decided on rather than the whole problem, read the output and say what you are checking, and catch the thing it got wrong. Saying when you are not using it, and why, counts for as much as using it well.
How do you prepare for a values round when you do not know what they want to hear?
You are not meant to. Read what the organisation has published, form an actual response including the parts you disagree with, and work out what would change your mind. Then say the same thing in every round of the loop, because the answers are compared in the debrief.
Resources
Free to watch and read, picked for this topic.
Videos
For communicating while you work
For preparing stories and practising for real
Full courses: the whole topic, start to finish
Stop 50 of 50 on the AI Engineer route
0 of 50 topics done · 0h behind you, 603h to go
That is the last stop on this route. What remains is the part no syllabus can do for you: build the projects, and apply.
What you have marked done is stored in this browser only. It does not reach a server, and clearing site data will clear it.