Module 13 · Lesson 01

What the low-level design round actually tests

It is not a pattern quiz. It is a maintenance test with a time limit.

Intermediate 9 min read Updated 2026-11-03

What you will be able to do

  • Explain what a machine-coding round scores beyond correctness
  • Turn a requirement paragraph into entities, invariants and methods
  • Spend the round's time in a defensible order
  • Recognise pattern dumping as a failure mode, not a strength

The round is a maintenance test

The interviewer is not buying a design. They are buying the next six months of working in it. So the questions behind every observation are the same: if I asked you to add a new payment provider on Thursday, how much of this file would I have to read? If a stock reservation raced with another checkout, where would the bug live? If I gave this to a mid-level developer, could they change behaviour without changing structure?

That framing matters because it changes what you optimise for. A clever generic solution that needs a paragraph to explain scores lower than three boring classes with obvious names and a test each. Commerce systems are especially unforgiving here: money, stock and order state have invariants that no amount of pattern vocabulary can rescue once the model lets two contradictory states exist.

Say the sentence the interviewer is waiting for
Early in the round, say out loud: I will keep the money and stock rules inside the domain objects so no caller can violate them. It tells them your design has a spine before you have written the first class.

What is actually scored

  • Requirements used, not listed. You asked about partial refunds, then modelled them. A requirements list that never appears in the design is a red flag.
  • Entities with behaviour. Order.cancel() that refuses to cancel a shipped order, rather than a service that checks three flags from outside.
  • Invariants made unrepresentable. No setter that allows a negative quantity; no public constructor for an order without a customer.
  • Extensibility at the seams you named. If you claim new payment providers will be easy, there must be one interface with two implementations, not an if-chain.
  • Working code and at least one test. Compiles, runs, demonstrates the happy path and one rejection.
  • Names. reserveStock says more about a design than a class diagram does.

The five moves

Clarify for five minutes, no more
Write down the three questions whose answers change the model: is stock reserved before or after payment, can an order be partially cancelled, is the price locked at cart or at checkout. Ask them, write the answers on the board, move on.
List entities and their verbs
From the requirements, extract nouns (Cart, LineItem, Money, Reservation, Payment) and the verbs the system must perform on them. Nouns become classes; verbs become methods on the noun that owns the invariant.
Write the invariants as sentences
A cart cannot hold two lines for the same SKU and variant. A paid order cannot return to draft. A total must equal the sum of line totals minus discounts, in integer paise. Each sentence is a future test and a future guard.
Code the spine, then one use case end to end
Money, LineItem, Cart, Checkout as a thin orchestrator. Get add-to-cart and checkout running before adding a second payment method or a discount engine.
Prove two behaviours, then discuss extension
One test that the happy path totals correctly, one that a checkout with insufficient stock fails without side effects. Then say where the next feature plugs in, and stop.

How the ninety minutes usually go

SliceMinutesOutput
Clarify and scope0-8Three answered questions, a one-line scope, entities on the board
Model and invariants8-20Class list, relationships, six invariant sentences
Code the spine20-50Money, line items, cart, checkout service that runs
Second behaviour50-70Discount or second payment provider behind the same interface
Tests and walkthrough70-85Two passing tests, one failure path demonstrated
Extension conversation85-90Where observability, persistence and concurrency plug in
Pattern dumping is the most common self-inflicted wound
A Factory, a Builder, a Strategy, an Observer and a Singleton in a 200-line answer do not read as expertise. They read as a design that has not decided anything. Every pattern you add should be traceable to a sentence in the requirements. If it is not, delete it and say why.

What the spine looks like

This is deliberately unglamorous. Money is a value object so arithmetic cannot silently lose paise; a line computes its own total; the cart refuses duplicate SKUs; checkout is a service because it coordinates objects that should not know about each other.

record Money(long paise, Currency currency) {
    Money plus(Money other) { requireSameCurrency(other); return new Money(paise + other.paise, currency); }
    Money times(int qty) { return new Money(Math.multiplyExact(paise, qty), currency); }
}

final class LineItem {
    private final Sku sku;          // sku + variant, not a String
    private final Money unitPrice;   // locked when added
    private int quantity;            // only changes through methods

    Money total() { return unitPrice.times(quantity); }
}

final class Cart {
    private final Map<Sku, LineItem> lines = new LinkedHashMap<>();

    void add(Sku sku, int qty, Money unitPrice) {
        if (qty <= 0) throw new IllegalArgumentException("quantity must be positive");
        lines.merge(sku, new LineItem(sku, unitPrice, qty),
            (existing, added) -> existing.withQuantity(existing.quantity() + qty));
    }
}
Instead
double price and String sku on every field.
Do this
Money (integer minor units + currency) and a Sku type, so units cannot be mixed and paise cannot be lost.
Instead
An anaemic model: getters, setters, and every rule in a service.
Do this
Entities own their invariants; the service only coordinates the order of operations.
Instead
Setting up repositories and a database before the domain exists.
Do this
An in-memory domain first, persistence named as a seam at the end of the round.
Instead
Tests only on the happy path.
Do this
One test that totals correctly and one that a checkout without stock fails with no side effects.
Instead
Manager, Helper, Processor, Util.
Do this
Name the responsibility: Pricing, Inventory, Checkout, Reservation.

The sentence that closes the round

When time is called, do not apologise for what is missing. Summarise the design in three sentences: the invariants you enforced, the seam you left for extension, and the concurrency risk you would handle next. That summary is often the part the interviewer remembers, because it is the part that sounds like a colleague rather than a candidate.

Worth remembering

  • The round measures whether your code can survive a second developer changing it, not whether you know the names of the design patterns.
  • Entities and invariants come first. Classes follow from the verbs in the requirements, not from a catalogue.
  • Sixty percent of the marks are in the first twenty minutes: what you clarify, what you name, and what you make impossible to represent.
  • A small working system with three tests beats a large sketched one with none, every time.

Checkpoint

Answer all 3 questions to finish the lesson.
1. You have forty minutes left and a working cart but no discount support. What is the strongest next move?
A named seam plus one test proves extensibility without consuming the round. A rule engine is a rewrite; a field on the line has no seam at all; extra cart tests do not answer the question that was asked.
2. Which design most reliably prevents overselling in a machine-coding round?
The invariant belongs to the thing that owns the stock. A check-then-decrement service is a race with extra steps, and a flag cannot represent partially reserved quantity.
3. An interviewer asks why you did not add a Singleton for the checkout service. The best answer is:
The honest reason is that instantiation policy is a framework concern here, and a hand-written Singleton would hide a dependency rather than simplify anything. Flat rejections of patterns read as dogma.