Many beginners learn system design by memorizing technologies:
- Load balancers
- Redis
- Kafka
- Microservices
- Sharding
- Database replication
But knowing these technologies is not enough.
The real question is:
What problem are we trying to solve?
A system serving 1,000 users does not need the same architecture as one serving 10 million users.
Good system design is about understanding requirements, scale, constraints, failures, and trade-offs before choosing technologies.
A simple system-design thinking process is:
Requirements
↓
Traffic
↓
API
↓
Database
↓
Bottlenecks
↓
Caching
↓
Scaling
↓
Reliability
↓
Monitoring
Let's understand each step.
What Is System Design?
System design is deciding how different software and infrastructure components work together to satisfy a system's requirements.
For example, a chat application may need:
- APIs
- WebSockets
- Database
- Authentication
- Application servers
The important part is not drawing these components.
It is understanding why they are needed.
1. Start With Requirements
First, understand what the system must do.
These are the functional requirements.
Chat application
- Send messages
- Receive messages
- View message history
URL shortener
- Submit a URL
- Generate a short URL
- Redirect to the original URL
Then identify non-functional requirements:
- Scalability
- Availability
- Reliability
- Latency
- Throughput
- Security
- Durability
These requirements influence your architecture.
For example, a payment system may prioritize correctness and durability, while a real-time application may prioritize low latency.
2. Understand the Scale
Before choosing infrastructure, estimate the workload.
Ask:
- How many users?
- How many daily active users?
- Requests per second?
- Peak traffic?
- Read/write ratio?
- How much data will be generated?
For example:
10 million users
↓
20 requests/user/day
↓
200 million requests/day
↓
~2,315 requests/sec average
Peak traffic may be several times higher.
You don't need perfect numbers.
You need estimates good enough to make architectural decisions.
3. Design the API
Define how clients interact with the system.
For a chat application:
GET /users/{id}
POST /messages
GET /messages?cursor=abc123
Keep endpoints focused on clear responsibilities.
For large datasets, use pagination instead of returning everything at once:
GET /messages?cursor=abc123&limit=50
Stateless APIs also make horizontal scaling easier because any application server can handle a request.
4. Choose the Database
Don't start with:
"Should I use PostgreSQL or MongoDB?"
Start with:
"How will the data be used?"
Consider:
- Data relationships
- Query patterns
- Read/write ratio
- Consistency requirements
- Dataset size
- Transaction requirements
SQL databases are often useful for structured data, relationships, and transactions.
NoSQL databases can be useful for specific distributed and high-throughput workloads.
Neither is universally better.
Database selection is a trade-off.
5. Find the Bottleneck
A bottleneck is the component limiting the system's performance.
For example:
Users
↓
API Servers
↓
Database
If the API can handle 10,000 requests/sec but the database can handle only 2,000 writes/sec, adding more API servers won't solve the problem.
The database is the bottleneck.
Possible solutions include:
- Better queries
- Indexing
- Caching
- Replication
- Partitioning
- Reducing unnecessary work
Find the constraint before scaling everything.
6. Add Caching When Necessary
Caching reduces repeated expensive operations.
A typical flow is:
Client
↓
API
↓
Cache
↓
Database
If the data exists in the cache, it's a cache hit.
If not, it's a cache miss, and the application can retrieve the data from the database.
Redis is commonly used for distributed caching.
But caching introduces its own problems:
- Stale data
- Cache invalidation
- Memory usage
- Cache failures
So don't add Redis because "scalable systems use Redis."
Add caching when you have a caching problem.
7. Scale the Application
There are two basic approaches.
Vertical Scaling
Increase the resources of one machine.
4 CPU + 8 GB RAM
↓
16 CPU + 64 GB RAM
Simple, but the machine has limits.
Horizontal Scaling
Add more machines.
Users
↓
Load Balancer
↓
Server 1
Server 2
Server 3
Horizontal scaling improves capacity and can improve availability.
Stateless application servers make this much easier.
8. Design for Failure
Systems fail.
Servers crash. Databases become unavailable. Networks timeout. External APIs stop responding.
Ask:
"What happens when this component fails?"
Important concepts include:
- Redundancy
- Health checks
- Failover
- Replication
- Backups
- Timeouts
- Retries
Also look for single points of failure.
Availability vs Reliability
Availability:
Is the system accessible?
Reliability:
Does the system consistently work correctly?
A system can be available but still unreliable.
9. Monitor the System
A production system needs visibility.
Three important areas are:
Logs
Tell you what happened.
Metrics
Tell you how the system is behaving.
Useful metrics include:
- Request volume
- Error rate
- Latency
- CPU
- Memory
- Database connections
Traces
Help identify where a request spent its time.
For example:
API Request
↓ 10ms
Application
↓ 20ms
Database
↓ 400ms
External API
Without observability, debugging production problems becomes much harder.
The System Design Thinking Process
When solving a new system design problem, follow this order:
Requirements
↓
Traffic Estimation
↓
API Design
↓
Database
↓
Bottlenecks
↓
Caching
↓
Scaling
↓
Reliability
↓
Monitoring
Each step answers a simple question:
| Step | Question |
|---|---|
| Requirements | What does the system need to do? |
| Traffic | How much load will it handle? |
| API | How will clients interact with it? |
| Database | How should data be stored? |
| Bottlenecks | What could limit performance? |
| Caching | What expensive work can be avoided? |
| Scaling | How will we handle more load? |
| Reliability | What happens when things fail? |
| Monitoring | How will we know the system is healthy? |
Example: A Chat Application
Let's see how architecture can evolve.
100 Users
Keep it simple:
Users
↓
Application Server
↓
Database
WebSockets can handle real-time communication.
No need for Kafka, Kubernetes, microservices, or database sharding.
100,000 Users
Now a single server may become a bottleneck:
Users
↓
Load Balancer
↓
App 1 | App 2 | App 3
↓
Database
A shared messaging or coordination layer may become useful for real-time communication.
10 Million Users
Now additional challenges appear:
- Concurrent connections
- Message throughput
- Database capacity
- Storage growth
- Network load
- Failure handling
The architecture may evolve toward:
Users
↓
Load Balancer
↓
Application Servers
↓
Message Queue
↓
Processing
↓
Database
├── Primary
└── Replicas
The important lesson is:
Don't build the 10-million-user architecture for 100 users.
Let the architecture evolve as the workload and requirements change.
Common Beginner Mistakes
1. Starting With Technologies
Don't start with:
"Let's use Kafka."
Start with:
"What problem requires a message queue?"
2. Jumping to Microservices
A modular monolith may be perfectly suitable for a smaller system.
3. Ignoring Traffic
Architecture depends heavily on workload.
4. Ignoring Failures
Always ask what happens when a component becomes unavailable.
5. Choosing Databases by Popularity
Choose based on data and access patterns.
6. Adding Caching Everywhere
Caching solves specific problems and introduces complexity.
7. Ignoring Monitoring
A system that cannot be observed is difficult to operate.
8. Over-Engineering
Not every application needs:
- Kafka
- Kubernetes
- Microservices
- Sharding
- Multiple databases
9. Focusing Only on the Happy Path
Think about:
What if the server fails?
What if the database is slow?
What if traffic suddenly spikes?
10. Memorizing Architectures
Understand why a component exists instead of memorizing where to draw it.
Beginner's System Design Checklist
Before finalizing a design, ask:
□ What does the system need to do?
□ How many users are there?
□ How much traffic will it receive?
□ What is the read/write ratio?
□ What latency is expected?
□ Where could bottlenecks occur?
□ Does caching solve a real problem?
□ How will the application scale?
□ How will the database scale?
□ What happens when something fails?
□ Are there single points of failure?
□ How will the system be monitored?
Conclusion
System design for beginners is not about memorizing Redis, Kafka, Kubernetes, or hundreds of architecture diagrams.
It is about learning how to think.
Start with requirements.
Estimate the workload.
Design the APIs.
Choose the right storage.
Find bottlenecks.
Add caching when necessary.
Scale when the workload demands it.
Plan for failures.
Monitor the system.
There is no single perfect architecture.
Good system design is about understanding constraints, making trade-offs, and building a system that can evolve as requirements and traffic change.
Top comments (0)