Practising the process
By the end: You can demonstrate scoping, planning, review and verification under time pressure.
- Scoping out loud
- Planning before executing
- Reviewing a diff properly
- Tests as part of the work
New to working with coding agents? Writing software alongside a coding agent — a model that reads your repository, proposes changes across several files and runs commands — rather than typing every line. The skill is not the wording of the request. It is cutting the task small enough that the result can be checked, reading the diff line by line, and recognising early when it has gone somewhere wrong. Why it matters
Knowing what is being scored does not mean you will do it with somebody watching and a clock running. This section is about rehearsal: stating scope and assumptions before you generate anything, planning in writing, reading a diff line by line rather than skimming it, and treating tests as part of the work rather than something you would have added later. None of it survives pressure unless it was a habit beforehand.
What to delegate and what to keep#
The round is not testing whether you can type. It is testing whether you know which parts of the work you are still responsible for when a tool is doing the typing. The dividing line is not difficulty, it is whether a wrong answer would be obvious to you on sight.
delegate keep
boilerplate you have written before what the thing is supposed to do
a regular expression you can test the boundary cases the test must cover
a data shape you can print whether the data shape is the right one
a first draft of a function the decision about where the seam goes
the docstring, from your code the name of the function
mechanical refactors with tests the refactor that changes an interface
the test bodies, once you named them which properties are worth asserting
the fiddly syntax you always forget the algorithm and its complexity
Keep anything where a plausible wrong answer costs more than
writing it yourself: concurrency, authentication, money,
deletion, and anything whose failure is silent.Say the split out loud as you work. Handing over a function while explaining that you will write the tests yourself, because you want the boundary conditions to come from your reading of the requirement rather than from the model's reading of your code, is a complete answer to the question the round is really asking.
Scope before you generate#
Spend the first few minutes on the problem rather than the tool. Ask clarifying questions, state your assumptions, and say what is out of scope. Interviewers are listening for this and most candidates skip straight to typing.
Say something like:
"Before I start, let me check a few things. Should this handle
concurrent updates? Is it acceptable to fail loudly on malformed
input, or should it skip and continue? I'll assume single-threaded
and fail loudly unless you'd rather otherwise."Plan, then execute#
Ask for a plan before asking for code, and push back on it. Revising a plan is where you demonstrate judgement, and it is visible in a way that reading code silently is not.
"That plan puts validation inside the loop. I want it at the
boundary instead, so there's one place to change it. Also drop
the caching for now, it's not in scope and it hides bugs."Delegate in pieces#
Ask for one bounded thing at a time. Small diffs are reviewable, and a wrong small diff is cheap to discard. A large generated change is either accepted unread or spends the rest of the round being untangled.
The practical size is whatever you can read in under a minute and check against a requirement you can state. If you find yourself scrolling, you asked for too much; say so, throw it away and ask again more narrowly. Discarding a generated diff in front of an interviewer is a positive signal rather than a lost two minutes, because it is evidence that you were reading it.
Verifying fast, worked#
This is the skill the round is built around, so here it is end to end on a function you will actually be asked for. The requirement: split a document into overlapping chunks for a retrieval index. What comes back looks like this, and it looks correct.
def chunk(text, size, overlap):
"""Split text into overlapping chunks of at most size characters."""
chunks = []
start = 0
while start + size <= len(text):
chunks.append(text[start:start + size])
start += size - overlap
return chunks
print(chunk("abcdefghij", 4, 1))
print(chunk("abcdefgh", 4, 1))
# ['abcd', 'defg', 'ghij']
# ['abcd', 'defg']Nobody catches that by reading. The loop condition is correct-looking, the slice is correct, the step is correct, and the example the model chose to demonstrate it with divides evenly. The way to catch it in under two minutes is not to read harder, it is to write down the property the caller depends on and check it over a range of inputs.
def loses_text(fn, text, size=4, overlap=1):
chunks = fn(text, size, overlap)
if not text:
return bool(chunks)
return not chunks or not text.startswith(chunks[0]) or not text.endswith(chunks[-1])
def sweep(fn):
alphabet = "abcdefghijklmnopqrstuvwxyz"
bad = [n for n in range(0, 40)
if loses_text(fn, "".join(alphabet[i % 26] for i in range(n)))]
return bad
bad = sweep(chunk)
print("input lengths that lose text: %d of 40" % len(bad))
print("smallest:", bad[:6])
print("what it does with 8 characters:", chunk("abcdefgh", 4, 1), "-- h is gone")
# input lengths that lose text: 27 of 40
# smallest: [1, 2, 3, 5, 6, 8]
# what it does with 8 characters: ['abcd', 'defg'] -- h is goneThe property is the interesting part, not the test. Asking what the caller relies on gives you one sentence, the document survives chunking start and end, and that sentence converts into four lines of code. It is faster than reading the implementation and it does not depend on you being alert, which matters at minute thirty-five of an interview.
def chunk_fixed(text, size, overlap):
if overlap >= size:
raise ValueError("overlap must be smaller than size")
if not text:
return []
step = size - overlap
chunks = [text[s:s + size] for s in range(0, len(text), step)]
while len(chunks) > 1 and chunks[-2].endswith(chunks[-1]):
chunks.pop() # the tail is already inside the previous chunk
return chunks
print("fixed, lengths that lose text: %d of 40" % len(sweep(chunk_fixed)))
print("8 characters:", chunk_fixed("abcdefgh", 4, 1))
print("3 characters:", chunk_fixed("abc", 4, 1))
try:
chunk_fixed("abcdef", 4, 4)
except ValueError as e:
print("overlap == size:", e)
# fixed, lengths that lose text: 0 of 40
# 8 characters: ['abcd', 'defg', 'gh']
# 3 characters: ['abc']
# overlap == size: overlap must be smaller than sizeNote what the whole exercise cost: about three minutes, and none of it was spent reading the generated code line by line. That is the answer to the round's central question, which is how you can be responsible for code you did not write. You are responsible for the properties, and the properties are checkable in less time than reading is.
Review like it came from a colleague#
- Read the diff itself, not the summary of it.
- Check it against the requirement, not against whether it looks reasonable.
- Look for the error cases. Generated code is usually strong on the happy path and thin on failure.
- Check the boundaries: empty input, one item, missing field, duplicate, and the input one element shorter than the window.
- Check what it did not do: a silently swallowed exception, a parameter accepted and ignored, a TODO left in a branch.
- Say out loud what you are checking. Silent reading looks identical to not reading.
Generated code has a characteristic shape of failure, and knowing it makes review much faster. It is fluent, idiomatic, and correct on the example it was implicitly written against. What it misses sits at the edges: the empty case, the case that does not divide evenly, the second call, the concurrent call, the error that should have been raised and was logged instead. Look there first and you will find most of what is there to find.
The code you cannot explain#
This is the specific failure the round exists to catch, and it does not feel like a failure while it is happening. You accepted something that worked, the tests passed, and you moved on. Then the interviewer picks a line.
24:10 INT Line 14 -- why the minus one?
24:14 YOU [scrolls back] So that's... it's computing the index
of the last complete window. I think it's because
the loop is exclusive at the end.
[hedges. "I think" on your own code is the tell]
24:30 INT Is it? What happens if the input is exactly one
window long?
24:35 YOU [silence] I'd have to trace through it.
-- the round is effectively over here, and not
because of the minus one. Two of the four things
being scored were "can defend the work" and "would
I merge this", and both just resolved to no.
WHAT TO DO INSTEAD, at the moment of accepting it
23:50 YOU I'll take this, but I don't like line 14. The minus
one is unexplained and I can't tell from reading it
whether it's an off-by-one guard or a deliberate
exclusion. Let me check with a one-window input
before I build on it.
[prints chunk("abcd", 4, 1) and reads the result]
Right -- it returns one chunk, so it's the exclusive
end. I'd still rather write that as a comment than
leave the next person to work it out.The rule underneath it is simple and worth stating in the room: nothing goes into the file that you could not defend if the tool vanished. Applied honestly it slows you down by a few seconds per acceptance, and it is the entire difference between a candidate who used a tool and a candidate who was used by one. If you cannot explain a line, either understand it now or replace it with something you would have written, and say which one you are doing and why.
Test without being asked#
Writing a test before the implementation gives you something objective to check the generated code against, and it demonstrates the habit without you having to claim it.
It also changes what you can safely delegate. Once the property is written down, handing over the implementation is cheap, because a wrong one fails immediately rather than three steps later. That is the practical reason to write the test first in this format, quite apart from what it signals: it is the thing that makes delegation safe enough to do quickly.
Narrate, or it did not happen
Everything in this rubric is invisible unless you say it. An interviewer cannot tell careful review from skimming, or deliberate scoping from hesitation. Thinking out loud is not a soft skill here, it is the entire assessment surface.
How to rehearse this#
- 1.Pick an unfamiliar problem and set a forty-five minute timer. Unfamiliar matters; a problem you have solved rehearses nothing.
- 2.Narrate continuously, out loud, including the parts that feel obvious. Record it.
- 3.Force yourself to state the property before accepting any generated function, and to run it.
- 4.At the end, close the tool and explain the whole solution from memory, out loud, as if to a colleague.
- 5.Watch the recording and mark two things: every silence over ten seconds, and every line you could not explain in step four.
- 6.Fix one of those in the next session. Only one.
The gap between what you shipped and what you can explain is the number this round produces, and it is the only one worth tracking across sessions. Four sessions is usually enough to close it, because the habit that closes it is small: a pause at each acceptance, and a sentence about what you just checked.
Where people go wrong
Working in silence. The round scores a process that is invisible unless narrated, so a candidate who did everything right quietly can score the same as one who did nothing right.
If this comes up in an interview
You are given a large task and an AI agent. What do you do first?
Clarify the requirements and state my assumptions. Then get a plan and revise it before any code is generated. Then work in small pieces I can review properly. Generating first and understanding later is how you end up with code you cannot defend.
How do you review generated code?
Read the diff rather than the summary, check it against the requirement rather than plausibility, and pay particular attention to error handling and boundary cases, which is where generated code is usually weakest. Then run tests.
The agent produces working code you do not fully understand. What now?
Stop and understand it, or replace it with something I do. Shipping code nobody on the team understands is a liability, and in an interview it guarantees failing the part where the tool is taken away.
Build this: Run four timed sessions on unfamiliar problems. Narrate scoping, revise the plan before executing, review every diff aloud, and write tests unprompted. Record yourself and watch where you went quiet.
This is one section of Working with coding agents, 7 hours across 2 sections. Read it in full to get the whole topic in order.
Stop 39 of 50 on the AI Engineer route
0 of 50 topics done · 0h behind you, 603h to go
What you have marked done is stored in this browser only. It does not reach a server, and clearing site data will clear it.