In this article
Before you start
For where a coding exercise sits among the other rounds, see the interview process.
Why interviewers ask this
A design drawn on a whiteboard hides whether you can finish anything. A machine-coding exercise removes that gap: the code either runs or it does not, and the reviewer sees how you structure it under a clock or over a few evenings.
Candidates report a wide spread of briefs: a circuit breaker in a pair-programming session, a block editor with undo, a rate limiter inside an online assessment, a file-directory navigator that is later extended and refactored, a load balancer exposed as a representational state transfer (REST) service, a stock broker with first in, first out (FIFO) order matching, and a long home assignment followed by a review of it.1 The shape is always the same: a small domain, a working program, then a change.
A weak submission works for the sample input and breaks on the first new requirement. A strong one works, is tested, and shows where each likely change would go. A Staff-level one also says what it left out and why.
Machine-coding and low-level design take-homes from first principles
- Machine-coding round
- A machine-coding round is a timed or take-home exercise in which you build a small, runnable program from a written brief, with attention to behaviour, class design, tests and how easily the code absorbs a requirement that changes after the first version works.
- Seam
- A seam is a place in the code where behaviour can be swapped or extended, usually an interface or a function parameter, without editing the code that uses it, so a new requirement becomes a new class or setting instead of a rewrite.
In plain words
Imagine a workshop where a customer hands you a note: "build a toaster." You build it. Then the customer says: "now it must toast bagels." If you welded the slot shut around bread, you start again. If you made the slot width a setting, you turn a screw.
A machine-coding round is that note, followed by that change. The analogy breaks in one place: a reviewer can read your code, so the screw must be visible and named. In one precise sentence, you split the program so the part that is likely to change sits behind one interface and the rest never needs editing.
Low-level design (LLD) is the class-level design of one component: its classes, interfaces, methods and how they interact, as opposed to high-level design (HLD), which arranges services, data stores and traffic. A machine-coding round tests low-level design in running code.
Step 1: Clarify the brief and write the contract
Clarifying the brief means turning loose text into a short written contract of operations, inputs, outputs, errors and non-goals before any class exists. Input: the brief. Output: a list you can check the finished program against.
List the nouns (breaker, call, state) and the verbs (call, record failure, reset). Then decide the open questions. For a circuit breaker: what counts as a failure, is the state per process, and where does time come from? In a pair-programming round, ask the interviewer and say your assumption aloud. In a take-home, write the assumptions at the top of the README file. Name the non-goals too, such as persistence or a user interface, so nobody wonders whether you forgot them.
Check the brief for rules on tools and libraries first; the AI-assisted coding interview page covers rounds where assistants are allowed. You now have a contract; the next step decides its shape.
Step 2: Put the rule that will change behind one seam
Putting the changing rule behind one seam means choosing the single decision most likely to be altered and making it an interface, while everything else stays plain code. Input: your contract. Output: a small set of classes with one named extension point.
For a circuit breaker the rule that changes is when to trip. Fowler (2014) shows a failure count that resets on success, then notes a more sophisticated approach might trip on a failure rate, say 50%. A TripPolicy interface covers both. The clock is the second seam: pass a time source in instead of reading the system clock inside the class.
The same move works elsewhere. In a block editor, each edit becomes an object with apply and revert methods, so undo is a stack of those objects (the Command pattern). In a load balancer, the choice of backend becomes a Strategy. The reviewer's change request now has an obvious home. You now know where the extension goes; the next step makes the core run.
Step 3: Build the thin core and test it
Building the thin core means writing the smallest version that runs end to end and checking it with unit tests before adding anything else. Input: the classes of Step 2. Output: a tested program.
A fake clock is a small object whose time you advance by hand, so a test of a timeout never has to wait. Azure's pattern page describes three states: closed counts failures, open rejects calls at once, and half-open lets trial calls through. Successful trials close the breaker; a failed one reopens it.
Take illustrative settings, where each call is one tick of the fake clock: open after three failures in a row, wait four calls, close after two successful trials. Over 16 calls where the backend fails at call 2 and again from call 4 to call 13, the breaker passes 10 calls to the backend and rejects 6.2 Without it, the failing service would receive 11 failing calls, not 5.2
| Call | State during the call | What happens | State after |
|---|---|---|---|
| 6 | closed | third failure in a row reaches the backend | open |
| 7 to 9 | open | rejected without calling the backend | open |
| 10 | half-open | trial call fails | open |
| 11 to 13 | open | rejected without calling the backend | open |
| 14 | half-open | first trial succeeds | half-open |
| 15 | half-open | second trial succeeds | closed |
Half-open is the state in which only trial calls reach the service, so a recovering service is not flooded. On the timeline, the breaker opens after the sixth call and closes after the fifteenth.2
Text description of the diagram
- The breaker opens after the sixth call.
- It closes again after the fifteenth call.
Step 4: Extend, refactor, then write the notes
Extending means adding the second requirement in small steps while the tests stay green, then refactoring so the new code looks planned. Input: the working core and a change request. Output: the extended program, passing tests and a short README.
Add the change behind a new class where the seam allows it. If it does not fit, refactor first in one small move, run the tests, then add the feature. The refactor take-home page covers that skill on its own. In a timed round, get the core running first and leave the extras for last; in a multi-evening take-home the same order holds. Finish with the README: assumptions, what you built, what you left out, and what you would do next with more time.
When a review follows the exercise, expect questions on performance, tests and the design choices; the project deep dive page shows how to answer them. Order matters. Write the contract before any class. Put the rule that will change behind one interface. Get a tested core running end to end. Extend and refactor last, then write the notes.
Step-by-step description
- Write the contract before any class.
- Put the changing rule behind one interface.
- Get a tested core running end to end.
- Extend and refactor, then write the notes.
- Write the contract before any class.
- Put the rule that will change behind one interface.
- Get a tested core running end to end.
- Extend and refactor last, then write the notes.
Knowing it is half the job. Saying it is the other half.
Interview Clozo is an AI interview copilot for real interview rounds: it hears the question and puts a strong answer on your screen, and you say it in your own words. See the features or how it works.
Start Free Trial →The Staff-level answer
You have a pair-programming hour. Implement a circuit breaker. How do you start?
I spend the first few minutes on the contract: the breaker wraps one call, counts consecutive failures, opens at a threshold, rejects while open, and after a wait lets a trial call through. I ask what counts as a failure and whether state is per process. Then I write three small pieces: a state type, a trip policy I can swap, and a clock I can fake.
The breaker itself stays thin, and I make its state update atomic so concurrent callers see one state. I get closed-to-open working with one test, then add half-open and the timeout. At the end I say what I left out: a shared store for many pods, metrics, and a failure-rate policy. The store and the policy already have a seam; metrics would hang off a listener.
What makes it Staff-level: the answer names its omissions and shows where each one would plug in, instead of claiming completeness.
The rubric
| Dimension | Weak answer | Strong answer | Staff answer |
|---|---|---|---|
| Correctness | Works on the sample input only | Handles the main path and the main failure | Also covers repeated trial failure and atomic state updates |
| Design | One large class holds everything | Small classes with clear jobs | One named seam for the rule most likely to change |
| Tests | Manual run only | Unit tests for the main behaviour | Tests use a fake clock and cover each state change |
| Communication | Silent, then a code dump | States assumptions and narrates choices | Names trade-offs and what was left out |
| Follow-up readiness | A new requirement forces a rewrite | A new requirement needs a small edit | The change drops into the seam with no rewrite |
This table is advice about what a strong submission shows, not any company's scoring sheet.
Three variants of this question
What if the brief is a block editor with drag-and-drop and undo?
Model each block type behind one interface, keep the document as an ordered list, and make every edit an object with apply and revert so undo and redo are two stacks. Reordering by drag-and-drop is then one more edit object.
What if the take-home ends in a review of your own code?
Treat the README as your script for that review. Write the decisions and the omissions down while you remember them, and be ready to justify each seam.
What if the brief is a rate limiter with per-user and per-time limits?
Put the counting rule behind an interface and key the state by user. Inject the clock as in the breaker, so a time window can be tested without waiting.
Common mistakes
- "I will start coding classes now." (wrong) Without a contract you build the wrong thing quickly. (right) "First I will confirm inputs, outputs, errors and what is out of scope."
- "I used five design patterns." (wrong) Counting patterns says nothing about whether the code works or can change. (right) "I used one interface, where the rule is most likely to change."
- "The breaker reads the system time inside its methods." (wrong) A test of the timeout must then wait. (right) "Time is passed in, so a fake clock can advance it."
- "I will skip the tests and the
READMEto finish the feature." (wrong) The reviewer then cannot see how you reason. (right) "A small tested core and a shortREADMEcome before extras." - "I will rewrite it for the new requirement." (wrong) A rewrite throws away tested code. (right) "I refactor in small steps with the tests green, then add the feature."
Follow-up questions
Is a centralised store needed for a circuit breaker across many pods?
Not necessarily. Local state per pod is simple and adds no network dependency, but each pod learns about an outage separately. A shared store gives one view at the cost of an extra dependency on every call. Azure's guidance warns that many concurrent instances can use the same breaker and it must not block requests or add heavy overhead, so state the trade-off and keep the store behind a seam.
Is a circuit breaker the same as a retry or a rate limiter?
No. Azure's documentation says retry expects an operation to eventually succeed, while a circuit breaker stops an operation that is likely to fail; the two can be combined. A rate limiter is different again: it caps how often a caller may call, whether or not the service is healthy.
How do you test code that depends on time?
Pass the clock in as a parameter and use a fake clock in tests, so a wait of several calls or seconds takes no real time. Assert the state after each call, as in the trace above.
How is low-level design different from high-level (system) design?
Low-level design shapes the classes, interfaces and methods of one component, while high-level design arranges services, data stores and traffic between components. A system design interview is mostly high-level discussion; a machine-coding round asks for running low-level code with tests. Both reward stating assumptions and trade-offs.
What if the interviewer changes the requirement halfway?
Say what the change touches, check whether it fits a seam, and refactor one small step before adding it. The staff follow-up page covers how to handle that moment.
- A machine-coding take-home is a small program a reviewer runs and reads, so working code and tests come first.
- Write the contract, then put the rule most likely to change behind one interface.
- Inject the clock so time-based behaviour can be tested without waiting.
- Extend in small steps with the tests green, and refactor rather than rewrite.
- Close with a
READMEthat names what you left out and where it would plug in.
Sources
- Circuit Breaker — martinfowler.com (Martin Fowler), 6 Mar 2014
- Circuit Breaker pattern - Azure Architecture Center — Microsoft Learn, 26 Sep 2026