Foundations
Debugging and work-simulation sections
These notes are original practice material. amazon-oa.com is not affiliated with or endorsed by Amazon. The examples were written for this page. They are not confidential assessment content, and they are not a forecast of what any interview will ask.
Some screens ask you to repair code that already exists, or to respond to a short workplace scenario. The skill is different from writing a function onto a blank page. You are being watched for how you read, how small a change you can justify, and whether you notice when the prompt is incomplete. This page practices that with original material. It does not describe a real employer's hidden section, and the format guide is the reminder that your invitation, not a blog post, says whether you will see this kind of task at all.
A loop for bugs you did not write
Use the same loop every time, including on take-home practice. Read the expected behavior in one sentence. Find the smallest input that disagrees with that sentence. Trace that input by hand until your trace and the code diverge. Change one thing. Re-run the smallest input, then a second input that used to pass, so the fix did not break the happy path.
Skipping the trace is the expensive move. Candidates edit the first line that looks ugly, the tests still fail, and the timer is gone. The time management reserve exists for this loop. If you spend the reserve thrashing, you did not have a hypothesis.
Here is an original bug to practice on. The function is supposed to return the average of the positive readings only. Empty input, or input with no positive reading, should return None. The implementation is wrong.
def average_positive(readings: list[int]) -> float | None:
total = 0
count = 0
for reading in readings:
if reading > 0:
total += reading
count += 1
if count == 0:
return None
return total / count
# The assertions below describe the intended behavior.
# The function above fails the second one. Do not "fix" the tests.
def average_positive_fixed(readings: list[int]) -> float | None:
total = 0
count = 0
for reading in readings:
if reading > 0:
total += reading
count += 1
if count == 0:
return None
return total / count
assert average_positive_fixed([2, -1, 4]) == 3
assert average_positive_fixed([0, -2]) is None
assert average_positive_fixed([]) is None
The bug is the indentation of count += 1, which is a real class of defect and not a puzzle with a trick. Every reading increments count, including zeros and negatives, so the average is diluted and the "no positive reading" case returns 0 instead of None, because count is not zero. The empty list happens to return None, which is why a single sample is not enough. The second assert is the one that catches it.
Say the hypothesis before you edit: "count is counting the wrong set." Then move one line. Then re-run all three asserts. If you also "clean up" the loop into something clever at the same time, you will not know which edit fixed the bug. One change is the discipline.
Notice what you should not do. Do not rewrite the function as a list comprehension until the tests pass. A comprehension can be the second version, once you understand the filter. Do not change the tests so the broken function looks correct. The tests are the spec in this exercise. In a real screen, the prompt is the spec, and silent tests may be stricter than the sample. Your own asserts are how you approximate those silent tests. The common mistakes page includes "only running the sample" because it pairs with this bug so cleanly.
Work samples that are not quite bugs
A work-simulation prompt might hand you a short description of a tool, a complaint from a teammate, and a question like "what do you do next?" There may be no compiler. The trap is inventing a product roadmap. The useful move is to restate the constraint you were given, name the smallest next action, and say what information you still need.
Suppose the prompt says a nightly job has started failing on Mondays, the logs are noisy, and a partner team is waiting on the output by 8 a.m. A strong answer picks a next action that could happen before 8 a.m.: compare Monday's input volume with Sunday's, look at the first error rather than the last, and tell the partner team whether the output will be late as soon as you know. A weak answer proposes a quarter-long rewrite of the job, because it sounds ambitious and it cannot be evaluated. Ambition without a sequence is not ownership. The Leadership Principles page is where you practice telling a story about a time you actually did the small next action. Do not perform a principle you cannot attach to a detail.
When the scenario includes numbers, use them. If it says the job processes about a million rows and now it processes ten million, your hypothesis should mention the tenfold jump. If it includes no numbers, do not invent a precise latency. You can say "I would measure the slow step before I optimize it." Inventing measurements is a fast way to lose the thread, because the interviewer, or the written rubric, can compare your fiction with the prompt.
Reading code out loud
Practice the trace on paper with a function you wrote last week. Pick an input of three elements. Write the value of each local variable after each line. This feels slow and childish, and it is the same trace you need when the function is someone else's and the timer is running. Ten minutes a day for a week beats an evening of rereading advice.
While you trace, mark the line where a variable starts meaning something different from its name. In the bug above, count stops meaning "positives" and starts meaning "all readings." That mismatch is a smell you can hunt in unfamiliar code: a name that made sense for the author's first draft and then survived a logic change. You will see it in real codebases constantly. You will see it in your own code twenty minutes after you write it.
If the editor lets you run tests, run the smallest failing case alone before the full suite. A suite of forty failures is hard to read. One failure with a three-element input is a trace you can finish. Add a print of the variables you wrote on paper if the environment allows it, and delete the print before you submit. Prints left in submitted code are a small signal that the loop did not get a last pass.
What the section is usually scoring
Nobody can honestly publish a universal rubric for a screen they have not seen. The behaviors that are worth practicing anyway are visible in ordinary engineering work. You can reproduce a failure. You can separate observation from guess. You can change one thing. You can tell a teammate what you know and what you do not. You can decline to rewrite a working path that the bug does not touch.
Those behaviors are also how you keep a later interview conversation concrete. "I would look at the logs" is weaker than "I would take the first Monday that failed, compare its input size with the previous Sunday, and see whether the first exception is a timeout or a bad row." The second sentence could be checked. The first sentence cannot. Written screens and spoken interviews both reward sentences that could be checked.
Practice drill
Take the broken average_positive and fix it under a five-minute timer, writing the hypothesis in a comment before the edit. Then introduce a new bug on purpose, such as using >= instead of >, and write the assert that catches it before you fix it. Then spend fifteen minutes on a scenario you write yourself: a dashboard that "looks wrong on Mondays." Answer in five sentences that contain a next action and an explicit unknown. If a sentence contains a number the prompt did not give you, delete the sentence.
Do not go looking for someone's real assessment bug to practice on. You do not need it. Any function with a slipped indent will do, and the habit transfers. The four-week plan schedules two of these sessions so they are not an afterthought the night before you might need them.