Previously, in Part 6, you handled the data round. Now for the interview that scares junior developers the most: system design. Here's the secret — at your level, nobody expects you to design Netflix. They expect you to think out loud, in a sensible order, about a system of honest size. And if you've read this site's system design series, you have already designed the exact system we're about to be asked for.

"Design an appointment booking system for a clinic chain."

Why they ask it: Not to see boxes and arrows — to see your order of operations. Do you clarify before you build? Do you start from the data or from buzzwords? Can you grow a simple design when they add pressure? A booking system is perfect for this: small enough to sketch in 45 minutes, rich enough to hide real problems like double-booking.

A strong answer: is a staged conversation, not a diagram dump. Walk through it in four stages, narrating as you go.

Stage 1: Clarify before you draw

This is the step juniors skip, and it's worth more than everything that follows. Ask questions before proposing anything: How many clinics and doctors? Do patients book online, or do staff book for them? Can appointments be canceled or rescheduled? Do we send reminders? Roughly how many bookings a day? The answers shape everything — a 10-clinic chain with a few thousand bookings a day needs a very different amount of machinery than a national platform. This is exactly the skill we practiced in gathering requirements from a real conversation: requirements come from dialogue, not assumption.

Stage 2: Entities and relationships

Now the data model — and here you're on home turf, because we built this database step by step in the design series: Patient, Doctor, Clinic, Appointment, and Availability. An Appointment connects a patient, a doctor, a clinic, and a time slot; Availability records which doctor works at which clinic on which days. Say the relationships out loud: a doctor works at many clinics and a clinic hosts many doctors, so that's a many-to-many resolved through a junction table — precisely the pattern from our post on foreign keys and junction tables. Starting from the data model signals maturity: the entities are the part of the design that will outlive every framework choice.

Stage 3: The API surface

Keep this quick, because you covered the principles in Part 5: an ASP.NET Core Web API with resource-shaped endpoints — GET /api/v1/doctors/7/availability?date=2026-08-10 to find open slots, POST /api/v1/appointments to book (201 on success, 409 if the slot just vanished), and a state-change endpoint for cancellations. One sentence on auth — JWTs, with patients and staff in different roles — and move on.

Stage 4: The scale layer

Only now, with the shape settled, talk about load — and tie each tool to a reason:

  • Caching, for availability lookups. Browsing free slots is by far the hottest read path, and it's the same answer for everyone looking at the same doctor and day. Cache it (in-memory, or Redis once you have multiple servers) with a short TTL, and invalidate on booking. Name what you cache and where — vague "add caching" earns nothing.
  • A queue, for notifications. Confirmation emails and SMS reminders shouldn't hold up the booking response — the patient doesn't need to wait for an email provider. Drop a message on a queue and let a background worker send, with retries for free. That's the case for async in one breath.
  • Read replicas, in one line: if reads swamp the primary database, route reports and availability browsing to replicas and keep writes on the primary.
  • Idempotency, for double-clicks. The follow-up that impresses: if a nervous patient double-clicks "Book," the client sends the same idempotency key with both requests, and the server returns the original result instead of creating a duplicate appointment.

Try it: Set a 20-minute timer and run this whole interview against a blank sheet of paper, out loud, no notes — clarify, entities, API, scale. Talking to an empty room feels silly and works wonders. You already own the ER diagram from the design series; now practice narrating it.

Follow-ups to expect:

  • "Two users grab the last slot at the same time — what happens?" — Answered in full below.
  • "How would you add a waiting list?" — Also below; they're testing design evolution.
  • "What breaks first as you grow 10x?" — Probably the availability reads; point back at your cache and replicas.

Red flag: Opening with "I'd use microservices and Kubernetes" before asking a single question. Reaching for maximum architecture on a clinic booking app tells the interviewer you design by fashion, not by requirement.

"Two users grab the last slot at the same time — what happens?"

Why they ask it: Every booking design gets this follow-up. It checks whether you know that an if-check in C# cannot protect you from a race between two requests.

A strong answer: The real answer lives in the database. Checking "is the slot free?" and then inserting is two steps, and both users can pass the check before either inserts. So you make the database the last line of defense: a unique constraint on the slot, so the second insert fails no matter how the requests interleave.

modelBuilder.Entity<Appointment>()
    .HasIndex(a => new { a.DoctorId, a.ClinicId, a.StartTime })
    .IsUnique();

The application catches that violation and returns a friendly 409: "That slot was just taken — here are the next three." Mention optimistic concurrency (a version column checked at save time) as the general pattern for updates, and you've covered both halves.

Red flag: "I'd check if the slot is free before inserting." That is the race condition. If your only defense is application code, two requests a millisecond apart will both win.

"How would you add a waiting list?"

Why they ask it: This tests whether your design can evolve under pressure — interviewers love changing the requirements mid-interview to see if the structure bends or shatters.

A strong answer: Extend, don't rebuild. Add a WaitingListEntry entity — patient, doctor, clinic, desired date, position, created-at — and hook it into a flow you already have: when a cancellation lands, publish an event to the notification queue from Stage 4, notify the first person in line, and give them a short window to claim the slot before offering it to the next. The pleasant surprise you can say out loud: "my queue from earlier already does most of the work." That's the sound of a design that was built to grow.

Red flag: Redesigning the whole system to accommodate one new feature. If a waiting list forces you to start over, the interviewer learns the first design was more fragile than it looked.

Tip: Narrate your trade-offs — "I'd cache availability with a short TTL, accepting we might briefly show a stale slot, because the unique constraint catches it at booking time." Interviewers grade the reasoning, not the boxes. A modest design defended with clear trade-offs beats an impressive diagram the candidate can't explain.

Next up: the human round

Technique, data, design — all covered. What's left is the round that decides more offers than candidates realize: the behavioral interview, the questions you ask them, and the money conversation. In Part 8, the series finale, we close strong.