Restaurant Management

Tables, orders, kitchen stations and the bill

Design the system behind a sit-down restaurant: seat a party, take an order, send each item to the right kitchen station, tell the server when the food is ready, and produce a bill that can be split.

Overview

A restaurant is a small factory with a dining room attached. Guests arrive and need a table. A server takes an order; each line on it goes to a different part of the kitchen, the burger to the grill, the fries to the fryer, the drinks to the bar. Cooks finish items at different times, someone has to notice when a whole order is ready, and at the end the guests want one bill, or three.

The interview version asks you to model that flow with a handful of classes and to get four things right. A table must move through its life in order: free, occupied, being cleaned, free again. An item must go to the station that makes it, and must stop being cancelable once a cook has started on it. Money must be in whole cents and a split bill must add up to the total, to the cent. And the host stand must not seat two parties at one table when two hosts click at the same moment.

A strong answer draws the two life cycles first (a table's and an item's), shows that routing is a lookup on the menu item rather than an if-else, and puts money in integer cents with a rule for the leftover penny. The code below does all of that.

Scoping the problem

Before drawing anything, ask these questions, because each answer adds or removes a class.

  • Walk-ins only, or reservations too? — Reservations add a time window to a table's state — Walk-ins; reservations are a follow-up
  • Can an order change after it is sent to the kitchen? — Decides whether items have a status of their own — Yes, until a cook starts the item
  • One kitchen, or stations? — Stations mean routing and per-station queues — Stations, one queue each
  • Who is told when food is ready? — A server needs a notification per item or per order — Both: item listeners, plus an all-ready check per order
  • How is the bill split? — Even, by item, custom — A strategy; even split in the code, by item in a question
  • Tax and tip? — Rates vary by place and must not be hard-coded — Tax rate is a constructor parameter in basis points; tip is a number
  • Many terminals at once? — The seating step and the station queues need locks — Yes

From seating to payment

One visit touches every class once. Routing happens inside place_order: for each line, the menu item's station field names the station, and the item goes into that station's queue.

Two life cycles

A table and an order item each have a short life, and both are enforced in code rather than by convention. Table.move_to checks a table of allowed moves and raises on anything else. An item's status decides what may still happen to it.

  • FREE — OCCUPIED (seat) — CLEANING
  • OCCUPIED — CLEANING (close_table) — FREE, OCCUPIED again
  • CLEANING — FREE (table_cleaned) — OCCUPIED

Routing by data, not by code

Each menu item carries the name of the station that makes it. place_order does self.stations[item.menu_item.station], so adding a dessert station means adding a station object and tagging the menu items; no method changes. Each station keeps a first-in, first-out queue of (order, item) pairs and a cook pulls from the front. A canceled item can still be sitting in a queue, so start_next skips anything that is no longer PENDING.

  • Burger x2, no onion — 1200 each — grill — burger
  • Fries — 400 — fryer — fries, then skipped when canceled
  • Soda x3 — 300 each — bar — soda

Money in cents, and the leftover penny

Prices, tax and tips are integers in cents. The tax rate is in basis points (hundredths of a percent) so 8.75 percent is the integer 875 and the tax is round(subtotal * 875 / 10000). Python's round sends an exact half to the even neighbor (so 0.5 becomes 0), which is fine here because 288.75 is not a tie; if the local rule is round half up, compute (subtotal * rate_bp + 5000) // 10000 with integers instead. When a bill is split evenly and the total does not divide, the leftover cents go one each to the first guests, so the shares always add up to the total. The code asserts that after every split.

  • Burger x2 — 2400 — 2 x 1200
  • Fries, canceled before cooking — 0 — canceled items cost nothing
  • Soda x3 — 900 — 3 x 300
  • Subtotal — 3300 — sum of item costs
  • Tax at 8.75 percent — 289 — round(3300 x 875 / 10000) = round(288.75)
  • Tip — 500 — given by the guests
  • Total — 4089 — 3300 + 289 + 500
  • Even split, 3 guests — 1363, 1363, 1363 — 4089 = 3 x 1363
  • Even split, 2 guests — 2045, 2044 — 4089 = 2 x 2044 + 1; the first guest takes the penny

Two locks, two jobs

Seating is the race that matters: two hosts, two terminals, one free table for four. seat finds the smallest free table that fits and marks it occupied inside one with self._seating_lock block, so the second host sees the table already taken. Each station has its own lock around its queue and around the one status change that races: a cancel and a cook's start_next both check PENDING and then write, so both run under the station's lock and exactly one of them wins. The seating lock also covers creating a table's order, so two servers ordering for one table at once share one order.

Python's Lock is not reentrant, which is why move_to does not take the seating lock itself; it is called from seat, which already holds it. The demo runs ten hosts against three tables for two and asserts each table is handed out once.

  • Restaurant._seating_lock — which table is free, and each table's current order — hosts and servers at several terminals
  • KitchenStation._lock — one station's queue, and the move of its items out of PENDING — servers adding and canceling, one or more cooks pulling

What you will be able to do

  • Draw the table and item life cycles and say which moves are refused and why.
  • Show that routing is a lookup on the menu item and that a new station is data plus one object.
  • Keep money in integer cents, compute tax from a rate in basis points, and split a bill so the shares always sum to the total.
  • Put one lock around seating and one around each station's queue, and name the race each one closes.
  • Answer the follow-ups: order changes after sending, split by item, reservations, and what must survive a crash.

Functional requirements

  • seat(party_size) gives the party the smallest free table with enough seats, or None
  • place_order(table, lines) creates or extends the table's order and sends each item to the station named on its menu item
  • cancel_item(item) is allowed only while the item is PENDING; a cooking or ready item cannot be canceled
  • A station pulls the next pending item with start_next and reports it with mark_ready; ready listeners are called
  • order.all_ready() tells the expo when every live item of an order is ready or served
  • bill(table, tip) computes subtotal, tax at the configured rate and total in cents; canceled items cost nothing
  • bill.split(strategy) returns per-guest shares that sum exactly to the total
  • close_table moves the table to CLEANING and table_cleaned moves it back to FREE; illegal moves raise

Non-functional requirements

  • No table is seated twice: seating is atomic under one lock
  • Station queues are safe with several servers adding and cooks pulling at once
  • Money is integer cents; the tax rate is a parameter, never a literal in the code
  • New stations, menu items and split rules are added as data or one class, with no change to place_order or Bill
  • Every state change of a table or item is checked against an allowed-moves rule

Interview questions

  • How does an item reach the right station, and how does the server know the whole order is ready?
  • A guest changes their mind after the order is sent. What can still change?
  • How do you split a bill by item instead of evenly, and keep the cents right?
  • Two hosts on two terminals seat parties at the same time. How do you keep them from taking the same table?
  • How would you add reservations?
  • What has to survive a crash, and what can be rebuilt?

Sign up free to read the full topic

More Low-Level Design topics

Start free on Cariara · Coding problems · System design studio