Art of Codeartofcode
LLeeaarrnniinngg
BBlloogg
TToooollss
GGaammeess AArreennaa
JJoobbss
LLiivvee CCoouurrsseess

Courses

  • System DesignHigh-level system design, one everyday scene at a time: 30 concepts and 15 interview rounds.712 lessons
All coursesTutorialsMy Learning

Categories

  • 01AI & Tools
  • 02Tutorials
  • 03Engineering
  • 04Reviews
  • 05Build Logs
  • 06Tales of Misfits
  • 07Opinion
  • 08Career
  • 09News

Read & write

All storiesEvery post, newest first.Write for usPublish your stories and earn from what you write.Writer leaderboardsWho is writing the most read posts.

Categories

  • PDF Tools25
  • Development09
  • Utilities10
  • Design04
  • Converters04
  • Generators02

Featured

JSON FormatterFormat, validate and minify JSON.Regex TesterTest patterns against live text.Merge PDFCombine PDFs in your browser.JWT DecoderRead a token’s header and claims.Password GeneratorStrong passwords, generated locally.Gradient GeneratorBuild CSS gradients visually.
All 53 tools

Play a round

DevdleOne developer word a day, six guesses.Python RushClassic snake, with coding icons to eat.Blink or BreakA quick test of your reflexes.
Games Arena

Learn with us

Live CoursesInstructor-led courses. Join a waitlist and be first in when one starts.LearningStructured programming courses with AI assistance and certificates.

System Design

2. Back-of-Envelope Estimation

Lesson 19 of 19

2. Back-of-Envelope Estimation

1
The picture to keep in your head
2
2.1 Why estimate at all?
3
2.2 Which units and sizes should you know?
4
2.3 What time shortcuts make the maths easy?
5
2.4 Which latency numbers should every developer know?
6
2.5 How do you turn daily users into requests per second?
7
2.6 Why does the read/write ratio matter?
8
2.7 Why size for the peak, not the average?
9
2.8 How do you estimate storage over the years?
10
2.9 How do you estimate bandwidth?
11
2.10 How much memory does the cache need?
12
2.11 How many servers do you need?
13
2.12 How do you round, and how do you know you're not way off?
14
Memory card and where the analogy breaks
15
Practice: five levels
16
Interview questions
17
Solutions
18
Sources
19
Code lab
2. Back-of-Envelope Estimation

Code lab

3 min read+10 XP

Code lab: Chapter 2

The full, tested code for this chapter. Press Run: every check should pass. Then change one number, run it again, and see which check breaks and why.

python

No tracks available

Lofi Player

artofcode

artofcode.in

The den of devs.

Stories, tools, games, and gear for developers.

Read the StoriesEExxpplloorree TToooollss
Art of Codeartofcode

Platform

  • BBlloogg
  • TToooollss
  • GGaammeess AArreennaa
  • CCoouurrsseess
  • LLeeaarrnniinngg
  • CCaammppuuss

Company

  • AAbboouutt UUss
  • JJoobbss && IInntteerrnnsshhiippss
  • CCoonnttaacctt

Legal

  • TTeerrmmss ooff SSeerrvviiccee
  • PPrriivvaaccyy PPoolliiccyy
  • RReeffuunndd PPoolliiccyy

Copyright © 2026 artofcode.in, All Rights Reserved.

IST·--:--

1"""Chapter 2 practice: a back-of-envelope estimator (Level 3 Build) and the
2bits-vs-bytes bug (Level 4 Debug). Run: python3 ch02_estimator.py"""
3
4SECONDS_PER_DAY = 86_400
5
6
7def human_bytes(n):
8    """1,460,000,000,000,000 -> '1.46 PB' (decimal units, as used in estimates)."""
9    for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB"]:
10        if abs(n) < 1000:
11            return f"{n:.3g} {unit}"
12        n /= 1000
13    return f"{n:.3g} ZB"
14
15
16def estimate(dau, reads_per_user, writes_per_user, write_size_bytes,
17             read_size_bytes, peak_factor=3, years=1, replicas=1, cache_fraction=0.2):
18    reads_per_day = dau * reads_per_user
19    writes_per_day = dau * writes_per_user
20    read_rps = reads_per_day / SECONDS_PER_DAY
21    write_rps = writes_per_day / SECONDS_PER_DAY
22    storage = writes_per_day * write_size_bytes * 365 * years * replicas
23    egress_bytes_per_s = reads_per_day * read_size_bytes / SECONDS_PER_DAY
24    return {
25        "read_rps": read_rps,
26        "write_rps": write_rps,
27        "peak_read_rps": read_rps * peak_factor,
28        "read_write_ratio": reads_per_day / writes_per_day if writes_per_day else float("inf"),
29        "storage_bytes": storage,
30        "egress_gbps": egress_bytes_per_s * 8 / 1e9,  # bytes -> bits, then giga
31        "cache_bytes": reads_per_day * read_size_bytes * cache_fraction,
32    }
33
34
35def servers_needed(peak_rps, rps_per_server, target_utilisation=0.6, spare=1):
36    """Servers to carry the peak at the target utilisation, plus spares for failures."""
37    import math
38    return math.ceil(peak_rps / (rps_per_server * target_utilisation)) + spare
39
40
41# ---- Level 4: the buggy version ------------------------------------------------
42
43def buggy_egress_gbps(reads_per_day, read_size_bytes):
44    bytes_per_s = reads_per_day * read_size_bytes / SECONDS_PER_DAY
45    return bytes_per_s / 1e9  # BUG: this is gigaBYTES per second, not gigaBITS
46
47
48def fixed_egress_gbps(reads_per_day, read_size_bytes):
49    bytes_per_s = reads_per_day * read_size_bytes / SECONDS_PER_DAY
50    return bytes_per_s * 8 / 1e9
51
52
53def close(a, b, tol=0.01):
54    return abs(a - b) <= tol * abs(b)
55
56
57def run_checks():
58    # The chapter's running example: a photo-sharing app.
59    # 10M daily users, 50 photo views each, 0.2 uploads each (2M uploads a day),
60    # 2 MB per uploaded photo, 200 KB per photo served.
61    e = estimate(dau=10_000_000, reads_per_user=50, writes_per_user=0.2,
62                 write_size_bytes=2_000_000, read_size_bytes=200_000)
63
64    assert close(e["read_rps"], 5787.04)            # about 5,800 reads a second
65    assert close(e["write_rps"], 23.15)             # about 23 uploads a second
66    assert close(e["peak_read_rps"], 17361.1)       # about 17,400 at 3x peak
67    assert close(e["read_write_ratio"], 250)
68    assert close(e["storage_bytes"], 1.46e15)       # 1.46 PB a year, one copy
69    assert close(e["egress_gbps"], 9.26)            # about 9.3 Gbps out
70    assert close(e["cache_bytes"], 2e13)            # 20% of a day's image bytes
71
72    with3 = estimate(10_000_000, 50, 0.2, 2_000_000, 200_000, replicas=3)
73    assert close(with3["storage_bytes"], 4.38e15)
74
75    assert human_bytes(1.46e15) == "1.46 PB"
76    assert human_bytes(4e12) == "4 TB"
77
78    # 17,400 peak reads, 1,000 per server, run at 60%, keep 1 spare.
79    assert servers_needed(17_361, 1_000) == 30
80
81    # Level 4: the bug is exactly a factor of 8.
82    bad = buggy_egress_gbps(500_000_000, 200_000)
83    good = fixed_egress_gbps(500_000_000, 200_000)
84    assert close(good / bad, 8)
85    assert close(good, 9.26)
86
87    print("All checks pass.")
88    print(f"Photo app: {e['read_rps']:,.0f} reads/s, {e['write_rps']:.0f} writes/s, "
89          f"peak {e['peak_read_rps']:,.0f}, storage {human_bytes(e['storage_bytes'])}/yr, "
90          f"egress {e['egress_gbps']:.2f} Gbps. Buggy egress: {bad:.2f} (8x too small).")
91
92
93if __name__ == "__main__":
94    run_checks()