</> MAANG.io
system design · 301

Advanced

Master system design interviews with scalable architecture patterns, distributed systems, and real-world design challenges.

0/480 solved 0% complete

Section 4: Three Audiences, Three Contracts - API Design (with Pushback)

Executive Summary: A feature flag platform has three very different callers: product teams changing flags a few thousand times a day, server code asking "is this on?" 50 million times a second, and browsers and phones that must never see the rules. This section designs one contract per caller: management REST with optimistic concurrency and a dedicated kill endpoint, an in-process SDK that never throws and never blocks, a version-addressed stream protocol, and a client evaluation endpoint that returns values instead of rules. Four rounds of pushback test the choices that matter most.

The interviewer uncaps the marker: "Walk me through the APIs." The trap here is drawing one API. Section 3 showed that the read path and the write path differ by roughly nine orders of magnitude, so you say out loud that there are three audiences, and each one gets its own contract.

Surface Caller Volume Latency budget
Management REST Product teams, rollout controller, on-call 5,000 changes/day p99 ≤ 500 ms
Server SDK + stream 100,000 service instances 50M evals/s, all local p99 ≤ 50 µs per eval
Client evaluation Web and mobile apps ~35,000 fetches/s at peak p99 ≤ 50 ms at the edge

The Management API: Where Humans Change Things

Creating smart-reply-v2 is a small, ordinary resource:

POST /v1/flags
{ "key": "smart-reply-v2", "type": "BOOLEAN",
  "variations": [false, true], "defaultVariation": false,
  "owner": "fabrikam-mail-compose", "tags": ["mail", "ai"] }

type is one of BOOLEAN | STRING | NUMBER | JSON, so the same machinery carries multivariate values later. Targeting lives per environment, and every edit is a conditional write:

PUT /v1/flags/smart-reply-v2/environments/prod/rules
If-Match: "v41"
{ "rules": [ { "segment": "seg-no-preview", "serve": false },
             { "segment": "seg-ring0-fabrikam", "serve": true } ],
  "rollout": { "bucketBy": "userId", "percent": 25 } }
-> 200 OK  ETag: "v42"     or     412 Precondition Failed

Interviewer: "Why the If-Match? It's a config tool, not a bank."

You: "Because two people editing the same flag is normal on deploy days, and those days peak around 50 changes a minute. Without a precondition, whoever saves last silently erases the other person's rule. With it, the second writer gets a 412, re-reads version 42, and merges on purpose. Every save creates an immutable version, so the ETag is just that flag version number. The environment also gets a new snapshot version, 8813, which is what the fleet tracks. Section 5 builds the tables behind both."

Rollouts are a resource of their own, so nobody has to babysit percentages:

POST /v1/flags/smart-reply-v2/rollouts
{ "steps": [ { "segment": "ring-0-fabrikam", "bakeMinutes": 1440 },
             { "percent": 1 }, { "percent": 5 }, { "percent": 25 },
             { "percent": 50, "approval": true }, { "percent": 100, "approval": true } ],
  "minBakeMinutes": 60,
  "gates": { "errorRatePp": 0.5, "p99Ratio": 1.5, "sustainMinutes": 5 } }

The plan states intent: Ring 0 for 24 hours, then 1% → 5% → 25% → 50% → 100%, at least an hour of bake per step, human approval past 25%, and treatment-vs-control gates. The rollout controller in Section 9 executes it. Two endpoints complete the surface: POST /v1/flags/{key}:kill with :unkill, and GET /v1/flags/{key}/usage, which serves the per-minute rollups behind stale-flag cleanup.

Quick check before moving on:

Sign in to continue reading

The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.

Sign in to read the full lesson

Sign in to MAANG.io

Use your Google or Microsoft account — no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.