Working with coding agents, section 2 of 2, 4h

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.
The right-hand column is what the interviewer is assessing. Delegating any of it reads as delegating the thinking, which is the one thing the round is designed to catch.

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."
Two sentences that show you read the plan and have opinions about structure.

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']
The first line is right. The second is missing the letter h, and the difference between those two inputs is two characters of length.

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 gone
Six lines, and they say that more than two thirds of document lengths silently lose their ending. Any document shorter than the chunk size produces no chunks at all, which is how a retrieval index ends up quietly missing every short page.

The 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 size
The guard on the first line is the other thing the original was missing: overlap equal to size makes the step zero, which is an infinite loop in the original and a clear error here.

Note 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 difference between the two transcripts is thirty seconds spent at the moment of accepting, not a different level of skill. The candidate who says 'I do not like line 14' out loud has already passed the part of the rubric the other one failed.

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. 1.Pick an unfamiliar problem and set a forty-five minute timer. Unfamiliar matters; a problem you have solved rehearses nothing.
  2. 2.Narrate continuously, out loud, including the parts that feel obvious. Record it.
  3. 3.Force yourself to state the property before accepting any generated function, and to run it.
  4. 4.At the end, close the tool and explain the whole solution from memory, out loud, as if to a colleague.
  5. 5.Watch the recording and mark two things: every silence over ten seconds, and every line you could not explain in step four.
  6. 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

Next on this routeLinux & the shellWhere the training runs and the servers live.10h

What you have marked done is stored in this browser only. It does not reach a server, and clearing site data will clear it.