Chapter 2: Gathering Requirements — Functional vs Non-Functional
The first step in any system design is understanding WHAT you're building. Skip this and you'll design the wrong system. Every design starts with requirements gathering.
Functional Requirements (FR)
What the system DOES. The features, the behavior, the user-facing capabilities.
// Example: Design a URL shortener
Functional Requirements:
1. Given a long URL, generate a short URL
2. Given a short URL, redirect to the original long URL
3. Users can optionally set custom short URLs
4. URLs expire after a configurable time (optional)
5. Analytics: track click count per URL
Non-Functional Requirements (NFR)
How well the system performs. The quality attributes that constrain the design.
| Category | Question | Example |
|---|---|---|
| Scale | How many users/requests? | 100M URLs created/month, 10B redirects/month |
| Latency | How fast must it respond? | Redirect in < 50ms (p99) |
| Availability | How much downtime is acceptable? | 99.99% uptime (< 52 min/year) |
| Durability | Can we lose data? | Never lose a URL mapping once created |
| Consistency | Can reads be stale? | New URL must work within 1 second of creation |
| Security | Auth? Encryption? Abuse? | Rate limit creation, block malicious URLs |
| Cost | Budget constraints? | Run on < $10K/month infrastructure |
The Questions to Always Ask
💡 Requirements Checklist
- Users: How many? Where geographically? Growth rate?
- Traffic: Reads vs writes ratio? Peak vs average? Burst patterns?
- Data: How much? How long to keep? What format?
- Latency: What's acceptable? p50? p99?
- Availability: What's the SLA? Can we have maintenance windows?
- Consistency: Must reads always be fresh? Or is eventual OK?
- Existing constraints: Tech stack? Cloud provider? Team expertise?
Read-Heavy vs Write-Heavy
URL Shortener:
Writes: 100M/month = ~40 writes/sec
Reads: 10B/month = ~4000 reads/sec
Ratio: 100:1 read-heavy
→ Optimize for reads (caching, read replicas)
Chat System:
Writes: Every message is a write
Reads: Users read messages once (mostly)
Ratio: ~1:1 balanced, but write-heavy at peak
→ Optimize for writes (append-only, async)
Telemetry/Monitoring:
Writes: Thousands of metrics/sec from every server
Reads: Occasional dashboard queries
Ratio: 1000:1 write-heavy
→ Optimize for writes (LSM-tree, time-series DB)
Deriving Numbers from Requirements
// URL Shortener example:
// 100M new URLs/month
// → 100M / (30 days × 24h × 3600s) ≈ 40 URLs/sec (write QPS)
// Read:Write = 100:1 → 4000 reads/sec (read QPS)
//
// Storage: each URL mapping ≈ 500 bytes
// → 100M × 500B = 50GB/month new data
// → 5 years retention = 3TB total
//
// Bandwidth: 4000 reads/sec × 500B = 2MB/sec (trivial)
Example: Telecom System Requirements
// Design: AMF Session Management
// Functional:
// - Handle UE Registration (create context)
// - Handle Service Request (retrieve/update context)
// - Handle Deregistration (delete context)
// - Handle N2 handover (move context between AMFs)
//
// Non-Functional:
// - 1M concurrent UE contexts
// - Registration latency < 200ms (p99)
// - 99.999% availability (5 nines = 5 min downtime/year)
// - Stateless compute (context in external store)
// - Survive single node failure with no data loss
// - Geographic redundancy (multi-site)
Key Takeaways
- Always start with requirements — functional (what) and non-functional (how well)
- Quantify everything: QPS, storage, latency, availability in numbers
- Identify read/write ratio — it drives your architecture choices
- Requirements determine trade-offs: you can't have everything
- Ask clarifying questions before designing — ambiguity leads to wrong designs