SevyDevy

Guide · System design

System Design for Beginners: A Visual Roadmap from Requirements to Real Systems

22 min readUpdated By Saket Bhatnagar

Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.

In short

A practical visual guide to system design for beginners, covering requirements, APIs, data modeling, architecture, scaling, reliability, observability, and real-world examples.

Why Beginners Find System Design Difficult

Most beginners think system design means drawing complex diagrams with load balancers, caches, queues, databases, and microservices. But that is not where system design starts. Real system design starts with clarity. You first understand what the system should do, how many users it should support, what data it should store, what can fail, and what tradeoffs are acceptable.

System design is not about memorizing the architecture of YouTube, WhatsApp, Instagram, or Netflix. It is about learning how to think from first principles. A strong system designer can take a vague product idea and convert it into requirements, APIs, data models, components, scaling strategy, reliability plan, and tradeoffs.

This course is built for someone who is completely new to system design. The goal is to make system design feel structured, practical, and explainable.

The One Mental Model You Need First

A system design problem is not solved in one jump. It is solved in layers. First, you clarify the product. Then you define requirements. Then you design interfaces. Then you decide how data will be stored. Then you draw architecture. After that, you improve it for scale, performance, reliability, and observability.

The beginner system design thinking ladder

Each step answers one question, moving from a product idea to requirements, APIs, data, architecture, scale, reliability and tradeoffs.

Diagram connections:

  • Product Idea to Functional Requirements
  • Functional Requirements to Non-Functional Requirements
  • Non-Functional Requirements to APIs and Interfaces
  • APIs and Interfaces to Data Model
  • Data Model to High-Level Architecture
  • High-Level Architecture to Caching and Performance
  • Caching and Performance to Scaling Strategy
  • Scaling Strategy to Reliability Plan
  • Reliability Plan to Observability
  • Observability to Final Design Explanation
  • Functional Requirements: What should it do?
  • Non-Functional Requirements: How well should it work?
  • APIs and Interfaces: How will users interact?
  • Data Model: What data is needed?
  • High-Level Architecture: How do components connect?
  • Caching and Performance: How do we make it fast?
  • Scaling Strategy: How do we handle growth?
  • Reliability Plan: What can fail?
  • Observability: How do we debug it?
  • Final Design Explanation: What did we trade off?

What You Will Learn in This Course

This course teaches the foundation that every beginner needs before touching advanced distributed systems. You will not start with Kafka, Kubernetes, consensus algorithms, distributed transactions, or multi-region architecture. You will first learn the thinking system behind good design.

  • How to clarify a vague product idea before designing anything.
  • How to separate functional requirements from non-functional requirements.
  • How to define APIs that reveal the real behavior of the system.
  • How to design data models based on access patterns.
  • How to draw clean high-level architecture diagrams.
  • How caching improves speed and where it creates complexity.
  • How load balancing and stateless services support horizontal scaling.
  • How queues and workers move slow work outside the main request flow.
  • How to think about timeouts, retries, idempotency, and failures.
  • How logs, metrics, and traces help operate a real system.
  • How to explain tradeoffs clearly in interviews and real engineering discussions.

The Complete Beginner Course Roadmap

The roadmap is intentionally layered. Each module builds on the previous one. If you skip requirements, architecture becomes guesswork. If you skip APIs, data modeling becomes weak. If you skip failure handling, the system only works in ideal conditions.

Complete beginner system design course roadmap

Fifteen modules in five layers: clarity, shaping the system, improving it, operating it, and applying the thinking to two examples.

Diagram connections:

  • What is System Design? to Requirements
  • Requirements to Core Vocabulary
  • APIs to Data Modeling
  • Data Modeling to High-Level Architecture
  • Performance to Caching
  • Caching to Scaling
  • Scaling to Queues
  • Reliability to Observability
  • Observability to Tradeoffs
  • Example 1: URL Shortener to Example 2: Chat System
  • Core Vocabulary to APIs
  • High-Level Architecture to Performance
  • Queues to Reliability
  • Tradeoffs to Example 1: URL Shortener
  • What is System Design?: Module 1 · Layer 1: Clarity
  • Requirements: Module 2 · Layer 1: Clarity
  • Core Vocabulary: Module 3 · Layer 1: Clarity
  • APIs: Module 4 · Layer 2: Shape the System
  • Data Modeling: Module 5 · Layer 2: Shape the System
  • High-Level Architecture: Module 6 · Layer 2: Shape the System
  • Performance: Module 7 · Layer 3: Improve the System
  • Caching: Module 8 · Layer 3: Improve the System
  • Scaling: Module 9 · Layer 3: Improve the System
  • Queues: Module 10 · Layer 3: Improve the System
  • Reliability: Module 11 · Layer 4: Operate the System
  • Observability: Module 12 · Layer 4: Operate the System
  • Tradeoffs: Module 13 · Layer 4: Operate the System
  • Example 1: URL Shortener: Layer 5: Apply the Thinking
  • Example 2: Chat System: Layer 5: Apply the Thinking

Module 1: What is System Design?

System design is the process of deciding how a software system should be structured internally so that it can serve users correctly, quickly, reliably, and affordably. It connects product requirements with engineering decisions.

A coding problem usually asks you to implement a function. A system design problem asks you to design a service. That service may need APIs, databases, caching, background jobs, monitoring, rate limiting, and failure handling. The answer is not a single block of code. The answer is a set of engineering decisions.

  • Coding asks: Can you solve this exact problem correctly?
  • System design asks: Can you design a system that survives real usage?
  • Coding is usually local to one function or module.
  • System design spans clients, servers, data, networks, failures, and operations.
  • Coding has a more objective answer. System design has tradeoffs.

Coding vs system design

Coding problems are judged at the function level; system design problems are judged on users, traffic, APIs, data, scale, failures and tradeoffs.

Diagram connections:

  • Software Engineering Problem to Coding
  • Software Engineering Problem to System Design
  • Coding to Function-level thinking
  • Coding to Input and output
  • Coding to Algorithm correctness
  • Coding to Time and space complexity
  • System Design to Service-level thinking
  • System Design to Users and traffic
  • System Design to APIs and data
  • System Design to Scale, failures, and tradeoffs

Module 2: Requirements Gathering

Requirements are the foundation of system design. If the requirements are unclear, every later decision becomes weak. Beginners often make the mistake of jumping directly to architecture. Strong engineers first clarify what the system must do and how well it must work.

Requirements are usually divided into functional requirements and non-functional requirements. Functional requirements describe the features. Non-functional requirements describe the quality targets.

  • Functional requirement: User can create a short URL.
  • Functional requirement: User can send a chat message.
  • Functional requirement: User can fetch conversation history.
  • Non-functional requirement: Redirect latency should be under 100ms for most requests.
  • Non-functional requirement: Messages should not be lost after being acknowledged.
  • Non-functional requirement: The system should remain available during traffic spikes.

Requirement types in system design

Functional requirements, non-functional requirements, constraints and assumptions, each with what it covers.

Diagram connections:

  • Requirements to Functional Requirements
  • Requirements to Non-Functional Requirements
  • Requirements to Constraints
  • Requirements to Assumptions
  • Functional Requirements to Features
  • Non-Functional Requirements to Quality Targets
  • Constraints to Limits
  • Assumptions to Reasonable Defaults
  • Features: What should users be able to do?
  • Quality Targets: Latency, availability, durability, throughput
  • Limits: Budget, technology, compliance, timeline
  • Reasonable Defaults: Traffic split, region, usage pattern

Module 3: Core System Design Vocabulary

Before designing systems, you need to understand the common building blocks. These building blocks appear again and again in almost every real-world system. The names may change, but the responsibility remains similar.

  • Client: The user-facing app such as browser, mobile app, or desktop app.
  • API Server: The service that receives requests and runs business logic.
  • Database: The durable storage layer where important data is saved.
  • Cache: A temporary fast storage layer used to reduce latency and database load.
  • Load Balancer: A component that distributes requests across multiple servers.
  • Queue: A buffer that stores jobs for asynchronous processing.
  • Worker: A background process that consumes jobs from a queue.
  • CDN: A network that serves static content close to users.
  • Object Storage: Storage for large files like images, videos, PDFs, and backups.

System design building blocks

The user facing, compute, data and async processing layers, and how requests move between them.

Diagram connections:

  • User to Client App
  • Client App to CDN
  • Client App to Load Balancer
  • Load Balancer to API Server A
  • Load Balancer to API Server B
  • Load Balancer to API Server C
  • API Server A to Cache
  • API Server B to Cache
  • API Server C to Cache
  • Cache to Database
  • API Server A to Database
  • API Server B to Database
  • API Server C to Database
  • API Server A to Queue
  • API Server B to Queue
  • API Server C to Queue
  • Queue to Worker A
  • Queue to Worker B
  • Worker A to Object Storage
  • Worker B to Object Storage
  • Worker A to Database
  • Worker B to Database
  • User: User Facing Layer
  • Client App: User Facing Layer
  • CDN: User Facing Layer
  • Load Balancer: Compute Layer
  • API Server A: Compute Layer
  • API Server B: Compute Layer
  • API Server C: Compute Layer
  • Cache: Data Layer
  • Database: Data Layer
  • Object Storage: Data Layer
  • Queue: Async Processing Layer
  • Worker A: Async Processing Layer
  • Worker B: Async Processing Layer

Module 4: APIs and Interfaces

APIs define how users, clients, and services interact with your system. A good API design makes the system easier to understand. It also exposes what data is needed, what actions are possible, and what errors can happen.

Beginners should learn to design APIs before architecture. APIs force you to think about the actual product behavior instead of jumping into vague infrastructure choices.

  • POST is commonly used to create resources.
  • GET is commonly used to read resources.
  • PATCH is commonly used for partial updates.
  • DELETE is commonly used to remove resources.
  • Request body should contain only the data needed for the operation.
  • Response should be predictable and easy for clients to consume.
  • Errors should be explicit, not random strings.
txt
Example: URL Shortener APIs

POST /short-urls
Body:
{
  "originalUrl": "https://example.com/very/long/path",
  "expiresAt": "2026-12-31T23:59:59Z"
}

Response:
{
  "shortCode": "a7Kx9p",
  "shortUrl": "https://short.ly/a7Kx9p"
}

GET /:shortCode

Success:
302 Redirect to originalUrl

Failure:
404 Short URL not found
410 Short URL expired

Module 5: Data Modeling

Data modeling means deciding what information the system stores and how that information will be queried. A beginner mistake is choosing MongoDB, PostgreSQL, Redis, or DynamoDB before understanding the access pattern. Good engineers first ask: what data do we need, and how will it be read or written?

  • Use relational databases when relationships, constraints, joins, and transactions matter.
  • Use key-value stores when the main access pattern is lookup by key.
  • Use indexes when reads need to be fast on specific fields.
  • Use object storage when files are large and do not fit well inside a database.
  • Avoid designing tables only from entities. Design them around important queries.
  • Always ask which operation must be fastest: read, write, search, update, or analytics.

Storage selection decision tree

Start from the access pattern; each answer points to a storage type and the data that usually lives there.

Diagram connections:

  • Choose Storage to What is the access pattern?
  • What is the access pattern? to Relational Database (Structured data with relationships)
  • What is the access pattern? to Key-Value Store (Fast lookup by key)
  • What is the access pattern? to Cache (Frequently read temporary data)
  • What is the access pattern? to Object Storage (Large files)
  • What is the access pattern? to Search Index (Search by text relevance)
  • What is the access pattern? to Event Store / Warehouse (Event history or analytics)
  • Relational Database: Users, orders, payments, permissions
  • Key-Value Store: shortCode to originalUrl, sessions
  • Cache: Popular reads, temporary computed data
  • Object Storage: Images, videos, PDFs, backups
  • Search Index: Documents, products, resumes
  • Event Store / Warehouse: Clicks, views, audit events

Module 6: High-Level Architecture

High-level architecture shows how major components connect. It should be simple enough to explain quickly, but complete enough to show the request flow. Beginners should start with a basic working system, then improve it only when the requirement demands it.

A strong architecture diagram should answer three questions: where does the request enter, where does the business logic run, and where is the data stored?

Simple request lifecycle

One user action, step by step: the client calls the API, the API validates and reads or writes the database, and the result flows back.

Diagram connections:

  • Performs action to Sends HTTP request
  • Sends HTTP request to Validate input and auth
  • Validate input and auth to Read or write data
  • Read or write data to Return result
  • Return result to Return response
  • Return response to Show result
  • Performs action: User → Client App
  • Sends HTTP request: Client App → API Server
  • Validate input and auth: API Server
  • Read or write data: API Server → Database
  • Return result: Database → API Server
  • Return response: API Server → Client App
  • Show result: Client App → User

Module 7: Performance Basics

Performance should be discussed with measurable terms. Saying the system should be fast is weak. Saying the redirect API should have p95 latency under 100ms is much stronger because it gives the design a target.

  • Latency means how long one request takes.
  • Throughput means how much work the system handles per second.
  • QPS means queries per second.
  • p95 latency means 95% of requests complete within that time.
  • p99 latency exposes slow edge cases.
  • Bottleneck means the first overloaded part of the system.
  • Read-heavy means the system receives more reads than writes.
  • Write-heavy means the system receives more writes than reads.

Performance vocabulary map

Latency, throughput, tail latency and bottlenecks, each with what it means and an example.

Diagram connections:

  • Performance to Latency
  • Performance to Throughput
  • Performance to Tail Latency
  • Performance to Bottlenecks
  • Latency to Example
  • Throughput to Example
  • Tail Latency to Example
  • Bottlenecks to Example
  • Latency: Time taken by one request
  • Throughput: Total work handled per second
  • Tail Latency: p95 and p99 slow requests
  • Bottlenecks: First component that gets overloaded
  • Example: API responds in 80ms
  • Example: 10,000 QPS
  • Example: p95 under 200ms
  • Example: database CPU is saturated

Module 8: Caching

Caching stores frequently accessed data in a faster layer so the system can respond quickly and reduce database load. But caching is not free. It introduces cache invalidation, stale data, cache stampede, and consistency concerns.

The most beginner-friendly caching pattern is cache-aside. In cache-aside, the application first checks the cache. If data is missing, it reads from the database, stores the result in cache, and then returns the data.

Cache-aside pattern

On a cache hit the API answers from the cache; on a miss it reads the database, stores the data with a TTL and responds.

Diagram connections:

  • Request data to Check cache
  • Check cache to Return cached data (Cache hit)
  • Return cached data to Fast response
  • Check cache to Not found (Cache miss)
  • Not found to Read from database
  • Read from database to Return data
  • Return data to Store data with TTL
  • Store data with TTL to Response
  • Request data: Client → API
  • Check cache: API → Cache
  • Return cached data: Cache → API
  • Fast response: API → Client
  • Not found: Cache → API
  • Read from database: API → Database
  • Return data: Database → API
  • Store data with TTL: API → Cache
  • Response: API → Client
  • Cache hit: requested data is found in cache.
  • Cache miss: requested data is not found in cache.
  • TTL: how long cached data should live.
  • Stale data: cache has old data after the source changed.
  • Cache invalidation: removing or updating cache when data changes.
  • Cache stampede: many requests miss the cache at the same time.
  • Negative caching: caching not-found results for a short time.

Module 9: Scaling Basics

Scaling means making the system handle more users, more traffic, more data, or more background work. There are two basic forms of scaling: vertical scaling and horizontal scaling.

Vertical scaling means making one machine bigger. Horizontal scaling means adding more machines. Modern systems usually prefer horizontal scaling for application servers because it gives better flexibility and fault tolerance.

Vertical scaling vs horizontal scaling

Vertical scaling makes one machine stronger; horizontal scaling adds machines behind a load balancer.

Diagram connections:

  • Scaling Strategy to Vertical Scaling
  • Scaling Strategy to Horizontal Scaling
  • Vertical Scaling to More CPU
  • Vertical Scaling to More RAM
  • Vertical Scaling to Better disk
  • Horizontal Scaling to Server A
  • Horizontal Scaling to Server B
  • Horizontal Scaling to Server C
  • Server A to Load Balancer
  • Server B to Load Balancer
  • Server C to Load Balancer
  • Scaling Strategy to Reality
  • Reality to Vertical scaling is simple but limited
  • Reality to Horizontal scaling is flexible but needs stateless services
  • Vertical Scaling: Make one machine stronger
  • Horizontal Scaling: Add more machines

Module 10: Queues and Async Processing

Queues are used when work does not need to happen immediately inside the user request. Instead of forcing the user to wait for heavy processing, the API records the request, pushes a job to a queue, and returns quickly. A background worker processes the job later.

Queues improve user experience and system resilience, but they introduce eventual processing. That means the result may not be available immediately.

Queue-based async processing with retry and DLQ

The API accepts the job and returns at once; a worker processes it, retries with a limit, and parks repeated failures in a dead letter queue.

Diagram connections:

  • User Action to API Server
  • API Server to Validate Request
  • Validate Request to Store Metadata
  • Store Metadata to Push Job to Queue
  • Push Job to Queue to Return Accepted Response
  • Push Job to Queue to Queue
  • Queue to Worker Picks Job
  • Worker Picks Job to Process Heavy Work
  • Process Heavy Work to Success?
  • Success? to Store Final Result (Yes)
  • Success? to Retry with Limit (No)
  • Retry with Limit to Still Failing?
  • Still Failing? to Dead Letter Queue (Yes)
  • Still Failing? to Worker Picks Job (No)

Module 11: Reliability

Reliability means the system behaves safely when something goes wrong. A beginner system design should not only describe the happy path. It should also explain what happens when the database is slow, cache is down, queue is full, external API times out, or a user retries the same request.

  • Timeout: Do not wait forever for a dependency.
  • Retry: Try again when failure is temporary.
  • Idempotency: Make repeated requests safe.
  • Availability: The system remains reachable and useful.
  • Durability: Saved data should not disappear.
  • Graceful degradation: The system gives reduced functionality instead of fully failing.
  • Circuit breaker: Stop calling a dependency that is repeatedly failing.

Reliability flow: timeout, retry, circuit breaker, idempotency

What happens when a dependency is slow, failing repeatedly or failing temporarily, and why retries need idempotency.

Diagram connections:

  • Request to Call Dependency
  • Call Dependency to Dependency Healthy?
  • Dependency Healthy? to Return Success (Yes)
  • Dependency Healthy? to Timeout (Slow)
  • Dependency Healthy? to Circuit Breaker Opens (Failing repeatedly)
  • Dependency Healthy? to Retry with Backoff (Temporary failure)
  • Timeout to Return Controlled Error
  • Circuit Breaker Opens to Fail Fast or Use Fallback
  • Retry with Backoff to Idempotent Operation?
  • Idempotent Operation? to Safe Retry (Yes)
  • Idempotent Operation? to Risk of Duplicate Side Effects (No)
  • Safe Retry to Success or Controlled Failure
  • Risk of Duplicate Side Effects to Use Idempotency Key Before Retrying

Module 12: Observability

Observability helps engineers understand what is happening inside a live system. Without observability, production debugging becomes guesswork. A system should emit enough information to answer three questions: what happened, how often did it happen, and where was time spent?

  • Logs tell what happened.
  • Metrics tell how often or how much it happened.
  • Traces tell where time was spent across components.
  • Request IDs connect logs across services.
  • Alerts notify the team when something important breaks.
  • Dashboards help engineers see system health quickly.

Observability: logs, metrics and traces

Each signal answers one question, with an example, and feeds debugging, alerting or performance analysis.

Diagram connections:

  • Running System to Logs
  • Running System to Metrics
  • Running System to Traces
  • Logs to Example
  • Metrics to Example
  • Traces to Example
  • Logs to Debugging
  • Metrics to Alerting
  • Traces to Performance Analysis
  • Debugging to System Health
  • Alerting to System Health
  • Performance Analysis to System Health
  • Logs: What happened?
  • Metrics: How often or how much?
  • Traces: Where was time spent?
  • Example: database timeout for requestId abc123
  • Example: error rate, latency, QPS, cache hit rate
  • Example: API 40ms, DB 120ms, cache 5ms

Module 13: Tradeoffs

System design is full of tradeoffs. Every improvement has a cost. Caching improves read speed but can create stale data. Queues improve resilience but add delay. Microservices improve separation but increase operational complexity. Replication improves availability but introduces consistency challenges.

A strong system design explanation does not hide tradeoffs. It names them clearly and explains why one choice is better for the current requirements.

Every system design decision has a tradeoff

A design choice brings benefits and costs; the tradeoff decision explains why this balance fits the requirements.

Diagram connections:

  • Design Choice to Benefit
  • Design Choice to Cost
  • Benefit to Lower latency
  • Benefit to Higher availability
  • Benefit to Better scalability
  • Benefit to Improved user experience
  • Cost to More complexity
  • Cost to More infrastructure cost
  • Cost to More failure modes
  • Cost to Possible consistency issues
  • Lower latency to Tradeoff Decision
  • Higher availability to Tradeoff Decision
  • Better scalability to Tradeoff Decision
  • Improved user experience to Tradeoff Decision
  • More complexity to Tradeoff Decision
  • More infrastructure cost to Tradeoff Decision
  • More failure modes to Tradeoff Decision
  • Possible consistency issues to Tradeoff Decision
  • Tradeoff Decision: Explain why this tradeoff fits the requirements

Example 1: URL Shortener System Design

A URL shortener is one of the best beginner examples because the product is simple but the system still teaches important design ideas: API design, unique short code generation, redirects, read-heavy traffic, caching, collision handling, rate limiting, and hot URLs.

  • Create short URL from long URL.
  • Redirect short URL to original URL.
  • Support optional expiry.
  • Keep redirect latency low.
  • Handle read-heavy traffic because redirects are usually more frequent than creations.
  • Prevent abuse using rate limiting.
  • Cache popular short-code mappings.
  • Handle short-code collisions during generation.

URL shortener: create flow and redirect flow

Creating a short URL retries on code collisions; redirects check the cache, then the database, and refill the cache.

Diagram connections:

  • User submits long URL to API validates URL
  • API validates URL to Generate short code
  • Generate short code to Code already exists?
  • Code already exists? to Generate short code (Yes)
  • Code already exists? to Store mapping in database (No)
  • Store mapping in database to Return short URL
  • User opens short URL to Redirect API
  • Redirect API to Check cache
  • Check cache to Mapping found?
  • Mapping found? to Return 302 redirect (Yes)
  • Mapping found? to Read mapping from database (No)
  • Read mapping from database to Exists and not expired?
  • Exists and not expired? to Update cache (Yes)
  • Update cache to Return 302 redirect
  • Exists and not expired? to Return 404 or 410 (No)
  • User submits long URL: Create Short URL Flow
  • API validates URL: Create Short URL Flow
  • Generate short code: Create Short URL Flow
  • Code already exists?: Create Short URL Flow
  • Store mapping in database: Create Short URL Flow
  • Return short URL: Create Short URL Flow
  • User opens short URL: Redirect Flow
  • Redirect API: Redirect Flow
  • Check cache: Redirect Flow
  • Mapping found?: Redirect Flow
  • Return 302 redirect: Redirect Flow
  • Read mapping from database: Redirect Flow
  • Exists and not expired?: Redirect Flow
  • Update cache: Redirect Flow
  • Return 404 or 410: Redirect Flow

This diagram has two flows: creating a short URL and opening a short URL. In the create flow, the user gives a long URL, the API validates it, generates a short code, checks for duplicates, saves it in the database, and returns the short URL.

In the redirect flow, the user opens the short URL. The system first checks the cache because it is faster. If the mapping is found, the user is redirected immediately.

If the cache does not have the mapping, the system checks the database. If the URL exists and is not expired, it updates the cache and redirects the user. If not, it returns 404 or 410.

  • Database stores the original long URL and short code.
  • Cache makes popular short URLs open faster.
  • Collision handling prevents duplicate short codes.
  • Expiry helps remove or block old short URLs.
  • 302 redirect sends the user to the original URL.

Example 2: Chat System Design

A chat system teaches real-time communication, message storage, delivery status, ordering, fanout, push notifications, and duplicate prevention. It is more complex than a URL shortener because users expect messages to appear quickly and not disappear after being sent.

  • User can send a message.
  • Receiver can receive the message.
  • Users can fetch conversation history.
  • Messages should be stored durably.
  • Duplicate messages should be avoided.
  • Push notifications can be async.
  • WebSocket can be used for real-time delivery.
  • Message ordering should be considered inside a conversation.

Chat system message delivery flow

The message is stored durably and acknowledged, then delivered in real time or as a push notification if the receiver is offline.

Diagram connections:

  • Send message to Forward message with idempotency key
  • Forward message with idempotency key to Store message durably
  • Store message durably to Message saved
  • Message saved to Acknowledge saved message
  • Acknowledge saved message to Message sent acknowledgement
  • Message sent acknowledgement to Deliver message in real time (Receiver online)
  • Message sent acknowledgement to Push notification job (Receiver offline)
  • Push notification job to Worker consumes job
  • Worker consumes job to Send push notification
  • Send message: Sender Client → WebSocket/API Server
  • Forward message with idempotency key: WebSocket/API Server → Message Service
  • Store message durably: Message Service → Message Database
  • Message saved: Message Database → Message Service
  • Acknowledge saved message: Message Service → WebSocket/API Server
  • Message sent acknowledgement: WebSocket/API Server → Sender Client
  • Deliver message in real time: Message Service → Receiver Client
  • Push notification job: Message Service → Notification Queue
  • Worker consumes job: Notification Queue → Notification Worker
  • Send push notification: Notification Worker → Receiver Client

This diagram shows how a chat message travels from one user to another user. Think of it like sending a WhatsApp message.

First, the sender’s phone or browser sends the message to the WebSocket/API server. The server then passes the message to the Message Service.

The Message Service is like the main brain of the chat system. It decides how the message should be saved and delivered.

Before showing the message as successfully sent, the system saves it safely in the database. This makes sure the message is not lost if the app crashes later.

After the message is saved, the sender gets a confirmation that the message was sent successfully.

Now the system checks whether the receiver is online or offline. If the receiver is online, the message is delivered immediately using WebSocket.

If the receiver is offline, the system adds a notification task into a queue. A worker later picks that task and sends the push notification.

  • Think of this like sending a WhatsApp message.
  • Sender Client means the phone or browser of the person sending the message.
  • WebSocket/API Server is the entry point where the message first reaches the backend.
  • Message Service is the main brain that decides what to do with the message.
  • The message is first saved in the database so it does not get lost.
  • After saving, the sender gets a confirmation that the message was sent.
  • If the receiver is online, the message is delivered instantly.
  • If the receiver is offline, the system creates a notification task.
  • The queue stores this notification task for later processing.
  • The worker picks the task from the queue and sends a push notification.
  • This design makes chat fast, safe, and reliable.

The Beginner System Design Checklist

Use this checklist whenever you solve a system design problem. It keeps your thinking organized and prevents you from randomly adding components.

  • What problem are we solving?
  • Who are the users?
  • What are the functional requirements?
  • What are the non-functional requirements?
  • What assumptions are we making?
  • What APIs are needed?
  • What data must be stored?
  • What are the read and write patterns?
  • Which storage system fits the access pattern?
  • Where can caching help?
  • What can become the bottleneck?
  • How will the system scale?
  • What work should be asynchronous?
  • What can fail?
  • How will timeout, retry, and idempotency work?
  • What logs, metrics, and traces are needed?
  • What tradeoffs are we making?

Beginner system design answer flow

A step-by-step answer, from clarifying the problem to explaining the tradeoffs.

Diagram connections:

  • Start to Clarify Problem
  • Clarify Problem to List Functional Requirements
  • List Functional Requirements to List Non-Functional Requirements
  • List Non-Functional Requirements to Define APIs
  • Define APIs to Design Data Model
  • Design Data Model to Draw Basic Architecture
  • Draw Basic Architecture to Explain Read and Write Flow
  • Explain Read and Write Flow to Identify Bottlenecks
  • Identify Bottlenecks to Add Cache if Needed
  • Add Cache if Needed to Add Queue if Needed
  • Add Queue if Needed to Scale Stateless Services
  • Scale Stateless Services to Handle Failures
  • Handle Failures to Add Observability
  • Add Observability to Explain Tradeoffs
  • Explain Tradeoffs to Final Answer

Common Beginner Mistakes

Most beginner mistakes come from rushing. They jump to components before understanding the system. A good design is not the one with the most boxes. A good design is the one where every box has a reason.

  • Jumping directly to architecture without requirements.
  • Using vague words like fast, scalable, or reliable without measurable targets.
  • Choosing a database before understanding access patterns.
  • Adding cache without explaining stale data or invalidation.
  • Adding queues without explaining async delay.
  • Adding retries without idempotency.
  • Ignoring failure modes.
  • Ignoring logs, metrics, and traces.
  • Using microservices too early.
  • Not explaining tradeoffs.

Final Takeaway

System design becomes easier when you stop treating it like architecture memorization and start treating it like structured thinking. Every system begins with requirements. Every component should solve a specific problem. Every optimization creates a tradeoff.

For beginners, the goal is not to design massive distributed systems on day one. The goal is to learn how to think clearly: define the problem, design the interface, model the data, draw the architecture, improve for scale, prepare for failures, observe the system, and explain the tradeoffs.

Practise this with Lala

Practise