Classic System Design Problems: Short Walkthroughs
12 common design questions with a concise approach: URL shortener, rate limiter, chat, news feed, notifications, and more.
1. Design a URL shortener like bit.ly.
Requirements: create a short link for a long URL, redirect quickly, optionally custom aliases and expiry, and read traffic far larger than write traffic. API: POST /urls with the long URL returning a short code, and GET /{code} returning a 301 or 302 redirect. Generate a unique code by base62-encoding a counter or ID from a distributed ID generator (a random code also works, with a collision check). Store code to URL in a key-value or relational store partitioned by code, and put a cache in front of reads, since popular links dominate. Use a 302 if you want to count clicks, and send click events to a queue for asynchronous analytics. Add rate limiting to prevent abuse.
2. Design a rate limiter.
Decide where it runs: in an API gateway or middleware, keyed by user id, API key, or IP. Use a token bucket per key, with its state (tokens and last refill time) kept in Redis so all servers share it, updated atomically with a Lua script or a transaction. Return HTTP 429 with Retry-After and rate limit headers when exceeded. Define rules (for example 100 requests a minute per user, with different limits per endpoint) in configuration. Discuss failure handling: if Redis is down, fail open or closed depending on the risk, and consider local approximate limits to reduce Redis traffic.
3. Design a chat application like WhatsApp.
Clients keep a persistent WebSocket connection to a chat server, so messages can be pushed in both directions. A connection layer keeps track of which server each user is connected to (a presence or session store). A sender's message goes to the server, which stores it (a write-optimized database partitioned by conversation id) and, if the recipient is online, forwards it through their server; otherwise it is queued and delivered later with a push notification. Use message ids and acknowledgments for delivery and read receipts, sequence numbers per conversation for ordering, and a media service with object storage for attachments. Group chats fan out to members, with limits on group size.
4. Design a news feed such as the Twitter or Facebook home timeline.
Two approaches: fan-out on write, where each new post is pushed into the precomputed feeds (cached lists) of followers, which makes reads very fast but is expensive for accounts with millions of followers; and fan-out on read, where the feed is assembled when the user opens it by merging recent posts from people they follow, which is cheaper to write but slower to read. A hybrid approach pushes for normal accounts and pulls for celebrity accounts at read time. Store posts durably, keep feeds in a cache such as Redis (a list of post ids), rank with a scoring service, and paginate with cursors.
5. Design a notification system.
Producers (services) publish notification events to a queue. A notification service looks up the user's preferences and channels (push, email, SMS, in-app), renders templates, deduplicates and rate-limits, then hands each message to a channel-specific worker that calls the provider (APNs, FCM, an email or SMS service). Use separate queues per channel and retries with backoff, store delivery status, and respect quiet hours and opt-outs. Make sending idempotent so retries do not produce duplicates.
6. Design a distributed ID generator (Snowflake style).
Create 64-bit IDs from a timestamp (about 41 bits of milliseconds since a custom epoch), a machine or datacenter id (about 10 bits), and a per-millisecond sequence (about 12 bits). IDs are unique without coordination, roughly sorted by time, and compact. Machine ids are assigned at startup through a coordinator such as ZooKeeper or configuration. Handle clock moving backwards by refusing to generate until time catches up, and design for clock synchronization with NTP.
7. Design a search autocomplete (typeahead) system.
Store popular queries in a trie, or a prefix-to-top-suggestions table, so lookup by prefix is fast. Each node keeps the top K completions by frequency or recency. Build the data offline from query logs on a schedule (and refresh trending terms more often), serve it from an in-memory store or cache, and put a cache or CDN in front for the most common prefixes. On the client, debounce keystrokes, and start suggesting after a couple of characters. Filter offensive or private suggestions.
8. Design a web crawler.
Start from seed URLs held in a URL frontier (a prioritized queue). Fetcher workers download pages, respecting robots.txt and per-host politeness delays. A parser extracts text and links, new links are normalized, checked against a seen-URL store (a Bloom filter or key-value store) to avoid repeats, and added to the frontier. Store content in blob storage and metadata in a database, deduplicate content with hashes, and distribute work by hashing the host so one worker handles each host. Handle traps (infinite pages), retries, and scale by adding workers.
9. Design a file storage and sync service such as Dropbox.
Split files into chunks (for example 4 MB), hash each chunk, and upload only new or changed chunks to object storage, which gives deduplication and efficient syncing. A metadata service stores the file tree, versions, and chunk lists in a relational database. A sync service notifies clients of changes (long polling or WebSockets) and clients reconcile differences, with conflict handling that keeps both versions. Add resumable uploads, encryption, sharing permissions, and a CDN for downloads.
10. Design a ride-hailing service such as Uber (matching riders to drivers).
Drivers send their location every few seconds to a location service, which stores it in a geospatial index (geohash, quadtree, or a Redis geo structure). When a rider requests a trip, a matching service queries nearby available drivers, ranks them (distance, ETA, rating), and offers the trip to the best driver, with timeouts and fallback to the next. A trip service manages the state machine (requested, matched, in progress, completed) and payments, communicating over events. Keep real-time updates on WebSockets, and shard the location data by region.
11. Design a video streaming service such as YouTube or Netflix.
Uploads go to object storage, then a pipeline transcodes each video into several resolutions and bitrates, split into short segments, producing adaptive streaming formats (HLS or DASH). Segments are pushed to a CDN so viewers stream from nearby edge servers, and the player switches quality based on bandwidth. Metadata, search, recommendations, comments, and view counts are separate services. Use asynchronous queues for processing and approximate counters for views.
12. How would you design a simple API for an e-commerce checkout, and what could go wrong?
Create an order with items and a payment method, reserve inventory, charge the payment provider, and confirm the order. Failure modes: double submission, payment succeeding while the order write fails, and stock oversold. Use idempotency keys on the create and payment calls, a state machine for the order, a transactional outbox or a saga with compensating actions (release stock, refund) across services, and reconcile with the payment provider's webhooks. Keep inventory reservation time-limited.
Interview Tips
- Use the same structure for every problem: requirements, estimation, API, data model, design, deep dive, trade-offs.
- Pick one or two components to go deep on and explain the trade-offs, instead of drawing every box.
- Practice out loud with a timer; a clear 35-minute walkthrough beats a perfect design you cannot explain.