Capstone: Designing a System at Scale

Distributed Systems & Scalability

Chapter 10 · Capstone: Designing a System at Scale

One continuous worked project: a URL shortener, assembling every verified pattern from Chapters 1–9 into a single running system — sharded storage, a cache-aside redirect path, an async click-tracking queue, rate-limited creation, and a circuit breaker protecting the critical path from a broken analytics pipeline. Every number below comes from actually running the assembled system, not from restating each chapter's own earlier findings.

Assembling the System

class UrlShortener: def __init__(self): self.store = ShardedUrlStore(NUM_SHARDS) # Chapter 4 self.redirect_service = CacheAsideRedirectService(self.store) # Chapter 3 self.creation_limiter = TokenBucket(capacity=5, refill_rate_per_sec=1) # Chapter 7 self.click_queue = ClickEventQueue() # Chapter 6 self.click_counts = {} def create_short_url(self, long_url): if not self.creation_limiter.allow_request(): raise RuntimeError('Rate limit exceeded') code = hashlib.md5(long_url.encode()).hexdigest()[:6] self.store.save(code, long_url) return code def redirect(self, short_code): long_url = self.redirect_service.resolve(short_code) self.click_queue.publish(short_code) # fire-and-forget, never blocks the redirect return long_url

Running the System End to End

Verified directly — a short code is created and correctly stored in the right shard
create_short_url('https://example.com/a-very-long-article-url') returns short code 'c69915', and store.get('c69915') correctly returns the original long URL — the sharded lookup (Chapter 4's own hash-based routing) found the exact same shard it was written to.
Verified directly — cache-aside reduces 21 redirects to 1 real store lookup
Redirecting the same short code 21 times (1 initial + 20 repeats) leaves redirect_service.store_lookups at exactly 1 — every redirect after the first was served entirely from cache, matching Chapter 3's own verified cache-aside shape at a different scale.
Verified directly — click tracking never blocks a redirect, and still counts every click correctly
Immediately after those 21 redirects, click_queue.events correctly holds 21 pending events — none of them processed yet, because redirect() only ever calls publish(), never a handler directly. Processing the queue afterward correctly produces click_counts == {'c69915': 21} — every single click accounted for, on its own schedule, exactly matching Chapter 6's own decoupling finding.
Verified directly — rate limiting correctly throttles a burst of creation requests
8 rapid calls to create_short_url() against a token bucket with capacity 5: the first 5 succeed, the remaining 3 correctly raise RuntimeError('Rate limit exceeded')['created', 'created', 'created', 'created', 'created', 'rate-limited', 'rate-limited', 'rate-limited'], matching Chapter 7's own token-bucket burst-then-throttle shape exactly.
Verified directly — redirects keep working even when the entire analytics pipeline is broken
Wrapping click processing in a circuit breaker (threshold 2) and feeding it a handler that always raises ConnectionError: processing 10 queued clicks produces ['failed-full-cost', 'failed-full-cost', 'failed-fast', 'failed-fast', ...] — the circuit opens after 2 real failures, exactly matching Chapter 9's own verified breaker behavior. Meanwhile, calling redirect() 10 more times during this same broken-analytics period: every single one succeeds correctly, and redirect_service.store_lookups stays at 1 — completely untouched. The core redirect functionality never even knows the analytics pipeline exists.

The Rest of the System, Reasoned About Rather Than Re-Verified

Three more chapters shape this same system's real deployment, without needing fresh code to demonstrate here — each one's own mechanism was already verified in its own chapter, applied directly:

ChapterHow it applies to this exact system
Chapter 2 — Load BalancingMultiple UrlShortener instances behind Least Connections, exactly as verified — redirect traffic vastly outweighs creation traffic in a real URL shortener, so read-heavy load balancing matters most here
Chapter 5 — CAP TheoremShort-code creation should be CP: two clients racing to create a code for the same long URL must never produce two different codes for it, the identical risk Chapter 5 verified for AP-style writes. Redirects, by contrast, can safely be AP — a slightly stale cache entry (Chapter 3) is a tolerable cost for availability, not a hash collision risk
Chapter 8 — API Gateway & Service DiscoveryA gateway would front create_short_url() and redirect() as separate routes, using discovery to find whichever shard/replica currently holds a given short code — exactly the registry pattern Chapter 8 verified surviving a redeploy

What This Course Doesn't Cover

This course stayed at the level of verifiable, single-process simulations of each pattern's own core mechanism — it did not cover actually deploying multiple real processes or machines, configuring a real load balancer or message broker, or the operational work of running any of this in production. Software Architecture Fundamentals Chapter 10's own scope note named this course as the next step after getting a system's own shape right; this course, in turn, hands off to actually operating one — Technical Support's own perfdiag1/incident1/netdiag1 courses cover diagnosing a system like this one once it's live and something goes wrong.

Hands-On Exercises

Exercise 1

Create two more short URLs through this chapter's own UrlShortener, then redirect all three short codes a mixed number of times (e.g., 5, 3, and 10 redirects respectively). Verify store_lookups is exactly 3 (one genuine miss per distinct code), not 1 and not 18.

📄 View solution
Exercise 2

Using this chapter's own rate-limited create_short_url(), wait long enough for the token bucket to refill 2 tokens (at 1/sec, this chapter's own configured rate), then attempt 2 more creations. Verify both succeed, confirming the limiter recovers correctly rather than staying permanently exhausted.

📄 View solution
Exercise 3

Using this chapter's own verified resilience finding, explain specifically WHY redirect()'s own code never needed a try/except around anything analytics-related, when Chapter 9's own graceful-degradation example needed an explicit try/except around a failing dependency. What's structurally different about how this capstone wired click tracking?

📄 View solution

Chapter 10 Quick Reference — and Course Quick Reference

  • This capstone: a URL shortener assembling Chapters 3, 4, 6, 7, and 9 into one running system — verified: 1 real store lookup across 21 redirects, 21 click events fully decoupled and correctly counted, 5 of 8 rapid creations allowed, and redirects proven immune to a fully broken, circuit-breaker-wrapped analytics pipeline
  • Course arc: Ch.1 (why systems need to scale, measured) → Ch.2 (load balancing) → Ch.3 (caching) → Ch.4 (database scaling) → Ch.5 (CAP theorem) → Ch.6 (message queues) → Ch.7 (rate limiting) → Ch.8 (API gateways & discovery) → Ch.9 (resilience patterns) → Ch.10 (assembling it all)
  • Where this leads: Technical Support's own diagnostic courses (perfdiag1, incident1, netdiag1) — this course builds the system; those courses diagnose it once it's live