All posts

System Design for Beginners: What I Wish I Knew

The mental models that make distributed systems click

System Design for Beginners: What I Wish I Knew article cover

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:

  1. Vertical scaling — a bigger machine, which has limits and is expensive
  2. 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

  1. DNS — translates domain names to IP addresses
  2. Load balancer — distributes traffic across servers
  3. Web servers — handle HTTP and should be stateless
  4. Application servers — contain business logic and should be stateless if possible
  5. Cache (Redis or Memcached) — fast in-memory storage
  6. Database — persistent storage
  7. Message queue (RabbitMQ or Kafka) — asynchronous service communication
  8. Object storage (S3) — large files and blobs
  9. 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.