These independent assignments use synthetic data. Try them first, then check edge cases and open the hint. Time is an estimate; allow additional time for project tests and documentation.
Choose your practice · Interview mistakes
Scroll the table horizontally →
| Assignment | Stage | Estimate |
|---|---|---|
| Review an order from another restaurant | Web framework | 50 min |
| Two bookings for the last table | Web framework | 60 min |
| Recipes and ingredients in an ORM | Web framework | 45 min |
| A menu page grew to 61 queries | Web framework | 40 min |
| The kitchen received an order twice | Async and background jobs | 45 min |
| The image rebuilds while the API waits for the database | Production basics | 35 min |
| A cache must not expose another guest’s booking | HTTP and APIs | 35 min |
Review an order from another restaurant
Review the handler fragment, identify its problems and propose a correction. The restaurant comes from the URL; the server must calculate the amount from its catalog. Retrying after a timeout must not create another order. A dish can be missing or belong to another restaurant. Also explain publication failure after the database write.
@app.post("/restaurants/{restaurant_id}/orders")
async def place_order(restaurant_id: int, body: dict, user=Depends(current_user)):
dish = await db.fetchrow(
f"SELECT * FROM dishes WHERE id = {body['dish_id']}"
)
await db.execute(
"INSERT INTO orders(user_id, dish_id, amount) VALUES ($1, $2, $3)",
user.id, dish["id"], body["amount"]
)
await publish({"type": "order_created", "user_id": user.id})
return {"ok": True}
Check your result
- Address parameterized SQL, input validation and restaurant ownership separately.
- Do not trust client-supplied prices or totals.
- Explain local-write atomicity, request retries and event redelivery.
Hint — after your attempt
Inspect each trust boundary and each step that can fail independently.
Extension: Write an HTTP test for an authenticated user ordering a dish from another restaurant.
Two bookings for the last table
A restaurant has one free table in a slot. Implement a booking endpoint and batch import. Import is all-or-nothing. Two requests may execute concurrently. A slot’s “closed for booking” status is business state; a database row lock temporarily coordinates transactions. Do not confuse them. Define lock-wait policy, HTTP responses and behavior on retry with the same key.
Check your result
- Two concurrent clients create exactly one new booking.
- A mid-batch failure rolls back the entire batch.
- The same key returns the same result; a changed payload under that key is rejected.
Hint — after your attempt
Availability checking and seat allocation need one concurrency guarantee.
Extension: Compare a conditional UPDATE, a uniqueness constraint and a row lock using two transactions.
Recipes and ingredients in an ORM
Design SQLAlchemy models Dish, Ingredient and RecipeLine. Each recipe line links a dish to an ingredient and stores a positive gram quantity. An ingredient occurs at most once per dish. Ingredients have an allergen flag. Archiving a dish preserves its recipe; deletion of an ingredient still in use is forbidden. Load a menu and each dish’s allergens without a query per recipe line.
Check your result
- DDL includes foreign keys, pair uniqueness and a positive-quantity CHECK.
- Test creation, duplicate ingredients, archiving and forbidden deletion.
- Measure query count for a 30-dish menu.
Hint — after your attempt
The relationship has its own quantity; model it as an association entity.
Extension: Include dishes without ingredients and explain how JOIN affects those rows.
A menu page grew to 61 queries
Adding photos and allergens made a menu response run 61 SQL queries for 30 dishes. A separate latest-bookings endpoint slowed as its table grew. You have query counts and p95; a relationship between the issues is not established. Design a diagnostic plan and a minimal experiment for each. After fixing them, report query count, execution plan and p95 under the same load.
Check your result
- Do not treat an index as a universal fix for N+1.
- Separate query count, individual query cost and connection wait time.
- Record inputs, dataset size and success criteria.
Hint — after your attempt
First find the step that adds a query per dish.
Extension: Test the page without photos and without allergens separately.
The kitchen received an order twice
The order was saved in PostgreSQL, but event publication timed out. The client retried, the publisher retried, and the consumer crashed after creating a kitchen ticket but before acknowledging the message. Design order creation and event handling so retries cannot create another ticket. Distinguish request, order and event identifiers. Broker guarantees must not replace business-effect checks.
Check your result
- Describe the local order/event transaction, retrying delivery and consumer deduplication.
- Test crashes before and after ticket creation.
- Discuss per-order event ordering separately from deduplication.
Hint — after your attempt
Keep the effect and the processed-event marker consistent.
Extension: Handle a cancellation arriving before an older creation event.
The image rebuilds while the API waits for the database
Changing one application line reruns dependency installation in Docker. Separately, the API often waits for PostgreSQL connections after scaling out. Diagnose the issues separately: propose build-layer ordering and a connection budget. Each replica has a 20-connection pool; there are 6 replicas, and the application’s database budget is 80. Account for background workers and old/new replicas overlapping during rollout.
Check your result
- 120 potential connections exceed the budget even before workers and rollout overlap.
- A Python-only change reuses the dependency layer.
- Measure build time, pool wait time and database load.
Hint — after your attempt
Replica count multiplies each pool’s settings.
Extension: Test rollout at the maximum simultaneous replica count.
A cache must not expose another guest’s booking
A personal-bookings endpoint requires authentication. After enabling a shared HTTP cache, another guest saw someone else’s list. Define separate cache rules for the public menu and personal bookings. Use menu version as the public ETag basis and handle If-None-Match. For personal data, choose a safe contract first, then justify cache keys and permitted storage if caching is needed at all.
Check your result
- An unchanged menu returns bodyless 304 for a valid conditional request.
- Updating the menu changes its ETag.
- Test two users, anonymous requests and switching users.
Hint — after your attempt
Public and personal resources have different access boundaries.
Extension: Discuss caching errors and restrictions on personal URLs in logs.