How you are graded, and extending live

Part of the free Low-Level Design course on LogicWiz, in the chapter: The machine-coding round. The class-diagram exercises run in the app.

Week 11: Now add one more thing

"Your code works. Now riders in the rain should be chosen by rating, not distance. You have 15 minutes."

Priya, at minute 70 of the mock


The rubric, line by line

Interviewers grade from a written rubric (a list of what they score). Companies word it differently, but most rubrics cover the same things:

  • Working code. Does it compile and run? Does the main flow give the right output?
  • Clear classes. Does each class have one job? Are models, services and storage separate?
  • Extensibility. When a new requirement arrives, how much existing code must change?
  • Naming and readability. Can the interviewer guess what assignRider does without reading it?
  • Edge cases and errors. What happens with an unknown order, or no free rider?
  • Thread safety, where shared state exists. Did you notice it and say so?
  • Communication. Did you explain your choices while you worked?

Levels are graded differently. For an SDE-1 role, the interviewer mostly wants working code with clean classes and sensible names. For SDE-2 and above, they also expect you to spot the extension points before being asked. They expect you to raise thread safety yourself, and to explain trade-offs, such as why you chose a lock over a version check.

Arjun had expected one big score for "used design patterns". There is no such line. A pattern earns marks only when it makes one of the lines above better. Three patterns forced into a small problem make readability worse.

Show it works: a main and a few checks

The interviewer will run your main. Some will also ask for tests. If JUnit is set up, use it. If not, a few check methods inside the program are enough:

static void check(boolean condition, String name) {
    if (!condition) {
        throw new AssertionError("FAILED: " + name);
    }
    System.out.println("PASSED: " + name);
}

static void noFreeRiderGivesClearError() {
    DispatchService dispatch = new DispatchService(new InMemoryRiderRepository(),
        new InMemoryOrderRepository(), new NearestRiderStrategy());
    Order order = dispatch.placeOrder("C1", List.of("eggs"));
    try {
        dispatch.assignRider(order.id());
        check(false, "assign with no riders should fail");
    } catch (IllegalStateException e) {
        check(true, "assign with no riders fails clearly");
    }
}

Test the rules, not the getters. Good targets are a slot that is full, a rider who is already busy, and an order id that does not exist. Because the service takes its repositories through the constructor, a test can build a fresh one in one line.

"Now add X": extending live

Around minute 70, most interviewers add a requirement. This is the extensibility line of the rubric, tested live. Here is Arjun's first try at the rain rule:

Rider rider;
if (weather.isRaining()) {
    rider = pickTopRated(freeRiders);
} else {
    rider = pickNearest(order, freeRiders);
}

It works. But the next request ("new riders get short orders first") adds another branch to the same method. That method now changes for every new rule. You saw this pain in Week 4 as a break of the open/closed principle.

Use these steps instead:

  1. Restate the requirement in one sentence, and ask one question if needed.
  2. Find the seam. A seam is the place in the design where behaviour varies. Here it is "how we choose a rider".
  3. Add a class, not a branch. Put each rule behind an interface.
  4. Run the demo again, so the old flow still works.
public interface RiderSelectionStrategy {
    Optional<Rider> pick(Order order, List<Rider> freeRiders);
}

public class NearestRiderStrategy implements RiderSelectionStrategy {
    public Optional<Rider> pick(Order order, List<Rider> freeRiders) {
        return freeRiders.stream()
            .min(Comparator.comparingDouble(r -> r.distanceTo(order.address())));
    }
}

public class TopRatedRiderStrategy implements RiderSelectionStrategy {
    public Optional<Rider> pick(Order order, List<Rider> freeRiders) {
        return freeRiders.stream().max(Comparator.comparingDouble(Rider::rating));
    }
}

This is the strategy pattern from Week 7. DispatchService receives a strategy in its constructor and calls pick. Who chooses which strategy? One small piece of code that reads the weather. The service itself does not change for the next rule.

Not every "add X" needs a new interface. If the request is "also store the rider's phone number", add a field. Save the seams for behaviour that varies.

Try it on the board. Pull the rider choice out of DispatchService into a strategy with two implementations.

💡 Tip: Before you code the extension, tell the interviewer which files will change and which will not. That sentence alone shows you understand your own design.

Ways candidates lose marks

These come up again and again in feedback:

  • Nothing runs at the end. Usually caused by building everything before running anything.
  • Everything in Main. One file with all the logic gives the interviewer no classes to grade.
  • Public fields and setters everywhere. Any class can break any rule.
  • if chains on a type string, such as if (type.equals("CARD")), repeated in many methods.
  • Swallowed errors. An empty catch block hides bugs. Throw a clear exception instead.
  • Patterns for show. A factory with one product, or a singleton nobody needed.
  • Silence. The interviewer cannot give marks for reasons you did not say.
  • No time left for the extension, because the first 70 minutes had no plan.

⚠️ Warning: Do not rewrite working code during the extension. Change the smallest part, run the demo, and only then tidy.

📌 Summary: Rubrics grade working code, clear classes, extensibility, names, errors and communication. Test the rules. For "now add X", find the seam, add a class, and rerun the demo.

What Arjun learns next

This is the last lesson of the course. Arjun now has the whole path: from requirements to classes, the principles, the patterns, the diagrams, thread safety and the 90-minute plan.

What he needs now is practice on real interview problems. That is the job of the problem library. It has worked LLD problems such as a parking lot and Splitwise. Each one starts with the interviewer's prompt. You design it yourself first, in the class designer, and the goals check your diagram. Only then do you open the model answer. It shows the clarifying questions, the class diagram, the key Java code, the deep dives and the "now add X" extensions.

For your own practice, use the free LLD Designer page. Draw any class diagram, see the same design checks as in these lessons, and export a Java skeleton or Mermaid text. Arjun's plan: one problem a day, designed before he looks.

Check your understanding

  1. At minute 70 the interviewer says "new riders should get short orders first". Arjun already has an `if` on the weather inside `assignRider`. What is the strongest response?
  2. Which of these is most likely to lose marks in a machine-coding round?
  3. Arjun asks Priya which tests to write in the last 10 minutes. What should he test first?
  4. The interviewer adds "also store each rider's phone number". Arjun starts adding a `PhoneNumberStrategy` interface. What would Priya say?