coderain guide

System Design Mock Interviews: Practice Questions and Answers

System design interviews are a critical part of the technical hiring process for roles like Software Engineer, SRE, or Technical Product Manager. They assess your ability to design scalable, reliable, and efficient systems—skills that go beyond coding to solving real-world engineering challenges. However, system design is not just about memorizing solutions; it requires *practice* to think through trade-offs, communicate ideas clearly, and adapt to ambiguous requirements. **Mock interviews** are the best way to simulate the pressure of a real interview, refine your problem-solving approach, and identify gaps in your knowledge. In this blog, we’ll break down how to approach system design mock interviews, walk through 5 common practice questions with detailed answers, and share tips to maximize your preparation. Whether you’re a new grad or a seasoned engineer, this guide will help you ace your next system design interview.

Table of Contents

  1. Why System Design Mock Interviews Matter
  2. How to Structure a System Design Mock Interview
  3. Practice Questions and Detailed Answers
  4. How to Practice Effectively
  5. Common Mistakes to Avoid
  6. Conclusion
  7. References

Why System Design Mock Interviews Matter

System design interviews are notoriously open-ended. Unlike coding interviews, there’s no single “correct” answer—success depends on how you approach the problem: clarifying requirements, prioritizing constraints, and justifying trade-offs. Mock interviews help you:

  • Simulate pressure: Real interviews have time limits (typically 45–60 minutes). Mock sessions train you to stay calm and focused under time constraints.
  • Refine communication: Interviewers evaluate not just your technical skills, but your ability to explain complex ideas to non-technical stakeholders. Mock interviews help you practice articulating decisions.
  • Identify blind spots: A peer or mentor can point out gaps (e.g., ignoring scalability, overlooking data consistency) that you might miss alone.
  • Build confidence: Regular practice turns vague concepts (e.g., “use a cache”) into concrete, actionable strategies (e.g., “use Redis with a TTL of 1 hour for frequent queries”).

How to Structure a System Design Mock Interview

A typical system design interview follows this flow. Use this structure in your mock sessions to mirror real-world scenarios:

1. Requirements Clarification (5–10 mins)

Start by asking questions to define the problem scope:

  • Functional requirements: What features must the system support? (e.g., “Does the URL shortener need custom short links?”)
  • Non-functional requirements: What are the scalability, reliability, and performance constraints? (e.g., “How many users? What’s the expected QPS?”)
  • Edge cases: What about rare scenarios? (e.g., “What happens if a user uploads a 10GB file?”)

2. High-Level Design (10–15 mins)

Outline the core components of your system using a diagram. Focus on:

  • Major services (e.g., “user service,” “feed service”).
  • Data flow (e.g., “user posts → API → database → cache → client”).
  • Technology choices (e.g., “use PostgreSQL for relational data, Redis for caching”).

3. Detailed Design (15–20 mins)

Dive into specific components:

  • Database schema (e.g., “users table: user_id (PK), name, email”).
  • API endpoints (e.g., POST /api/shorten for URL shortening).
  • Algorithms or protocols (e.g., “use WebSockets for real-time chat”).

4. Scalability & Trade-Offs (5–10 mins)

Discuss how the system handles growth:

  • Scaling strategies: Horizontal vs. vertical scaling, sharding, replication.
  • Trade-offs: Consistency vs. availability (CAP theorem), latency vs. cost (e.g., using a CDN adds cost but reduces latency).

Practice Questions and Detailed Answers

Below are 5 common system design questions, with step-by-step answers to guide your mock sessions.

Question 1: Design a URL Shortener

Scenario: Build a service that converts long URLs (e.g., https://example.com/blog/system-design) into short URLs (e.g., https://short.xyz/abc123).

Step 1: Requirements Clarification

  • Functional: Shorten URLs, redirect short URLs to original, (optional) custom short links, analytics (clicks per URL).
  • Non-functional: Low latency (redirects must be fast), high availability (99.99% uptime), scalability (100M new URLs/month, 10B redirects/month).
  • Constraints: Short URLs must be unique and as short as possible (6–8 characters).

Step 2: High-Level Design

Key components:

  • API Layer: Handles POST /shorten (create short URL) and GET /{short_code} (redirect).
  • URL Generator: Creates unique short codes (e.g., abc123).
  • Database: Stores mappings between short codes and original URLs.
  • Cache: Speeds up redirects by caching frequent short codes.

Step 3: Detailed Design

URL Generation

To create short codes, use base62 encoding:

  • Map each short code to a unique integer ID (e.g., 123456 → dnh in base62).
  • Use an auto-incrementing counter (e.g., a database sequence) to generate unique IDs.
  • Why base62? It uses 62 characters (a-z, A-Z, 0-9), so 6 characters = 62⁶ ≈ 56 billion unique URLs—enough for most use cases.

Edge case: Hash collisions (two long URLs mapping to the same short code). Mitigate by checking the database for existing codes and regenerating if needed.

Database Schema

Use a NoSQL database (e.g., MongoDB) for scalability, or a relational database (e.g., PostgreSQL) with sharding. Schema:

Table: url_mappings  
- short_code (PK): string (6 chars)  
- original_url: string (long)  
- created_at: timestamp  
- user_id: (optional, for custom links)  
Caching

Most redirects are read-heavy (10B redirects/month). Use Redis to cache frequent short codes with a TTL (e.g., 24 hours). This reduces database load and speeds up redirects.

API Endpoints
  • POST /api/shorten: Accepts original_url and optional custom_code. Returns short_url.
  • GET /{short_code}: Looks up short_code in cache → if miss, check database → redirect with 301 Moved Permanently (for SEO) or 302 Found (temporary).

Step 4: Scalability & Trade-Offs

  • Scaling the database: Shard by short_code (e.g., split into 62 shards, one per first character) to distribute load.
  • Handling traffic spikes: Use a load balancer (e.g., NGINX) to distribute requests across multiple API servers.
  • Trade-offs:
    • 301 vs. 302: 301 (permanent) is cached by browsers, reducing server load, but analytics will undercount (since browsers skip the redirect). Use 302 if accurate click tracking is critical.
    • Custom short codes: Increase user satisfaction but require checking for duplicates (adds latency).

Question 2: Design a Social Media Feed (e.g., Twitter Timeline)

Scenario: Build a system that displays a user’s feed of posts from accounts they follow (e.g., “Your Home Timeline”).

Step 1: Requirements Clarification

  • Functional: Post tweets, view home timeline, like/retweet posts.
  • Non-functional: Low latency (timeline loads in <200ms), high availability, scalability (100M daily active users, 500M tweets/day).
  • Constraints: Users follow up to 5000 accounts; timeline should show recent posts first (sorted by timestamp).

Step 2: High-Level Design

Key components:

  • Post Service: Handles creating/retrieving tweets.
  • Timeline Service: Generates and caches user timelines.
  • Database: Stores tweets, user data, and follow relationships.

Step 3: Detailed Design

Timeline Generation: Push vs. Pull Model

Two approaches to build timelines:

  • Pull model (on-demand): When a user loads their timeline, fetch recent tweets from all followed accounts and merge them.

    • Pros: Simple, no precomputation.
    • Cons: Slow for users with many followers (e.g., a user following 5000 accounts must query 5000 data sources).
  • Push model (precomputed): When a user posts a tweet, push it to the timelines of all their followers.

    • Pros: Timelines are precomputed, so loading is fast.
    • Cons: Resource-heavy for celebrities (e.g., a user with 100M followers would trigger 100M writes).

Hybrid solution: Use push for most users, pull for celebrities. For example:

  • If a user has <10k followers: push tweets to their followers’ timelines.
  • If >10k followers: pull tweets on-demand when followers load their timeline.
Data Storage
  • Tweets: Use a column-family database (e.g., Cassandra) for high write throughput. Schema:
    Table: tweets  
    - tweet_id (PK): UUID  
    - user_id: string  
    - content: text  
    - timestamp: datetime  
    - likes/retweets: counters  
  • Followers/Following: Use a graph database (e.g., Neo4j) or Redis sorted sets to track relationships.
Caching Timelines

Store timelines in Redis sorted sets (sorted by timestamp) for fast retrieval. Example:

  • Key: timeline:{user_id}
  • Value: Sorted set of tweet_ids, scored by timestamp.

Step 4: Scalability & Trade-Offs

  • Sharding: Shard tweet data by user_id to distribute read/write load.
  • CDN for media: Store images/videos in a CDN (e.g., Cloudflare) to reduce latency.
  • Trade-offs:
    • Push model latency: For users with many followers, pushing tweets may take seconds. Use a message queue (e.g., Kafka) to process pushes asynchronously.
    • Timeline freshness: Precomputed timelines may not include the latest tweets. Add a “pull latest” button to fetch new posts on demand.

Question 3: Design a Real-Time Chat Application

Scenario: Build a chat app supporting one-on-one, group chats, and message history (e.g., WhatsApp, Slack).

Step 1: Requirements Clarification

  • Functional: Send/receive messages (text/media), group chats (up to 100 users), message history, read receipts.
  • Non-functional: Low latency (<1s delivery), high availability, durability (messages not lost).
  • Constraints: Support 100M daily active users, 10B messages/day.

Step 2: High-Level Design

Key components:

  • WebSocket Server: For real-time message delivery (bidirectional communication).
  • REST API: For fetching message history, user profiles.
  • Message Queue: For reliable delivery (e.g., Kafka, RabbitMQ).
  • Database: Stores messages, user data, chat metadata.

Step 3: Detailed Design

Real-Time Communication

Use WebSockets (or Socket.io for fallback) instead of HTTP polling:

  • Clients connect to a WebSocket server, which maintains persistent connections.
  • For group chats, use a pub/sub system (e.g., Redis Pub/Sub): When a user sends a message, the server publishes it to a channel, and all group members subscribe to the channel.
Message Delivery
  • Flow: User sends message → WebSocket server → message queue (to ensure durability) → database → delivered to recipients via WebSocket.
  • Guarantees: Use at-least-once delivery (retry failed sends) to prevent message loss.
Database Schema
  • Messages: Store in a time-series database (e.g., InfluxDB) or Cassandra (for scalability). Schema:
    Table: messages  
    - chat_id (PK): UUID (group or one-on-one chat)  
    - message_id (PK): UUID  
    - sender_id: string  
    - content: text/media URL  
    - timestamp: datetime  
    - status: read/unread  
  • Chats: Track participants in group chats. Use a relational database (e.g., PostgreSQL) for joins:
    Table: chat_participants  
    - chat_id (FK): UUID  
    - user_id (FK): string  

Step 4: Scalability & Trade-Offs

  • Horizontal scaling: Add more WebSocket servers behind a load balancer (use sticky sessions to keep clients connected to the same server).
  • Handling offline users: Store undelivered messages in the database and send them when the user reconnects.
  • Trade-offs:
    • WebSocket vs. HTTP long polling: WebSockets are more efficient for real-time, but some networks block WebSockets. Use Socket.io for automatic fallback to long polling.
    • Media messages: Compress images/videos before sending to reduce bandwidth. Use a CDN for media delivery.

Question 4: Design a File Storage System (e.g., Google Drive)

Scenario: Build a system for uploading, storing, and sharing files (documents, images, videos).

Step 1: Requirements Clarification

  • Functional: Upload/download files, share with users/groups, version history, search files.
  • Non-functional: Durability (99.999% uptime), scalability (1B users, 10PB total storage), low latency for downloads.
  • Constraints: Support files up to 100GB; minimize storage costs.

Step 2: High-Level Design

Key components:

  • Object Storage: Stores raw file data (e.g., S3, Google Cloud Storage).
  • Metadata Service: Manages file metadata (name, size, owner, permissions).
  • CDN: Caches frequently accessed files for fast downloads.
  • Search Service: Indexes metadata for fast file search (e.g., Elasticsearch).

Step 3: Detailed Design

File Upload/Download
  • Upload flow:
    1. Client splits large files into chunks (e.g., 5MB) to avoid retransmitting on failure.
    2. Chunks are uploaded to object storage via a presigned URL (temporary, secure URL).
    3. Metadata service records the file’s chunk IDs, size, and checksum.
  • Download flow:
    1. Client requests file → metadata service returns chunk IDs and presigned URLs.
    2. Client downloads chunks in parallel and reassembles the file.
Metadata Storage

Use a relational database (e.g., PostgreSQL) for structured metadata:

Table: files  
- file_id (PK): UUID  
- name: string  
- owner_id: string  
- size: bigint  
- created_at: timestamp  
- chunk_ids: array<string> (list of object storage keys)  
- permissions: json (e.g., {"user:123": "read", "group:456": "write"})  
Sharing Files
  • Generate a shareable link with permissions (view/edit). Embed the link in a token (e.g., JWT) to avoid database lookups.
  • For group sharing, use a group service to map group IDs to user IDs (check permissions at download time).

Step 4: Scalability & Trade-Offs

  • Durability: Replicate files across 3+ regions (object storage typically does this automatically).
  • Cost optimization: Use tiered storage (e.g., “hot” for recent files, “cold” for archives with higher latency but lower cost).
  • Trade-offs:
    • Consistency vs. availability: Use eventual consistency for metadata (e.g., search indexes may lag by 5 mins) to improve availability.
    • Chunk size: Smaller chunks (1MB) reduce retransmission on failure but increase metadata overhead. Larger chunks (50MB) reduce overhead but are slower to upload.

Question 5: Design a Rate Limiter

Scenario: Build a rate limiter to prevent abuse (e.g., too many API requests from a single user).

Step 1: Requirements Clarification

  • Functional: Limit requests per user (e.g., 100 requests/minute), block excess requests.
  • Non-functional: Low latency (add <1ms to requests), distributed (works across multiple API servers).
  • Constraints: Support 100k QPS; track limits for 10M users.

Step 2: High-Level Design

Key components:

  • Rate Limiter Service: Enforces limits using an algorithm (e.g., token bucket, fixed window).
  • Redis: Stores request counts (in-memory, fast for distributed systems).

Step 3: Detailed Design

Rate Limiting Algorithms

Choose an algorithm based on strictness:

  • Fixed window: Track requests in 1-minute windows (e.g., “100 requests between 2:00–2:01”). Simple but allows “bursting” (99 requests at 2:00:59, 100 at 2:01:00 = 199 in 2 seconds).
  • Sliding window: Split the window into intervals (e.g., 60 1-second intervals per minute). More precise but complex.
  • Token bucket: Users get tokens at a fixed rate (e.g., 100 tokens/minute). Each request consumes a token; refills over time. Allows short bursts (uses stored tokens).
Implementation with Redis

Use Redis to track request counts/distributed tokens:

  • Fixed window example:
    def is_allowed(user_id, limit=100, window=60):
        key = f"rate_limit:{user_id}:{int(time.time()/window)}"  # e.g., "rate_limit:123:16200000"
        count = redis.incr(key)
        if count == 1:
            redis.expire(key, window)  # Auto-delete after window
        return count <= limit
  • Token bucket example: Use redis.decr to consume tokens; refill with a background job.

Step 4: Scalability & Trade-Offs

  • Distributed rate limiting: Redis cluster ensures all API servers see the same request counts.
  • Race conditions: Use Redis INCR (atomic) to avoid double-counting.
  • Trade-offs:
    • Strictness vs. performance: Sliding window is precise but requires more Redis operations. Use fixed window for simplicity.
    • Exceeding limits: Return 429 Too Many Requests with a Retry-After header to guide clients.

How to Practice Effectively

  • Find a partner: Use platforms like Pramp, interviewing.io, or Meetup to connect with peers.
  • Use tools: Draw diagrams with Miro/FigJam; simulate Redis/database interactions with code snippets.
  • Time yourself: Set a 45-minute timer for each mock interview to practice pacing.
  • Review and iterate: After each session, debrief with your partner. Ask: “Did I clarify requirements? Miss any scalability issues?”

Common Mistakes to Avoid

  • Jumping into design too early: Spend 5–10 minutes clarifying requirements before drawing diagrams.
  • Ignoring non-functional requirements: Interviewers care about scalability, reliability, and latency as much as features.
  • Over-engineering: You don’t need to design for 1B users if the problem specifies 10k. Tailor complexity to constraints.
  • Poor diagramming: Use clear labels (e.g., “API Server” vs. “Server A”). Avoid messy, unlabeled boxes.

Conclusion

System design mock interviews are the bridge between theoretical knowledge and real-world problem-solving. By practicing with realistic questions, refining your communication, and learning from feedback, you’ll turn “I think I need a cache” into “I’ll use Redis with a TTL of 1 hour for frequent queries, sharded by user ID to scale.”

Remember: The goal isn’t perfection—it’s to show you can break down complex problems, prioritize constraints, and justify decisions. With consistent practice, you’ll approach your next interview with confidence.

References

  • Books: System Design Interview (Alex Xu), Designing Data-Intensive Applications (Martin Kleppmann).
  • Courses: Grokking the System Design Interview (educative.io), System Design Fundamentals (ByteByteGo).
  • Tools: Miro (diagramming), Redis (caching/rate limiting), Kafka (message queues).
  • Platforms: Pramp (free mock interviews), interviewing.io (tech-focused mock interviews).