Types of System Design
Overview
When engineers talk about "system design" they are actually talking about three distinct but complementary disciplines. Each one asks a different question, operates at a different level of abstraction, and produces a different kind of artefact.
| Type | Central question | Primary output |
|---|---|---|
| Product Design | What should the system do and how will users interact with it? | Requirements, API contracts, data models, user flows |
| Infrastructure Design | How do we make it fast, reliable, and scalable at real-world load? | Architecture diagrams, capacity estimates, technology choices |
| OO Design | How should the code be structured internally? | Class diagrams, interfaces, module boundaries, design patterns |
A production system needs all three. A feature with brilliant infrastructure but no clear product requirements ships the wrong thing. A well-structured codebase on a single server collapses under real load. And a scalable cluster full of tangled, untestable code becomes a maintenance nightmare. The three lenses are complementary, not interchangeable.
Product Design
Product Design — also called functional system design — is concerned with the behaviour of the system from the perspective of its users and clients. It answers questions like: Who uses this? What can they do? What data does the system manage? What guarantees does it make to callers?
This is the first design step. Getting it wrong means building the right infrastructure for the wrong product. Everything else is downstream of it.
What it covers
- Requirements gathering — Functional requirements define what the system must do ("users can post and like content"). Non-functional requirements define how well it must do it ("99.9% availability, p99 latency under 200 ms"). Clarifying both upfront prevents scope creep and wrong architectural choices later.
- User and actor identification — Who are the clients? End users via a browser? Mobile apps? Other backend services? Each actor may have different latency tolerances, data access patterns, and trust levels.
- Core entities and data model — What are the main nouns in the domain? A ride-sharing app has Rider, Driver, Trip, and Payment. Identifying entities and their relationships early shapes the database schema, API surface, and service boundaries.
- API design — The public contract between the system and its callers. Defines endpoints (REST, GraphQL, gRPC), request/response shapes, error codes, authentication mechanism, and versioning strategy.
- Core user flows — Tracing the critical paths end-to-end. For a payment system: how does a charge go from button click to bank confirmation? Walking through flows exposes missing requirements, edge cases, and failure modes before any code is written.
- Capacity estimation (back-of-envelope) — How many users? How many requests per second? How much data per day? These numbers feed directly into infrastructure decisions — whether a single database is sufficient or whether sharding is necessary.
Typical interview framing
Product Design questions sound like: "Design Twitter", "Design a URL shortener", or "Design a notification service". The interviewer is looking for how you scope the problem, define the MVP, and arrive at a concrete API before talking about any infrastructure. Jumping straight to infrastructure without establishing requirements is one of the most common interview mistakes.
A strong answer to "Design a URL shortener" covers:
- Clarify scope — read/write ratio, expected scale, custom aliases, expiry?
- Entities —
ShortUrlwith fields:id,originalUrl,shortCode,createdAt,expiresAt. - API —
POST /urls→ returns short code;GET /{shortCode}→ redirects. - Back-of-envelope — 100 M URLs, 1 KB each ≈ 100 GB total; 10 K reads/sec, 100 writes/sec → read-heavy.
Only after this is settled does it make sense to talk about databases, caching, and load balancing.
Infrastructure Design
Infrastructure Design is concerned with the deployment topology of the system — how services are arranged, how data flows between them, how the system handles load spikes, hardware failures, and network partitions. It operates at the level of servers, databases, queues, and network links, not lines of code.
This is where scalability, availability, and fault tolerance are designed in — not bolted on after the fact.
What it covers
- Scalability — How does the system handle 10× the current load? Vertical scaling (bigger machines) is simple but has a ceiling. Horizontal scaling (more machines) requires stateless services and introduces the need for load balancers, distributed state, and coordination.
- Load balancing — Distributes incoming traffic across multiple server instances. Strategies include round-robin, least-connections, and consistent hashing (important when session affinity or cache locality matters).
- Caching — Stores frequently read data in fast memory (Redis, Memcached) to reduce database load. Key decisions: cache-aside vs write-through, TTL, eviction policy (LRU, LFU), and cache invalidation strategy.
- Databases and storage — SQL vs NoSQL depends on query patterns, consistency requirements, and scale. Techniques include read replicas (scale reads), sharding (scale writes and storage), and denormalization (optimize for read-heavy workloads).
- Message queues and async processing — Queues (Kafka, RabbitMQ, SQS) decouple producers from consumers, absorb traffic spikes, and enable retry logic. Critical for operations that can be deferred — email sending, image resizing, analytics.
- Content Delivery Networks (CDN) — Cache static assets (images, JS, CSS) at edge nodes close to users, reducing latency and origin server load.
- Fault tolerance and availability — Replication ensures data survives hardware failure. Circuit breakers prevent cascading failures when a downstream service is degraded. Health checks and auto-restarts recover failed instances automatically.
- CAP theorem trade-offs — In a distributed system you can guarantee at most two of: Consistency, Availability, Partition tolerance. Most real systems choose between CP (consistent but may reject requests during a partition) and AP (always available but may return stale data).
Typical interview framing
Infrastructure questions are usually the second half of a product design question once the API and data model are settled. A strong answer to "how would you scale the URL shortener to 1 billion redirects per day?" covers:
- Add a CDN — the redirect response is the same for every user; cache it at the edge.
- Read replicas — redirect lookups are reads; replicate the DB and route reads to replicas.
- Cache hot short codes in Redis with a TTL — most traffic hits a small number of popular links.
- Shard the database by the first character of the short code if write volume grows.
- Use a message queue to handle analytics writes asynchronously — don't block the redirect on it.
Object-Oriented Design
Object-Oriented Design (OOD) — sometimes called low-level design or class-level design — is concerned with the internal structure of the code. While product design defines what the system does and infrastructure design defines how it is deployed, OOD defines how the code is organized: which classes exist, what they are responsible for, how they communicate, and which design patterns apply.
Good OOD makes a codebase maintainable, testable, and extendable by a team over time. Poor OOD produces a system that works on day one but becomes increasingly painful to change — regardless of how well-scaled the infrastructure is.
What it covers
- Class and interface design — Identifying the core abstractions of the domain and their relationships. A parking lot system has ParkingLot, Floor,Spot, Vehicle, and Ticket. Getting the nouns right is the foundation everything else rests on.
- SOLID principles — The five principles that guide class design: Single Responsibility (one reason to change), Open/Closed (extend without modifying), Liskov Substitution (subtypes are substitutable), Interface Segregation (small focused interfaces), and Dependency Inversion (depend on abstractions).
- Design patterns — Reusable structural templates for recurring design problems. Choosing the right pattern — Factory, Strategy, Observer, Decorator — reduces coupling and makes the code easier to reason about and extend.
- Encapsulation and information hiding — Each class exposes only what its callers need. Internal implementation details are private and can change without breaking other classes.
- Module and package boundaries — Grouping related classes into cohesive modules with well-defined public APIs. A change inside one module should not require changes in unrelated modules.
- Testability — Well-designed classes have injected dependencies, no hidden global state, and single responsibilities — making them straightforward to unit test in isolation without spinning up databases or external services.
Typical interview framing
OOD questions sound like: "Design a parking lot system", "Design a chess game", or "Design a library management system". The interviewer is not interested in infrastructure — they want to see how you model a domain with classes and interfaces.
A strong answer to "Design a parking lot" covers:
- Identify entities —
ParkingLot,Floor,Spot(with type: compact/large/handicapped),Vehicle(car/motorcycle/truck),Ticket,Payment. - Define interfaces —
SpotAssignmentStrategyso the algorithm for picking a spot is swappable (Strategy pattern). - Apply SRP —
ParkingLotmanages floors;TicketServicehandles entry/exit;PaymentServicehandles billing. One class, one job. - Apply OCP — adding a new vehicle type or spot type means a new subclass, not a change to existing logic.
How they relate
The three types of system design are not sequential phases — they inform each other iteratively. But there is a natural dependency order: you cannot make good infrastructure decisions without knowing the product requirements, and you cannot design good classes without knowing the domain that the product has defined.
| Question | Design type that answers it |
|---|---|
| What does the system do? | Product Design |
| What are the main entities and API contracts? | Product Design |
| How many requests per second must it handle? | Product Design (feeds into Infrastructure) |
| Where does the data live and how does it flow? | Infrastructure Design |
| How does the system stay up when a server dies? | Infrastructure Design |
| How is the codebase structured internally? | Object-Oriented Design |
| How are classes decoupled so they can be tested? | Object-Oriented Design |
In an interview context, always establish which lens the interviewer wants before diving in. Starting an OOD answer with load balancers, or starting a product design answer with class hierarchies, signals that you are not thinking clearly about the level of abstraction the question is operating at.