Frequently Asked Questions About Simonyan System Design Architecture Skill

21 answers covering everything from basics to advanced usage.

// Basics

What is horizontal scaling and why is it preferred over vertical scaling?

Horizontal scaling (scale out) adds more servers to share load, providing fault tolerance and theoretically unlimited growth. Vertical scaling (scale up) adds more RAM or CPU to a single server — it is simpler but hits a hard resource cap and creates a single point of failure with no redundancy. For high-traffic applications, horizontal scaling is almost always the correct long-term strategy.

What is a single point of failure in system design?

A single point of failure (SPOF) is any component whose failure alone causes the entire system to go down. Common SPOFs include a single database server, a single load balancer, or a single application server. Eliminate them through redundancy (multiple instances), health checks (continuous monitoring), and self-healing systems (automatic replacement of failed instances).

What is ACID and when does it matter for database selection?

ACID stands for Atomic, Consistent, Isolated, and Durable — the four guarantees of SQL database transactions. Atomic means all-or-nothing execution. Consistent means valid state transitions. Isolated means concurrent transactions don't interfere. Durable means data persists after failure. ACID matters for banking, finance, e-commerce orders, and any domain where data integrity is non-negotiable.

What is the difference between TCP and UDP and when do I choose each?

TCP guarantees ordered, reliable delivery via a three-way handshake (SYN → SYN-ACK → ACK). Use it for payments, authentication, user data, and anything where packet loss is unacceptable. UDP sends packets without delivery guarantees, ordering, or handshaking — it is faster and lower-overhead. Use it for video calls, gaming, and live streams where speed matters more than guaranteed delivery and some packet loss is tolerable.

What is overfetching and how does GraphQL solve it?

Overfetching is a REST API problem where the server returns more data than the client needs for a given view, wasting bandwidth and increasing response times. For example, a mobile app displaying a user's name receives the user's entire profile. GraphQL solves this by letting the client specify exactly which fields to return in the query, so the response contains only the requested data — no more, no less.

// How To

How do I design a REST API that follows best practices?

Model resources as plural nouns (e.g., /products, not /getProducts). Use proper HTTP methods: GET for reads, POST for creates, PUT for full replacements, PATCH for partial updates, DELETE for removals. Return correct status codes (200, 201, 400, 401, 404, 500). Add versioning (/api/v1/). Support filtering via query parameters, sorting, and pagination on all list endpoints. Enforce authentication, authorization, rate limiting, and input validation.

How do I separate the web tier from the data tier?

Place your application servers (web tier) on separate machines or containers from your database servers (data tier). The web tier handles incoming HTTP requests from web and mobile clients. The data tier manages database reads and writes. This separation lets each tier scale independently — you can add more app servers for traffic spikes without touching the database infrastructure, and vice versa.

How do I eliminate single points of failure in my architecture?

Apply three strategies to every critical component: redundancy (run multiple instances of load balancers, databases, and caches), health checks (continuously probe components and stop routing to failed ones), and self-healing (auto-replace failed instances with fresh ones). For databases, use replication. For load balancers, deploy pairs in active-passive or active-active configurations. Never assume any single component is infinitely reliable.

How do I decide between REST, GraphQL, and gRPC for my API?

Use REST for standard web and mobile apps where simplicity and cacheability matter. Use GraphQL for complex UIs that need flexible, precise queries with minimal round trips — but enforce query depth limits to prevent DoS attacks. Use gRPC for high-performance microservice-to-microservice communication where low latency and strong typing matter — but avoid it for browser-facing APIs because most browsers lack full HTTP/2 support.

// Troubleshooting

Why is my system design interview answer scoring as junior-level?

The most common reason is omitting trade-off articulation. Naming the right technology (e.g., 'use Cassandra') without explaining what you gain (massive write throughput) and what you give up (eventual consistency, no ACID transactions) is a junior-level answer. Senior-level answers explicitly state trade-offs for every major decision. Other issues include skipping the single-server baseline, ignoring pagination, and not addressing single points of failure.

Why is my REST API slow at scale?

Common causes include missing pagination on list endpoints (returning all records at once wastes bandwidth), no caching strategy (every request hits the database), overfetching (returning more data than clients need), and too many round trips (clients making multiple sequential API calls). Fix with cursor-based pagination, Redis caching for hot data, field selection or GraphQL for precise responses, and co-locating related data to reduce round trips.

What if my load balancer becomes a single point of failure?

A single load balancer is itself a SPOF. Deploy load balancers in redundant pairs — either active-passive (standby takes over on failure) or active-active (both handle traffic simultaneously). Use health checks between the load balancers. Cloud providers like AWS offer managed load balancers (ALB, NLB) with built-in redundancy and self-healing. Never rely on a single load balancer instance in production.

// Comparisons

How does the Simonyan System Design framework compare to Grokking the System Design Interview?

Grokking the System Design Interview focuses on solving specific design problems (e.g., design Twitter, design a URL shortener) with worked examples. The Simonyan framework provides a reusable, principle-driven methodology applicable to any system — emphasizing the workflow of decisions (baseline → tiers → database → scaling → load balancing → APIs → trade-offs) rather than memorizing specific system solutions. The two approaches complement each other: use Simonyan's framework as your thinking process and Grokking for practice problems.

How does this framework differ from just reading the System Design Primer on GitHub?

The System Design Primer is a comprehensive reference covering many topics broadly. The Simonyan framework is a structured workflow — a step-by-step decision sequence you follow in order. It tells you when to make each decision (database before scaling, scaling before load balancing, API style before API contract) and forces trade-off articulation at every step. The Primer gives you knowledge; the Simonyan framework gives you a repeatable process for applying that knowledge.

When should I use WebSockets versus AMQP for async communication?

WebSockets are for real-time bidirectional communication between a client and server — chat apps, live notifications, live dashboards. AMQP is for asynchronous message queuing between backend services — decoupling a producer (e.g., web app generating events) from a consumer (e.g., recommendation processor). WebSockets face the client; AMQP operates behind the scenes between microservices.

// Advanced

How do I apply consistent hashing in a distributed system?

Consistent hashing places servers and keys on a virtual hash ring. Each key is assigned to the nearest server clockwise on the ring. When a server is added or removed, only the keys between the affected server and its predecessor are redistributed — minimizing disruption. Use it for distributed caches (like Memcached clusters), sharded databases, and any system requiring session affinity with graceful scaling.

How do I handle database replication as part of eliminating single points of failure?

Deploy database replicas in a primary-replica (master-slave) configuration: the primary handles writes, replicas handle reads. If the primary fails, promote a replica to primary. For higher availability, use multi-primary replication where multiple nodes accept writes — but this introduces conflict resolution complexity. The trade-off is replication lag (replicas may serve slightly stale data) versus availability. State this trade-off explicitly in interviews.

What is contract-first API design and when should I use it?

Contract-first design means defining the API's request and response shapes before writing any implementation code. You specify endpoints, methods, parameters, status codes, and data types in a specification (like OpenAPI/Swagger for REST or a schema for GraphQL). Use it in team environments where frontend and backend develop in parallel, and in interviews to demonstrate structured thinking. It prevents integration surprises and aligns teams early.

Can I use this framework for microservices migration from a monolith?

Yes. Start at step 1 by documenting the monolith's current single-server baseline and request flows. In step 2, identify which components should become separate services based on independent scaling needs. Use step 3 for per-service database selection. Apply step 7 to choose inter-service protocols (gRPC for synchronous, AMQP for async). Step 10's trade-off articulation is critical: microservices add network latency and operational complexity in exchange for independent deployability and scaling.

How do I handle GraphQL security and prevent abuse?

Enforce query depth limits to prevent denial-of-service via deeply nested queries. Use query complexity analysis to reject queries exceeding a cost threshold. Implement rate limiting per client. Always validate and sanitize inputs in mutations. Use authentication and authorization at the resolver level, not just at the endpoint. Remember that GraphQL always returns HTTP 200 — errors live in the response body's errors field, so monitor that field for security issues.

Should I use cursor-based or offset-based pagination?

Offset-based pagination (page+limit or offset+limit) is simpler but degrades on large datasets because the database must skip all preceding rows. Cursor-based pagination uses a pointer (cursor) to the last item returned, making it consistently fast regardless of dataset size. Use offset-based for small, relatively static datasets. Use cursor-based for large, frequently updated datasets like social media feeds. Always implement one of them — returning all results is never acceptable at scale.