Module 1 · Interview Method and the Request Path · Lesson 1 of 20
How to Run a System Design Interview as a .NET Developer
Learning outcome
You can run a 45-minute system design interview from the first question to the wrap-up without freezing or rambling. You know the six steps strong candidates follow, how much time each one gets, which questions to ask before drawing anything, and how to turn vague words such as "scalable" into numbers. You can also name the .NET building blocks (ASP.NET Core, EF Core, SQL Server or PostgreSQL, Redis, Azure Service Bus, BackgroundService, OpenTelemetry) that you would reach for, and explain why.
Intuition
A system design interview is not a quiz with one right architecture. It is a simulation of a design review. The interviewer wants to see how you turn a fuzzy business problem into a design that works, what you choose, what you give up, and how you would know it is failing in production.
Think of yourself as the tech lead in the room. A tech lead does not start by drawing Kafka. They ask what the system must do, how big it is, what "fast" and "reliable" mean in numbers, and only then sketch the simplest thing that meets those numbers. Then they find the weak spots and fix the ones that matter.
flowchart LR
R["1. Requirements (5 min)"] --> E["2. Estimates (5 min)"]
E --> A["3. API and data model (5-8 min)"]
A --> H["4. High-level design (10 min)"]
H --> D["5. Deep dives (10-15 min)"]
D --> W["6. Wrap-up: risks, trade-offs, next steps (3 min)"]Deep dive
Step 1: requirements
Split them into two lists and say them out loud.
- Functional: what users can do. "Customers place orders; customers see order history; the warehouse gets a pick list; customers get a confirmation email."
- Non-functional: the numbers and qualities. Scale (daily users, requests per second), latency targets (p99, not average), availability (99.9% is about 43 minutes of downtime a month; 99.99% is about 4.3 minutes), consistency needs, durability, security, compliance, cost.
Ask clarifying questions that change the design, not trivia:
| Question | Why it matters |
|---|---|
| How many users, and how spiky is traffic? | Decides caching, autoscaling and queueing |
| Read-heavy or write-heavy? | Decides replicas, caches and data store |
| Can a user see slightly stale data? | Decides consistency model and cache TTLs |
| What must never be lost or duplicated? | Decides idempotency, outbox and transactions |
| Single region or global? | Decides replication, CDN and data residency |
| Multi-tenant? | Decides isolation, partitioning and noisy-neighbour controls |
Write the answers in a corner of the whiteboard. You will point at them later when you justify a choice.
Step 2: estimates
Turn the requirements into a few numbers: average and peak QPS, read/write ratio, storage growth per year, bandwidth, and cache size. Round hard. The goal is the order of magnitude: is this 50 requests per second (one small app service) or 50,000 (a fleet behind a load balancer with aggressive caching)? Lesson 2 shows the method with a runnable calculator.
Step 3: API and data model
Sketch three to five endpoints and the main entities. This forces precision early:
POST /orders Idempotency-Key header -> 201 { orderId }
GET /orders/{id} -> 200 order with lines and status
GET /customers/{id}/orders?cursor=...&limit=20
POST /payments/webhook (from the payment provider)
Order(Id, CustomerId, Status, Total, CreatedAt, RowVersion)
OrderLine(OrderId, Sku, Quantity, UnitPrice)The access patterns you write here ("orders of one customer, newest first") decide your indexes and partition keys in Module 2.
Step 4: high-level design
Draw the request path and the data path. Start simple and grow it only when a requirement forces you to:
flowchart LR
C["Clients"] --> FD["CDN / Front Door"]
FD --> LB["Load balancer / API gateway (YARP)"]
LB --> API["ASP.NET Core Orders API (N instances)"]
API --> R[("Redis cache")]
API --> DB[("SQL Server / PostgreSQL")]
API --> Q[["Azure Service Bus"]]
Q --> W["Worker (BackgroundService)"]
W --> DB
W --> EM["Email provider"]
Say why each box exists. "The API is stateless so I can run N instances behind the load balancer. Orders go to a relational database because they need transactions. Email is sent from a worker through a queue, because the provider is slow and sometimes down and the customer should not wait for it."
Step 5: deep dives
The interviewer usually picks one or two areas, or asks you to. Good candidates choose the riskiest parts themselves: "The two things I would worry about are double-charging on retries and the database becoming the bottleneck at peak. Shall I start with idempotency?" Typical deep dives in this course: caching and invalidation (Lesson 8), sharding (Lesson 7), idempotency and the outbox (Lesson 11), retries and circuit breakers (Lesson 13), rate limiting and tenancy (Lesson 16).
Step 6: wrap-up
Finish with the risks you know about and what you would do next: "Single-region today; the next step is a warm standby. We should load-test the checkout path. The outbox relay is a single point of delay, so it needs an alert on queue age." This shows judgement, which is what senior interviews are scored on.
The .NET toolbox you should name
| Need | Typical .NET / Azure choice | Say this about it |
|---|---|---|
| HTTP API | ASP.NET Core minimal APIs or controllers on Kestrel | Stateless, scale out behind a load balancer |
| Reverse proxy / gateway | YARP, Azure Front Door, Application Gateway, API Management | Routing, TLS termination, rate limits at the edge |
| Relational data | SQL Server / Azure SQL or PostgreSQL with EF Core | Transactions, constraints, rowversion for optimistic concurrency |
| Document / key-value at scale | Azure Cosmos DB | Partition key design decides cost and scale |
| Cache | HybridCache (L1 in memory + L2 Redis), Azure Cache for Redis | Cache-aside, stampede protection, TTLs |
| Messaging | Azure Service Bus (queues, topics, sessions), RabbitMQ, Kafka / Event Hubs | Decouple, level load, at-least-once delivery |
| Background work | BackgroundService, Azure Functions, Hangfire/Quartz | Idempotent jobs, leases, retries |
| Resilience | Microsoft.Extensions.Http.Resilience (built on Polly v8) | Timeouts, retries with jitter, circuit breaker |
| Rate limiting | Microsoft.AspNetCore.RateLimiting middleware | Partition by authenticated identity |
| Observability | OpenTelemetry .NET, Azure Monitor / Application Insights | Traces, metrics, logs correlated by trace id |
Code example: turning a vague requirement into numbers
You will not run code in most system design interviews, but you should be able to write the numbers you are designing for. This is the requirements sheet a strong candidate writes in the first five minutes for "Design the order system for an online shop".
FUNCTIONAL F1 place an order (cart -> order, payment authorised) F2 order history, newest first F3 order status updates (paid, packed, shipped) F4 confirmation email NON-FUNCTIONAL (agreed with the interviewer) scale 10 M daily users, 2 M orders/day at sale peaks, peak = 3 x average latency p99 < 300 ms for GET, p99 < 800 ms for POST /orders (payment call included) availability 99.95% for checkout (about 22 minutes of downtime a month) consistency an order must never be lost or created twice; history may lag by a few seconds security customers see only their own orders; PCI data stays with the payment provider OUT OF SCOPE catalog search, recommendations, returns
What to notice:
- Every non-functional line is a number. "Fast" became p99 targets; "reliable" became 99.95% and "never lost or created twice".
- The consistency line already tells you the design. "Never created twice" means idempotency keys (Lesson 11). "History may lag" means you are allowed a read replica or cache (Lessons 6 and 8).
- Out of scope is explicit. It protects your time and shows you can prioritise.
Failure modes
- Drawing boxes before asking questions. You design for the wrong problem, and the interviewer marks "did not clarify requirements".
- Buzzword architecture. Kafka, Kubernetes and microservices for 50 requests per second. Say "a single ASP.NET Core service and one database is enough at this scale; here is when I would split it".
- Averages instead of percentiles. A 40 ms average can hide a 3-second p99. Always state p95 or p99.
- No numbers at all. Without estimates you cannot justify a cache, a replica or a shard.
- Silence during deep dives. Think aloud. Interviewers score reasoning, not the final picture.
- Ignoring failure. Every box can be slow or down. Say what happens when it is.
Interview angle
The opening is scored more than people think. A strong first two minutes sounds like: "Before I design anything, let me check the requirements. Who are the users, and roughly how many? Is it read-heavy? What happens if an order is duplicated, and how stale can the history page be? I will then do quick estimates, sketch the API, draw a simple design, and we can go deep on the riskiest part." That one paragraph shows structure, product sense and time management.
When the interviewer pushes ("What if traffic grows 10x?"), go back to your numbers: "At 10x the peak is about 100,000 reads per second. The API tier scales horizontally; the database does not, so I would add a cache in front of reads and move history reads to replicas. Writes are still only about 700 per second, which one primary handles."
Practice questions
- The interviewer says "Design a scalable notification service." What do you ask first?
Answer: Who sends and receives notifications, through which channels, how many per day and at peak, the latency target (seconds or minutes), whether duplicates or losses are acceptable, and whether users set preferences. Those answers decide queues, priority lanes and deduplication.
- Why give latency targets as p99 rather than an average?
Answer: Averages hide the slow tail that real users feel. With many backend calls per page, one slow call per hundred affects most page loads. p99 makes the tail a design target.
- How much downtime per month does 99.9% availability allow?
Answer: About 43 minutes (0.1% of roughly 43,800 minutes). 99.99% allows about 4.3 minutes.
- When is "one ASP.NET Core service and one database" the right answer?
Answer: When estimates show modest load (hundreds of requests per second), one team owns it, and there is no hard isolation need. Say what signal (team size, scaling hot spots, independent deploys) would make you split it later.
- What should a good wrap-up contain?
Answer: The main trade-offs you made, the known risks and single points of failure, how you would monitor the system, and the next steps you would take with more time.
Revision checklist
- Six steps: requirements, estimates, API and data model, high-level design, deep dives, wrap-up.
- Non-functional requirements are numbers: QPS, p99, availability, staleness, durability.
- Ask questions that change the design; write the answers down.
- Start simple; add components only when a number forces you to.
- Pick the riskiest areas for deep dives yourself; finish with risks and next steps.
Related on TechInterviewNotes
- Next lesson: Back-of-the-Envelope Estimation: QPS, Storage, Bandwidth and Latency
- Later in this course: Design Walkthrough: An Order Placement System on .NET
- After this course: .NET System Design Case Studies
Analogy
The architect and the client
A good architect does not start by drawing a skyscraper. They ask how many people will live in the building, what the budget is, whether there are earthquakes, and how many lifts people will tolerate waiting for. Then they draw the smallest building that meets those needs and point out where it can grow. A system design interview is that first client meeting, compressed into 45 minutes.
Quick reference
The 45-minute plan
- 0-5 min: functional and non-functional requirements, written as numbers.
- 5-10 min: QPS (average and peak), read/write ratio, storage per year, cache size.
- 10-18 min: 3-5 endpoints, main entities, access patterns.
- 18-28 min: high-level diagram; say why each box exists.
- 28-42 min: deep dives on the riskiest parts.
- 42-45 min: trade-offs, risks, monitoring, next steps.