Published by: Vimal Patel
System Design - 101
Software applications start small, but successful applications rarely stay small.
An application that works perfectly for 100 users may behave very differently when it needs to support 100,000 or 10 million users.
As the number of users, requests, data, and services increases, simply writing more code is not enough. We need to think about architecture, scalability, performance, reliability, availability, security, data management, and failure handling.
This is where System Design becomes important.
In this article, we will build the foundation of System Design by answering:
1. What Is System Design?
System Design is the process of defining the architecture, components, data flow, interfaces, technologies, and operational characteristics of a software system so that it can satisfy both functional and non-functional requirements.
It is not only about drawing architecture diagrams.
System Design involves making engineering decisions about:
Example
Suppose we want to build a food-delivery application.
At first, the problem may appear simple:
- A customer selects a restaurant, chooses food, pays, and receives the order.
But once we start designing the system, many questions appear:
Answering these questions systematically is part of System Design.
2. Why Do We Need System Design?
- A small application might initially look like this:
User
↓
Application Server
↓
Database
This may work perfectly for a small number of users.
- But imagine the application grows:
100 Users
↓
10,000 Users
↓
100,000 Users
↓
1,000,000 Users
↓
10,000,000 Users
The original architecture may no longer be sufficient.
- We may need:
System Design helps us think about these requirements before the system becomes difficult to scale or maintain.
3. Functional and Non-Functional Requirements
Before designing a system, we need to understand what the system is supposed to do.
Requirements are commonly divided into two major categories.
Functional Requirements
Functional requirements describe what the system should do.
For example, in a food-delivery application:
- Users can register.
- Users can log in.
- Users can browse restaurants.
- Users can view menus.
- Users can place orders.
- Users can make payments.
- Restaurants can manage orders.
- Delivery partners can update delivery status.
These describe the actual functionality.
Non-Functional Requirements
Non-functional requirements describe how well the system should perform.
Examples include:
- Scalability
- Availability
- Reliability
- Performance
- Security
- Maintainability
- Durability
- Fault tolerance
For example:
The system should support 1 million concurrent users.
or:
The API should normally respond within 200 milliseconds.
or:
The payment system should remain available even if one application server fails.
These requirements strongly influence the architecture.
4. Classification of System Design
System Design can be discussed from several perspectives.
The most common classification is based on the level of design:
- High-Level Design — HLD
- Low-Level Design — LLD
We can also discuss different architectural approaches such as:
- Monolithic architecture
- Microservices architecture
- Distributed systems
- Event-driven architecture
These are architectural approaches rather than additional "levels" of HLD/LLD.
5. High-Level Design — HLD
High-Level Design focuses on the overall architecture of the system.
It answers:
What are the major components of the system, and how do they communicate?
For example:
Client
↓
Load Balancer
↓
API Gateway
↓
Application Services
↓
Database
For a larger application:
┌── User Service
│
Client → API Gateway ────┼── Order Service
│
├── Payment Service
│
└── Notification Service
HLD generally discusses:
- System architecture
- Major services
- Databases
- APIs
- Communication
- Load balancing
- Caching
- Message queues
- External services
- Scalability
- Availability
- Security
HLD focuses on the big picture.
6. Low-Level Design — LLD
Low-Level Design focuses on the internal implementation of individual components.
It answers:
How exactly should a component be implemented?
For example, a Spring Boot application might have:
OrderController↓OrderService↓OrderRepository↓PostgreSQL
LLD can involve:
- Classes
- Interfaces
- Methods
- Objects
- Design patterns
- Database entities
- Relationships
- API contracts
- Validation
- Exception handling
For example:
public interface PaymentService {
PaymentResult processPayment(
PaymentRequest request
);
}
We could then have different implementations:
PaymentService
│
┌─────────┴─────────┐
↓ ↓
StripePaymentService RazorpayPaymentService
HLD tells us what the major pieces are and how they interact.
LLD tells us how individual pieces are implemented.
7. Other System Architecture Approaches
System Design also involves choosing an appropriate architectural style.
Monolithic Architecture
Everything is deployed as a single application.
Client↓Monolithic Application↓Database
This can be a very good choice for many small and medium-sized systems.
Microservices Architecture
The application is divided into independently deployable services.
Client↓API Gateway↓┌────────────┬────────────┬────────────┐│ User │ Order │ Payment ││ Service │ Service │ Service │└────────────┴────────────┴────────────┘
Microservices can provide independent scaling and deployment, but they also introduce additional operational and distributed-system complexity.
Distributed Systems
Multiple independent machines or services work together to provide a unified system.
Large-scale platforms such as search engines, streaming platforms, social networks, and e-commerce platforms commonly use distributed architectures.
Event-Driven Architecture
Components communicate using events.
For example:
Order Service↓Kafka↓ ↓Payment NotificationService Service
This can help decouple services and support asynchronous processing.
8. Significance of System Design
System Design becomes increasingly important as software grows.
It helps us answer questions such as:
Can the system scale?
Can we handle increasing:
- Users
- Requests
- Data
- Traffic
Can the system remain available?
What happens when:
- A server fails?
- A database becomes unavailable?
- A network connection fails?
Can the system perform efficiently?
Can we reduce:
- Response time
- Database load
- Network overhead
- Processing time
Can the system remain secure?
Can we protect:
- User accounts
- Personal data
- APIs
- Credentials
- Business information
Can the system be maintained?
Can developers:
- Add new features?
- Fix bugs?
- Replace components?
- Deploy changes safely?
System Design forces us to consider the entire system rather than only individual pieces of code.
9. Advantages of System Design
1. Better Scalability
A well-designed architecture can handle increasing workloads more effectively.
2. Better Performance
System Design helps identify potential bottlenecks and choose appropriate solutions.
3. Improved Reliability
Failure scenarios can be considered during the design phase.
4. Improved Availability
Redundancy and fault-tolerant architecture can reduce downtime.
5. Better Maintainability
Well-separated components are easier to understand, test, modify, and maintain.
6. Better Security
Security requirements can be incorporated into the architecture from the beginning.
7. Reduced Development Risk
Important architectural decisions can be evaluated before significant implementation effort is invested.
8. Better Team Collaboration
Developers, architects, database engineers, DevOps engineers, and other stakeholders can work from a shared architectural understanding.
9. Cost Optimization
Good design helps avoid unnecessary infrastructure and operational expenses.
10. Disadvantages and Limitations of System Design
System Design itself is not necessarily a disadvantage.
However, poor or excessive system design can create problems.
1. Increased Complexity
Adding more components can make a system harder to understand and operate.
For example:
Simple:Application → Database
could eventually become:
Client↓API Gateway↓Load Balancer↓Multiple Services↓Kafka↓Redis↓PostgreSQL↓Read Replicas
The second architecture may provide capabilities that the first does not, but it is also more complex.
2. Higher Infrastructure Cost
Additional:
- Servers
- Databases
- Caches
- Message brokers
- Monitoring systems
can increase operational costs.
3. Over-Engineering
One of the most common mistakes is designing for a scale that the application does not actually need.
For example:
Building a highly distributed architecture for an application with only 100 users.
A good architecture should be appropriate for the current requirements and expected growth.
4. Longer Initial Development
Good design requires analysis, discussion, estimation, and planning.
This can increase the initial development effort.
5. Architectural Rigidity
Poor architectural decisions can become expensive to change later.
This is why architectural decisions should be based on requirements and trade-offs.
6. Distributed-System Complexity
Distributed systems introduce additional challenges such as:
- Network failures
- Partial failures
- Data consistency
- Distributed transactions
- Message duplication
- Race conditions
- Observability challenges
11. Common Difficulties in System Design
While designing a system, engineers commonly face several challenges.
Challenge 1 — Unclear Requirements
It is difficult to design a system if we don't understand what the system needs to do.
Solution
Clearly identify:
Functional requirements
What should the system do?
Non-functional requirements
How well should the system do it?
12. Challenge 2 — Unknown Scale
We need to understand the expected workload.
Important questions include:
- How many users?
- How many active users?
- How many requests per second?
- How much data is generated?
- How much storage is required?
- What is the expected peak traffic?
Solution: Capacity Estimation
Suppose:
Daily Active Users = 2,000,000Requests per user per day = 50
Then:
Total requests per day= 2,000,000 × 50= 100,000,000 requests/day
This provides a starting point for estimating infrastructure requirements.
We also need to consider peak traffic, because average traffic can hide significant spikes.
13. Challenge 3 — Single Point of Failure
Suppose the entire application depends on one server:
Application Server↓DOWN↓Application unavailable
Solution
Introduce redundancy:
┌── Server 1│Load Balancer├── Server 2│└── Server 3
Now one server can fail without necessarily taking down the entire application.
14. Challenge 4 — Database Bottlenecks
As traffic increases, the database can become a bottleneck.
Potential solutions include:
- Proper indexing
- Query optimization
- Connection pooling
- Caching
- Read replicas
- Partitioning
- Sharding
However, these techniques should be introduced based on actual requirements and measured bottlenecks rather than simply because they are popular technologies.
15. Challenge 5 — Data Consistency
Distributed systems may contain multiple services and databases.
We then need to determine:
Should all components see the same data immediately?
or:
Is eventual consistency acceptable?
The correct answer depends on the business requirement.
For example, payment processing generally requires stronger consistency guarantees than a social-media-like counter.
16. Challenge 6 — Communication Failures
In a distributed system:
Service A↓Service B
Service B might:
- Be unavailable
- Respond slowly
- Return an error
- Receive the request but fail before responding
Possible Solutions
- Timeouts
- Retries
- Circuit breakers
- Idempotency
- Message queues
- Dead-letter queues
Each solution has trade-offs and should be used according to the failure scenario.
17. Challenge 7 — Security
Security should be considered during System Design rather than added at the end.
Important areas include:
- Authentication
- Authorization
- Encryption
- Secrets management
- Input validation
- Rate limiting
- API security
- Data protection
- Audit logging
A secure architecture protects both the system and its users.
18. A Practical System Design Problem-Solving Process
A useful System Design process can be summarized as:
1. Understand Requirements↓2. Define Functional Requirements↓3. Define Non-Functional Requirements↓4. Estimate Scale↓5. Design APIs↓6. Design High-Level Architecture↓7. Design Data Storage↓8. Identify Bottlenecks↓9. Design for Failure↓10. Consider Security↓11. Consider Scalability↓12. Evaluate Trade-offs↓13. Monitor and Iterate
This process should not be treated as a rigid checklist.
Real-world system design is iterative.
As we discover new requirements or constraints, the architecture may need to change.
19. The Most Important Concept: Trade-Offs
One of the most important principles in System Design is that there is rarely a single perfect architecture.
Instead, we make decisions based on requirements and trade-offs.
For example:
PostgreSQL vs NoSQL
Which one is better?
There is no universal answer.
It depends on:
- Data model
- Consistency requirements
- Query patterns
- Scale
- Operational requirements
Monolith vs Microservices
Microservices aren't automatically better than a monolith.
A monolith may be the better choice when:
- The team is small.
- The system is relatively simple.
- Independent scaling is not required.
- Operational simplicity is important.
Microservices may become valuable when:
- Services have clear boundaries.
- Independent deployment is valuable.
- Different components need independent scaling.
- Organizational or technical requirements justify the additional complexity.
Synchronous vs Asynchronous Communication
REST APIs may be appropriate when an immediate response is required.
Message queues may be better when work can be processed asynchronously.
Again, the correct choice depends on the problem.
20. The Core Principle of System Design
The most important lesson is:
System Design is not about creating the most complicated architecture. It is about creating the right architecture for the problem.
A good system designer doesn't automatically choose:
- Microservices
- Kafka
- Redis
- Kubernetes
- NoSQL
- Multiple databases
just because they are popular technologies.
Instead, the designer asks:
What problem are we trying to solve?
Then:
What requirements do we have?
Then:
What architecture satisfies those requirements with an appropriate level of complexity and cost?
That is the mindset behind good System Design.
21. What We Will Learn Next
This article provides the foundation for our System Design journey.
In future articles, we can explore topics such as:
- HLD vs LLD
- Scalability
- Availability
- Reliability
- Load Balancing
- Caching
- Database Design
- Database Replication
- Database Sharding
- CAP Theorem
- Consistency Models
- Message Queues
- Apache Kafka
- Redis
- API Gateway
- Microservices
- Event-Driven Architecture
- Distributed Systems
- Rate Limiting
- Fault Tolerance
- Observability
- System Design Case Studies
- Real-world architecture
- System Design interview problems
We will gradually move from fundamentals → architecture → distributed systems → real-world system design.
Conclusion
System Design is one of the most important areas of modern software engineering because building software is not only about making individual features work.
We also need to understand:
How will the entire system behave as users, traffic, data, and complexity increase?
A good system design considers:
Requirements → Architecture → Data → Communication → Scalability → Reliability → Security → Failure → Trade-offs
The goal is not to create the most complicated system.
The goal is to create a system that is appropriate, scalable, reliable, secure, maintainable, and cost-effective for the problem we are solving.
And that is where the real engineering begins.
Connect With Me
If you enjoyed this article and would like to follow my work, feel free to connect with me on the platforms below. I regularly share updates on software development, Java, Spring Boot, web development, open-source projects, and new technical blog posts.
🌐 Portfolio
https://vimaltech.dev
📝 System Design Blog
https://sd.vimaltech.dev
📝 Technical Blog
https://blog.vimaltech.dev


Comments
Post a Comment