One of the major benefits of being introduced to system design is that it has allowed me to rethink the problems I face when building new software for a client. Below are the 14 pillars I now use to structure any system design process, whether in an interview or on a real project.

1. Problem Definition and Scope

This is where you receive the client's problem, identify the system actors, and define the in-scope and out-of-scope requirements. It ensures you don't over-engineer and can stay focused on the core features.

Pro-tip: On a real project, divide the system into major features at this stage and re-apply the 14 pillars by defining each feature's separate problem space.

2. Functional Requirements

Take the problem, the actors, and the in-scope items to define the sub-features that must be included to make the system work end-to-end, as well as the nice-to-have features that serve as good additions.

3. Non-Functional Requirements (NFRs)

NFRs are the unstated requirements, not explicitly requested by the client, but crucial for the system to perform well in production. They revolve around 6 axes:

  • Performance & Scalability: keeping the system fast as users grow. Performance is speed for a single user (latency, response time). Scalability is handling volume (throughput, 10× more users without crashing).
  • Reliability & Resilience: ensuring minimal downtime, proportional to the criticality of the system.
  • Maintainability & Extensibility: tools to supervise and monitor every time a new feature, bottleneck, or update is introduced.
  • Security & Compliance: preventing unauthorized access, ensuring correct behavior, and providing proper fallback mechanisms.
  • Portability & Interoperability: running on multiple architectures and remaining backward-compatible from a hardware perspective.
  • Usability: ease of navigation for end users (UI/UX) and developers (APIs) alike.

Mnemonic: Please Remember My Secure Portable UI (Performance, Reliability, Maintainability, Security, Portability, Usability).

4. Back-of-the-Envelope Estimation

Estimate the data traffic entering and leaving the system, the expected latency, throughput, and storage requirements for both disk and RAM. This depends entirely on the use case: a video platform like YouTube needs high storage capacity and low streaming latency, while a URL shortener is compute-light but read-heavy.

5. API Design

Define the inputs and outputs of the functions that must be implemented to achieve your goals. These could be HTTP endpoints or standard function signatures. This is the first concrete implementation layer of your functional requirements.

6. High-Level Architecture

Show the main actors and their interactions with system components that contribute to both functional and non-functional requirements: load balancers, microservice boundaries, database types, message queues, CDN nodes, and hardware topology.

7. Data Model

Define how data looks in storage. This is especially important for SQL databases where you map out tables, relationships, and schemas, but equally relevant for document stores where you design your embedding and denormalization strategy up front.

8. Core Flows End-to-End

Trace the traversal of data through the system for each trigger, caused by an actor action or a cron job. List all paths: the happy path, edge cases, and failure scenarios. This is where paper designs get stress-tested.

9. Caching and Read Performance

Technologies used to fulfill non-functional requirements around latency. This includes infrastructure-level CDNs and in-memory caches like Redis to accelerate data retrieval and reduce pressure on primary storage.

10. Storage, Indexing, and Media

Choose the right technology for fast access to persistent storage based on the nature of what you store and how quickly you need to access it, including full-text search indexes, blob storage for media, and tiered archival strategies.

11. Scaling Strategies

What happens when you go beyond the estimated traffic, data volume, or user count? This step decides whether to change the technology stack or apply specific engineering concepts: sharding, horizontal scaling, read replicas, or event-driven decoupling.

12. Reliability, Failure Handling, and Backpressure

How does the system behave under pressure, undefined inputs, or cascading errors? This covers circuit breakers, retry policies, dead-letter queues, and backpressure mechanisms that prevent a slow component from taking down the entire system.

13. Security, Privacy, and Abuse

Harden the obvious attack surfaces first: authentication, authorization, rate limiting, input validation. Design the system so security improvements can be layered on iteratively as new features are added.

14. Bottlenecks and Next Steps

Step back and ask: where are the weak points? Were the communication protocols the right choice? Where does the system break first under load? This pillar is about continuous evaluation.