System Design for Beginners: What I Wish I Knew
The mental models that make distributed systems click
Why system design matters
Most junior developers spend years building features without thinking about what happens when a service has 10,000 concurrent users instead of 10. System design is the practice of thinking at that scale.
The core mental model: trade-offs
Every architecture decision is a trade-off. There are no objectively correct answers — only answers that are correct given your constraints.
Common trade-offs:
- Consistency vs. Availability (CAP theorem)
- Latency vs. Throughput
- Storage cost vs. Computation cost
- Complexity vs. Scalability
Start with the basics
Load balancing
A single server has a ceiling. When you hit it, you have two options:
- Vertical scaling — a bigger machine, which has limits and is expensive
- Horizontal scaling — more machines, which requires a load balancer
Request → [Load Balancer] → [Server 1]
→ [Server 2]
→ [Server 3]
Round-robin is the simplest strategy. Least-connections is better when requests have variable processing time.
Databases
Most apps start with a single relational database. That's fine. Know when to consider alternatives:
- Read replicas — scale read-heavy workloads without the complexity of sharding
- Database sharding — partition data horizontally; complex, but necessary at huge scale
- NoSQL — when data is genuinely document-oriented or extreme write throughput is required
Caching layers
We covered Redis in a previous post. The broader pattern:
Request → Cache hit? → Yes → Return cached data
→ No → DB query → Cache result → Return data
CDNs are a cache for static assets and increasingly for API responses too.
The components every system uses
- DNS — translates domain names to IP addresses
- Load balancer — distributes traffic across servers
- Web servers — handle HTTP and should be stateless
- Application servers — contain business logic and should be stateless if possible
- Cache (Redis or Memcached) — fast in-memory storage
- Database — persistent storage
- Message queue (RabbitMQ or Kafka) — asynchronous service communication
- Object storage (S3) — large files and blobs
- CDN — globally distributed static asset delivery
A worked example: designing a URL shortener
This is a classic system design question. Let's think through it.
Requirements:
- Shorten URLs (for example, ariankoochak.com → ak.io/x7z)
- Redirect to the original URL on visit
- Handle 10M new URLs per day and 1B redirects per day
Key insight: Writes are 10M per day (about 115 per second). Reads are 1B per day (about 11,500 per second). This is a 100:1 read-heavy system.
Design:
- Generate a 7-character Base62 ID for each URL
- Store the mapping in a primary database
- Cache aggressively because most redirects repeatedly hit popular links
- Use a CDN for the redirect logic itself if latency is critical
Resources I'd recommend
- Designing Data-Intensive Applications by Martin Kleppmann — the best book on the subject
- ByteByteGo newsletter — visual system design breakdowns
- High Scalability blog — real-world architecture postmortems
System design rewards curiosity and patient study more than memorization. Start with the trade-offs, and the patterns will follow.