$npx -y skills add proyecto26/system-design-skills --skill back-of-the-envelopeThis skill should be used when the user needs to "estimate QPS", "back-of-the-envelope" (BOTEC) numbers, "how much storage / bandwidth", "how many servers", "peak load", "capacity planning", or wants the standard latency / throughput / availability numbers to ground a design (lat
| 1 | # Back-of-the-Envelope Estimation (BOTEC) |
| 2 | |
| 3 | Turn vague scale ("high traffic", "huge data") into a few concrete numbers that |
| 4 | *decide the design*. BOTECs are quick, approximate calculations — feasibility |
| 5 | checks, not precision. The point is the process and directional correctness: |
| 6 | they tell you when a single database won't do, when caching is forced, when a |
| 7 | write spike needs a queue. |
| 8 | |
| 9 | > A design for 1k QPS and one for 1M QPS are different systems. 10 GB fits in |
| 10 | > RAM; 10 TB needs distributed storage. Estimate first, choose second. |
| 11 | |
| 12 | ## When to reach for this |
| 13 | At step 2 of any design (right after requirements), and any time a choice depends |
| 14 | on scale: sizing the read vs write path, deciding sharding vs a single node, |
| 15 | justifying a cache, or sanity-checking a proposed component against load. |
| 16 | |
| 17 | ## When NOT to |
| 18 | Don't chase precision or model every microservice — that's the opposite of the |
| 19 | technique. Don't estimate what won't change a decision (YAGNI). Round |
| 20 | aggressively: "99,987 / 9.1" is "100,000 / 10". Always **label units** and |
| 21 | **write assumptions down**. |
| 22 | |
| 23 | ## Clarify first |
| 24 | Estimates are only as good as their inputs. Pin down: |
| 25 | - **DAU/MAU** and what fraction is active daily. |
| 26 | - **Actions per user per day** (posts, reads, messages…). |
| 27 | - **Read:write ratio** — which path dominates. |
| 28 | - **Object sizes** — per record and per media blob. |
| 29 | - **Retention** — how long data is kept (drives total storage). |
| 30 | - **Peak factor** — peak is typically ~2× average; spikier for some workloads. |
| 31 | |
| 32 | ## The core estimations (recipes) |
| 33 | Work each as a single multiply/divide chain. Full worked numbers and the CPU-time |
| 34 | derivation are in `references/estimation-recipes.md`. |
| 35 | |
| 36 | - **QPS** = `DAU × actions_per_user_per_day ÷ 86,400`. **Peak QPS ≈ 2 × QPS** |
| 37 | (state your peak factor). |
| 38 | - **Storage/day** = `writes_per_day × avg_object_size`. **Total** = |
| 39 | `storage/day × retention_days` (watch base-10 vs base-2; storage is sold base-10). |
| 40 | - **Bandwidth** = `QPS × payload_size` (separate read and write; egress usually |
| 41 | dominates and costs money). |
| 42 | - **Number of servers** = `peak_QPS ÷ per_server_QPS`. Use the per-server rates |
| 43 | below as the divisor. |
| 44 | - **Concurrent connections / memory** = `concurrent_users × per_connection_cost`; |
| 45 | check the working set fits RAM (else it's an IO-bound, disk-backed design). |
| 46 | |
| 47 | ## Numbers that matter |
| 48 | These are the reference points to *know*, so you can estimate without lookups. |
| 49 | Full tables (latency, server specs, request types, powers of two, nines) live in |
| 50 | `references/numbers-to-remember.md` — load it when you need a specific figure. |
| 51 | |
| 52 | The two that drive most decisions: |
| 53 | |
| 54 | | What | Rule of thumb | |
| 55 | |---|---| |
| 56 | | Single SQL/RDBMS node | ~**1,000** QPS | |
| 57 | | Key-value store node | ~**10,000** QPS | |
| 58 | | Cache server (Redis/Memcached) | ~**100,000–1M** QPS | |
| 59 | | One modern CPU core | ~**1,000** simple requests/s → a 64-core box ≈ **64k** req/s | |
| 60 | | Read 1 MB: memory vs SSD vs disk | ~**μs vs tens–hundreds of μs vs ms** (memory ≫ SSD ≫ disk) | |
| 61 | |
| 62 | **Think in orders of magnitude, not exact values.** CPU-bound work is ~1×, |
| 63 | memory-bound ~10×, IO-bound ~100× the time. That ratio, not the decimals, is what |
| 64 | shifts an architecture. |
| 65 | |
| 66 | ## Dos and don'ts |
| 67 | Distilled from the recipes and the ways estimates mislead. |
| 68 | |
| 69 | **Do** |
| 70 | - **Do round to one significant figure** and reason in orders of magnitude — the |
| 71 | ratio (1× / 10× / 100×) is what shifts an architecture, not the decimals. |
| 72 | - **Do size on peak, not average.** State the peak multiplier (≈2× is a common |
| 73 | default; spikier for bursty workloads) before picking capacity. |
| 74 | - **Do estimate reads and writes separately** — a 95% read ratio and a write |
| 75 | spike pull the design in opposite directions. |
| 76 | - **Do label units and write assumptions down**, so a "GB" isn't ambiguous and |
| 77 | the chain can be re-checked when an input changes. |
| 78 | |
| 79 | **Don't** |
| 80 | - **Don't carry false precision.** Decimals imply a confidence the inputs don't |
| 81 | support; "99,987" is "100,000". |
| 82 | - **Don't trust per-server rates as universal.** "1k QPS for SQL" is a |
| 83 | point-query rule of thumb; range scans, joins, and fat payloads can be 10× |
| 84 | worse — use it for the order of magnitude, then validate with real benchmarks. |
| 85 | - **Don't conflate base-2 and base-10.** RAM is base-2; storage/network marketing |
| 86 | is base-10 — close enough for an estimate, but only if the units are stated. |
| 87 | - **Don't compute what won't change the decision.** If a number doesn't move the |
| 88 | architecture, skip it (YAGNI). |
| 89 | |
| 90 | ## Diagram |
| 91 | Estimation is us |