Heavy Lifting + Your Rehearsal
Design a video platform
Upload a video, press play somewhere else, it just works. Behind that sentence sit two of the most instructive systems you will ever draw: a queue-driven factory that turns one raw file into dozens of streamable ones, and a delivery network that serves petabytes a day without touching your servers. Design both, and you have designed the hard half of the modern internet.
Say it in the first minute of the interview: a video platform is two flows. The upload flow — a creator pushes a raw file, the system ingests it and transcodes it into every resolution it will ever be watched at. The playback flow — a viewer presses play, and small chunks of video stream to their device at whatever quality their connection can hold right now. The flows share storage and almost nothing else; they scale independently and fail independently. Numbers for the envelope: 500 hours uploaded per minute, a 10:1 watch-to-upload ratio, and one finished video becoming 6–10 output files.
A raw hour of 4K footage can be 50 GB. You do not POST that in one request. The client splits the file into chunks — say 8 MB each — and uploads them to object storage, tracking which chunk numbers succeeded. A dropped connection resumes the chunk, not the file: retry chunk 4,217, not 50 GB. When the last chunk lands, a completion event fires and the object store now holds one immutable original. This is also your durability story — object storage replicates across machines for you, so the raw master survives disk failures without you writing that code.
The completion event drops a message on a queue, and workers chew through a DAG: split the original into segments → transcode each segment to 1080p, 720p, 480p, 360p in parallel, each in its codec → merge the results and write the manifests. Why a DAG and not a script? Parallelism where work is independent — every segment-resolution pair is its own task on its own worker — and ordering where it is dependent — merge cannot start until every transcode for that resolution finished. Why a queue and not a synchronous call? Transcoding takes minutes to hours; the uploader must not wait, workers must be retryable when they die mid-segment, and the queue absorbs the 8 PM upload spike instead of your CPU budget.
The player never downloads "a video". It fetches a manifest — a small text file listing every resolution as a sequence of 2–6 second chunks — then downloads chunk by chunk, measuring throughput on each one. Bandwidth drops? The next chunk is requested at 480p. It recovers? Back to 1080p, mid-video, mid-scene. The adaptation logic lives entirely in the client; the servers are dumb chunk vending machines. That is the whole trick of adaptive bitrate streaming: put the intelligence where the measurement is.
Popular video obeys a brutal power law: a small fraction of content takes the overwhelming majority of watch time. That fraction lives at the CDN edge, in points of presence close to the viewer. A warm edge serves the chunk without ever calling you — your origin sees only two things: cache misses for cold or brand-new content, and the original uploads from your transcode pipeline. So size the origin for misses, not for total traffic; a system designed to serve every play from origin would need a hundred times the egress and would still be slower, because physics charges you for distance.
Object storage costs cents per gigabyte-month — a library of ten million videos is an accounting footnote. Bandwidth costs dollars per gigabyte delivered, and it scales with success: every viewer-hour pays the meter again. This is why the CDN is not an optimization, it is the business model. And the metadata — title, owner, duration, per-resolution chunk manifests — lives in a relational, strongly-consistent store: it is tiny next to the blobs, it is queried relationally (videos by owner, by recency), and it is the one thing you cannot afford to lose or serve stale.
A video platform is two systems sharing a storage bill: an asynchronous factory that converts uploads into streamable artifacts at its own pace, and a read-mostly delivery network that serves those artifacts from the edge. Once you see the split, every decision sorts itself — queues, retries, and DAGs on the factory side; caching, placement, and bandwidth economics on the delivery side.
A creator's upload dies at 92% on hotel Wi-Fi. What exactly is retried, and why is the transcode pipeline not blocked either way? (Only the failed chunks resume — chunk-level tracking in object storage means the 92% is banked; and the pipeline is never blocked because the queue decouples upload from transcoding — the DAG starts when the completion event fires, on the platform's schedule, not the creator's connection.)
Draw it in two boxes and you are already ahead of most whiteboard answers: chunked resumable upload into object storage, a queue-fed transcoding DAG, a manifest-driven adaptive player, and a CDN that turns your origin into a miss-handler. Storage is cheap, bandwidth is the bill, and the metadata — small, relational, precious — is the only part that needs a real database.
Take a large file your system moves today — a CSV import, a report, a backup — and make its transfer chunked and resumable: fixed-size parts, a record of completed part numbers, resume from the first missing part. Then write down, in one sentence each, which of your current synchronous jobs would become a queue-fed DAG if they grew a hundred times.
Heavy Lifting + Your Rehearsal