InterviewPitch
System Design interview questions

System Design Interview Questions with Answers

Most Asked System Design Interview Questions for Software Engineer Roles

100+ QuestionsDetailed AnswersCode ExamplesUpdated for 2026

Introduction

System design is the process of designing scalable, reliable, secure, and maintainable software systems that can handle real-world business and technical requirements. This comprehensive guide presents 100+ carefully curated System Design interview questions and answers, covering everything from fundamental concepts to advanced distributed-system architecture. You'll learn about scalability, availability, reliability, load balancing, caching, databases, database sharding, replication, partitioning, message queues, API design, microservices, monolithic architecture, distributed systems, CAP theorem, consistency, fault tolerance, rate limiting, authentication, authorization, storage systems, CDNs, monitoring, and system performance. Whether you're preparing for a Software Engineer, Senior Software Engineer, Backend Developer, Full Stack Developer, DevOps Engineer, or System Design interview at a product-based company, this question bank will help you understand how to approach real-world architecture problems. You'll learn how to analyze requirements, estimate system capacity, identify bottlenecks, choose the right technologies, and design systems that can scale efficiently. From designing URL shorteners, notification systems, chat applications, social media platforms, payment systems, file storage services, search systems, and ride-sharing applications to handling millions of users and requests, these System Design interview questions will strengthen your architectural thinking and prepare you for real-world technical interviews. Start practicing now and build the confidence to design scalable systems.

Why Learn System Design?

  • Essential skill for senior software engineering and backend development interviews
  • Learn how to design scalable, reliable, and high-performance software systems
  • Understand core concepts such as load balancing, caching, replication, sharding, and partitioning
  • Master distributed systems concepts including CAP theorem, consistency, availability, and fault tolerance
  • Learn how to choose databases, message queues, storage systems, and other components based on system requirements
  • Develop the ability to analyze scalability, performance, security, reliability, and system bottlenecks
  • Prepare for real-world system design problems commonly discussed in technical interviews
  • Improve architectural thinking and make better technology and design decisions

Most Asked System Design Interview Questions

Beginner
1. What is System Design?

System Design is the process of defining the architecture, components, modules, interfaces, and data for a system to satisfy specified requirements.

  • Scalability: Handle growth in users and data
  • Reliability: System availability and fault tolerance
  • Performance: Response time and throughput
  • Security: Protect data and resources
  • Cost: Infrastructure and operational costs
system-design
// System Design - Load Balancer Example
// Nginx configuration for load balancing
http {
    upstream backend {
        server backend1.example.com weight=3;
        server backend2.example.com weight=2;
        server backend3.example.com weight=1;
    }

    server {
        listen 80;
        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

// Round Robin Load Balancer implementation
class LoadBalancer {
    private servers: string[];
    private currentIndex: number = 0;
    
    constructor(servers: string[]) {
        this.servers = servers;
    }
    
    getNextServer(): string {
        const server = this.servers[this.currentIndex];
        this.currentIndex = (this.currentIndex + 1) % this.servers.length;
        return server;
    }
}
Beginner
2. What is Load Balancing?

Load balancing distributes incoming network traffic across multiple servers to ensure reliability, availability, and performance.

  • Round Robin: Distributes requests sequentially
  • Least Connections: Sends to server with fewest connections
  • IP Hash: Consistent routing based on client IP
  • Weighted: Assigns weights to servers
  • Health checks: Monitor server health
system-design
// System Design - Database Sharding
// Consistent hashing for sharding
class ConsistentHash {
    private ring: SortedMap<number, string>;
    private virtualNodes: number;
    
    constructor(nodes: string[], virtualNodes: number = 150) {
        this.ring = new SortedMap();
        this.virtualNodes = virtualNodes;
        
        for (const node of nodes) {
            this.addNode(node);
        }
    }
    
    addNode(node: string): void {
        for (let i = 0; i < this.virtualNodes; i++) {
            const hash = this.hash(`${node}-${i}`);
            this.ring.set(hash, node);
        }
    }
    
    getNode(key: string): string {
        const hash = this.hash(key);
        const node = this.ring.ceilingEntry(hash);
        return node ? node.value : this.ring.firstEntry().value;
    }
    
    private hash(key: string): number {
        // Hash function implementation
        let hash = 0;
        for (let i = 0; i < key.length; i++) {
            hash = (hash << 5) - hash + key.charCodeAt(i);
            hash = hash & hash;
        }
        return hash;
    }
}
Beginner
3. What is Caching?

Caching stores frequently accessed data in high-speed storage to reduce latency and improve performance.

  • Cache-Aside: Application manages cache
  • Read-Through: Cache reads from database
  • Write-Through: Writes to cache and database
  • Write-Behind: Asynchronous write
  • Cache invalidation: Removing stale data
system-design
// System Design - Caching Strategy
// Cache aside pattern implementation
class CacheAside<K, V> {
    private cache: Map<K, V>;
    private db: Database;
    private ttl: number;
    
    constructor(db: Database, ttl: number = 3600) {
        this.cache = new Map();
        this.db = db;
        this.ttl = ttl;
    }
    
    async get(key: K): Promise<V | null> {
        // Check cache first
        if (this.cache.has(key)) {
            return this.cache.get(key);
        }
        
        // Cache miss - get from DB
        const value = await this.db.get(key);
        if (value) {
            this.cache.set(key, value);
            setTimeout(() => this.cache.delete(key), this.ttl * 1000);
        }
        return value;
    }
    
    async set(key: K, value: V): Promise<void> {
        await this.db.set(key, value);
        this.cache.set(key, value);
    }
    
    invalidate(key: K): void {
        this.cache.delete(key);
    }
}

// Write-through cache
class WriteThroughCache<K, V> {
    private cache: Map<K, V>;
    private db: Database;
    
    constructor(db: Database) {
        this.cache = new Map();
        this.db = db;
    }
    
    async get(key: K): Promise<V | null> {
        return this.cache.get(key) || null;
    }
    
    async set(key: K, value: V): Promise<void> {
        await this.db.set(key, value);
        this.cache.set(key, value);
    }
}
Beginner
4. What is a Message Queue?

A message queue enables asynchronous communication between services, providing decoupling and reliability.

  • Producer: Sends messages
  • Consumer: Receives messages
  • Queue: Stores messages
  • Publish/Subscribe: Broadcast messages
  • Dead Letter Queue: Failed message handling
system-design
// System Design - Message Queue
// Simple message queue implementation
class MessageQueue {
    private queues: Map<string, Queue>;
    private subscribers: Map<string, ((message: any) => void)[]>;
    
    constructor() {
        this.queues = new Map();
        this.subscribers = new Map();
    }
    
    createQueue(name: string): void {
        this.queues.set(name, {
            messages: [],
            consumers: []
        });
        this.subscribers.set(name, []);
    }
    
    publish(queueName: string, message: any): void {
        const queue = this.queues.get(queueName);
        if (!queue) {
            throw new Error(`Queue ${queueName} not found`);
        }
        
        queue.messages.push(message);
        this.notifySubscribers(queueName, message);
        
        // Notify consumers
        for (const consumer of queue.consumers) {
            consumer(message);
        }
    }
    
    subscribe(queueName: string, callback: (message: any) => void): void {
        const subscribers = this.subscribers.get(queueName);
        if (subscribers) {
            subscribers.push(callback);
        }
    }
    
    private notifySubscribers(queueName: string, message: any): void {
        const subscribers = this.subscribers.get(queueName);
        if (subscribers) {
            for (const subscriber of subscribers) {
                subscriber(message);
            }
        }
    }
}

// Kafka-like message broker
class MessageBroker {
    private topics: Map<string, Topic>;
    
    constructor() {
        this.topics = new Map();
    }
    
    createTopic(name: string, partitions: number): void {
        this.topics.set(name, {
            partitions: Array.from({ length: partitions }, (_, i) => ({
                id: i,
                messages: [],
                offset: 0
            })),
            consumers: []
        });
    }
    
    publish(topicName: string, key: string, message: any): void {
        const topic = this.topics.get(topicName);
        if (!topic) {
            throw new Error(`Topic ${topicName} not found`);
        }
        
        const partition = this.getPartition(key, topic.partitions.length);
        topic.partitions[partition].messages.push({
            key,
            value: message,
            timestamp: Date.now()
        });
    }
    
    private getPartition(key: string, numPartitions: number): number {
        return Math.abs(this.hash(key)) % numPartitions;
    }
    
    private hash(key: string): number {
        let hash = 0;
        for (let i = 0; i < key.length; i++) {
            hash = (hash << 5) - hash + key.charCodeAt(i);
            hash = hash & hash;
        }
        return hash;
    }
}
Beginner
5. What is a Distributed Lock?

A distributed lock coordinates access to shared resources across multiple nodes in a distributed system.

  • Redlock: Redis-based distributed lock
  • ZooKeeper: Coordination service
  • Lease: Time-based lock
  • Fencing token: Prevent conflicting writes
  • TTL: Time-to-live for locks
system-design
// System Design - Distributed Lock
// Distributed lock using Redis
class DistributedLock {
    private redis: Redis;
    private lockKey: string;
    private lockValue: string;
    private ttl: number;
    
    constructor(redis: Redis, lockKey: string, ttl: number = 30000) {
        this.redis = redis;
        this.lockKey = lockKey;
        this.lockValue = `${process.pid}-${Date.now()}`;
        this.ttl = ttl;
    }
    
    async acquire(): Promise<boolean> {
        const result = await this.redis.set(
            this.lockKey,
            this.lockValue,
            'NX',
            'PX',
            this.ttl
        );
        return result === 'OK';
    }
    
    async release(): Promise<void> {
        const script = `
            if redis.call("get", KEYS[1]) == ARGV[1] then
                return redis.call("del", KEYS[1])
            else
                return 0
            end
        `;
        await this.redis.eval(script, 1, this.lockKey, this.lockValue);
    }
    
    async execute<T>(fn: () => Promise<T>): Promise<T | null> {
        const acquired = await this.acquire();
        if (!acquired) {
            return null;
        }
        
        try {
            return await fn();
        } finally {
            await this.release();
        }
    }
}

// Redlock algorithm implementation
class Redlock {
    private redisInstances: Redis[];
    private retryCount: number;
    private retryDelay: number;
    
    constructor(redisInstances: Redis[], retryCount: number = 3, retryDelay: number = 100) {
        this.redisInstances = redisInstances;
        this.retryCount = retryCount;
        this.retryDelay = retryDelay;
    }
    
    async lock(resource: string, ttl: number): Promise<Lock | null> {
        const lockValue = `${process.pid}-${Date.now()}`;
        let successCount = 0;
        const quorum = Math.floor(this.redisInstances.length / 2) + 1;
        
        for (let attempt = 0; attempt < this.retryCount; attempt++) {
            const results = await Promise.all(
                this.redisInstances.map(async (redis) => {
                    const result = await redis.set(
                        resource,
                        lockValue,
                        'NX',
                        'PX',
                        ttl
                    );
                    return result === 'OK';
                })
            );
            
            successCount = results.filter(r => r).length;
            
            if (successCount >= quorum) {
                return new Lock(resource, lockValue, ttl, this.redisInstances);
            }
            
            await this.sleep(this.retryDelay);
        }
        
        return null;
    }
}
Beginner
6. What is Rate Limiting?

Rate limiting controls the amount of incoming and outgoing traffic to prevent system overload and ensure fair usage.

  • Token Bucket: Tokens refill over time
  • Leaky Bucket: Constant rate output
  • Sliding Window: Request count per time window
  • Fixed Window: Count per fixed time period
  • Distributed: Rate limiting across nodes
system-design
// System Design - Rate Limiter
// Token bucket rate limiter
class TokenBucketRateLimiter {
    private capacity: number;
    private tokens: number;
    private refillRate: number;
    private lastRefill: number;
    
    constructor(capacity: number, refillRate: number) {
        this.capacity = capacity;
        this.tokens = capacity;
        this.refillRate = refillRate;
        this.lastRefill = Date.now();
    }
    
    allowRequest(): boolean {
        this.refill();
        if (this.tokens >= 1) {
            this.tokens -= 1;
            return true;
        }
        return false;
    }
    
    private refill(): void {
        const now = Date.now();
        const elapsed = (now - this.lastRefill) / 1000;
        const tokensToAdd = elapsed * this.refillRate;
        this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);
        this.lastRefill = now;
    }
}

// Sliding window rate limiter
class SlidingWindowRateLimiter {
    private windowSize: number;
    private maxRequests: number;
    private requests: number[];
    
    constructor(windowSize: number, maxRequests: number) {
        this.windowSize = windowSize;
        this.maxRequests = maxRequests;
        this.requests = [];
    }
    
    allowRequest(): boolean {
        const now = Date.now();
        this.requests = this.requests.filter(
            timestamp => now - timestamp < this.windowSize
        );
        
        if (this.requests.length < this.maxRequests) {
            this.requests.push(now);
            return true;
        }
        return false;
    }
}

// Distributed rate limiter using Redis
class DistributedRateLimiter {
    private redis: Redis;
    private key: string;
    private maxRequests: number;
    private windowSize: number;
    
    constructor(redis: Redis, key: string, maxRequests: number, windowSize: number) {
        this.redis = redis;
        this.key = key;
        this.maxRequests = maxRequests;
        this.windowSize = windowSize;
    }
    
    async allowRequest(): Promise<boolean> {
        const now = Date.now();
        const windowStart = now - this.windowSize;
        
        // Remove old requests
        await this.redis.zremrangebyscore(this.key, 0, windowStart);
        
        // Count requests in current window
        const count = await this.redis.zcard(this.key);
        
        if (count < this.maxRequests) {
            await this.redis.zadd(this.key, now.toString(), now.toString());
            await this.redis.expire(this.key, this.windowSize / 1000);
            return true;
        }
        
        return false;
    }
}
Beginner
7. What is an API Gateway?

An API Gateway acts as a single entry point for client applications, providing routing, authentication, rate limiting, and other cross-cutting concerns.

  • Routing: Forward requests to services
  • Authentication: JWT, OAuth2 verification
  • Rate Limiting: Throttle requests
  • Caching: Cache responses
  • Monitoring: Logging and metrics
system-design
// System Design - API Gateway
// API Gateway implementation
class APIGateway {
    private routes: Map<string, Route>;
    private authService: AuthService;
    private rateLimiter: RateLimiter;
    
    constructor(authService: AuthService, rateLimiter: RateLimiter) {
        this.routes = new Map();
        this.authService = authService;
        this.rateLimiter = rateLimiter;
    }
    
    registerRoute(path: string, service: Service): void {
        this.routes.set(path, {
            path,
            service,
            methods: ['GET', 'POST', 'PUT', 'DELETE']
        });
    }
    
    async handleRequest(request: Request): Promise<Response> {
        // Authentication
        if (!await this.authService.authenticate(request)) {
            return new Response('Unauthorized', { status: 401 });
        }
        
        // Rate limiting
        if (!await this.rateLimiter.allowRequest(request.ip)) {
            return new Response('Too Many Requests', { status: 429 });
        }
        
        // Route matching
        const route = this.matchRoute(request.url);
        if (!route) {
            return new Response('Not Found', { status: 404 });
        }
        
        // Request transformation
        const transformedRequest = this.transformRequest(request);
        
        // Forward to service
        const response = await route.service.handle(transformedRequest);
        
        // Response transformation
        return this.transformResponse(response);
    }
    
    private matchRoute(url: string): Route | undefined {
        for (const [path, route] of this.routes) {
            if (url.startsWith(path)) {
                return route;
            }
        }
        return undefined;
    }
    
    private transformRequest(request: Request): Request {
        // Add headers, modify body, etc.
        return request;
    }
    
    private transformResponse(response: Response): Response {
        // Modify response, add headers, etc.
        return response;
    }
}

// Service registry
class ServiceRegistry {
    private services: Map<string, ServiceInstance[]>;
    private healthCheckInterval: number;
    
    constructor(healthCheckInterval: number = 30000) {
        this.services = new Map();
        this.healthCheckInterval = healthCheckInterval;
    }
    
    register(serviceName: string, instance: ServiceInstance): void {
        if (!this.services.has(serviceName)) {
            this.services.set(serviceName, []);
        }
        this.services.get(serviceName).push(instance);
    }
    
    deregister(serviceName: string, instanceId: string): void {
        const instances = this.services.get(serviceName);
        if (instances) {
            this.services.set(
                serviceName,
                instances.filter(i => i.id !== instanceId)
            );
        }
    }
    
    getService(serviceName: string): ServiceInstance | null {
        const instances = this.services.get(serviceName);
        if (!instances || instances.length === 0) {
            return null;
        }
        // Load balancing - round robin
        return instances[0]; // Simplified
    }
    
    healthCheck(): void {
        // Check health of all instances
        for (const [name, instances] of this.services) {
            const healthyInstances = instances.filter(i => i.isHealthy());
            if (healthyInstances.length === 0) {
                // All instances unhealthy
                console.warn(`No healthy instances for service: ${name}`);
            }
            this.services.set(name, healthyInstances);
        }
    }
}
Beginner
8. What is a Circuit Breaker?

A circuit breaker prevents cascading failures by stopping requests to a failing service, allowing it to recover.

  • Closed: Normal operation
  • Open: Failing, requests fail fast
  • Half-Open: Testing recovery
  • Timeout: Reset after timeout
  • Fallback: Alternative response
system-design
// System Design - Circuit Breaker
// Circuit breaker pattern implementation
class CircuitBreaker {
    private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN';
    private failureThreshold: number;
    private timeout: number;
    private failures: number;
    private lastFailureTime: number;
    private retryTimeout: number;
    
    constructor(failureThreshold: number = 5, timeout: number = 30000, retryTimeout: number = 1000) {
        this.state = 'CLOSED';
        this.failureThreshold = failureThreshold;
        this.timeout = timeout;
        this.retryTimeout = retryTimeout;
        this.failures = 0;
        this.lastFailureTime = 0;
    }
    
    async execute<T>(fn: () => Promise<T>): Promise<T> {
        if (this.state === 'OPEN') {
            if (Date.now() - this.lastFailureTime > this.timeout) {
                this.state = 'HALF_OPEN';
            } else {
                throw new Error('Circuit breaker is OPEN');
            }
        }
        
        try {
            const result = await fn();
            this.onSuccess();
            return result;
        } catch (error) {
            this.onFailure();
            throw error;
        }
    }
    
    private onSuccess(): void {
        if (this.state === 'HALF_OPEN') {
            this.state = 'CLOSED';
            this.failures = 0;
        }
    }
    
    private onFailure(): void {
        this.failures++;
        this.lastFailureTime = Date.now();
        
        if (this.failures >= this.failureThreshold) {
            this.state = 'OPEN';
            this.scheduleRetry();
        }
    }
    
    private scheduleRetry(): void {
        setTimeout(() => {
            this.state = 'HALF_OPEN';
        }, this.retryTimeout);
    }
}

// Circuit breaker with fallback
class CircuitBreakerWithFallback<T> {
    private breaker: CircuitBreaker;
    private fallback: () => T;
    
    constructor(breaker: CircuitBreaker, fallback: () => T) {
        this.breaker = breaker;
        this.fallback = fallback;
    }
    
    async execute(fn: () => Promise<T>): Promise<T> {
        try {
            return await this.breaker.execute(fn);
        } catch (error) {
            return this.fallback();
        }
    }
}
Beginner
9. What is Event Sourcing?

Event sourcing stores all changes to application state as a sequence of events, enabling audit trails and state reconstruction.

  • Event Store: Append-only log
  • Event Replay: Reconstruct state
  • Snapshots: Performance optimization
  • Event Versioning: Handle schema evolution
  • CQRS: Command Query Responsibility Segregation
system-design
// System Design - Event Sourcing
// Event sourcing implementation
interface Event {
    id: string;
    type: string;
    data: any;
    timestamp: number;
    version: number;
}

class EventStore {
    private events: Event[];
    private aggregates: Map<string, any>;
    
    constructor() {
        this.events = [];
        this.aggregates = new Map();
    }
    
    appendEvent(aggregateId: string, event: Event): void {
        this.events.push(event);
        this.applyEvent(aggregateId, event);
    }
    
    getEvents(aggregateId: string): Event[] {
        return this.events.filter(e => e.aggregateId === aggregateId);
    }
    
    getAggregateState(aggregateId: string): any {
        return this.aggregates.get(aggregateId);
    }
    
    private applyEvent(aggregateId: string, event: Event): void {
        let aggregate = this.aggregates.get(aggregateId) || {};
        
        switch (event.type) {
            case 'CREATED':
                aggregate = { ...aggregate, ...event.data };
                break;
            case 'UPDATED':
                aggregate = { ...aggregate, ...event.data };
                break;
            case 'DELETED':
                aggregate = null;
                break;
            default:
                break;
        }
        
        this.aggregates.set(aggregateId, aggregate);
    }
}

// Snapshot implementation
class SnapshotStore {
    private snapshots: Map<string, { state: any, version: number, timestamp: number }>;
    private snapshotFrequency: number;
    
    constructor(snapshotFrequency: number = 100) {
        this.snapshots = new Map();
        this.snapshotFrequency = snapshotFrequency;
    }
    
    saveSnapshot(aggregateId: string, state: any, version: number): void {
        this.snapshots.set(aggregateId, {
            state,
            version,
            timestamp: Date.now()
        });
    }
    
    getSnapshot(aggregateId: string): { state: any; version: number } | null {
        const snapshot = this.snapshots.get(aggregateId);
        if (!snapshot) {
            return null;
        }
        return {
            state: snapshot.state,
            version: snapshot.version
        };
    }
    
    shouldSnapshot(version: number): boolean {
        return version % this.snapshotFrequency === 0;
    }
}
Beginner
10. What is Pub/Sub Pattern?

Publish-Subscribe is a messaging pattern where publishers send messages to topics, and subscribers receive messages from topics they subscribe to.

  • Publisher: Sends messages to topics
  • Subscriber: Receives messages from topics
  • Topic: Channel for messages
  • Fan-out: One-to-many communication
  • Filtering: Subscribe to specific messages
system-design
// System Design - Pub/Sub System
// Publish/Subscribe system implementation
class PubSubSystem {
    private topics: Map<string, Topic>;
    private subscribers: Map<string, Subscriber[]>;
    
    constructor() {
        this.topics = new Map();
        this.subscribers = new Map();
    }
    
    createTopic(name: string): void {
        this.topics.set(name, new Topic(name));
        this.subscribers.set(name, []);
    }
    
    subscribe(topicName: string, subscriber: Subscriber): void {
        const subscribers = this.subscribers.get(topicName);
        if (subscribers) {
            subscribers.push(subscriber);
            subscriber.onSubscribe(topicName);
        }
    }
    
    unsubscribe(topicName: string, subscriber: Subscriber): void {
        const subscribers = this.subscribers.get(topicName);
        if (subscribers) {
            this.subscribers.set(
                topicName,
                subscribers.filter(s => s.id !== subscriber.id)
            );
            subscriber.onUnsubscribe(topicName);
        }
    }
    
    publish(topicName: string, message: Message): void {
        const topic = this.topics.get(topicName);
        if (!topic) {
            throw new Error(`Topic ${topicName} not found`);
        }
        
        topic.addMessage(message);
        const subscribers = this.subscribers.get(topicName) || [];
        
        for (const subscriber of subscribers) {
            subscriber.onMessage(topicName, message);
        }
    }
    
    getTopic(name: string): Topic | undefined {
        return this.topics.get(name);
    }
}

class Topic {
    name: string;
    messages: Message[];
    
    constructor(name: string) {
        this.name = name;
        this.messages = [];
    }
    
    addMessage(message: Message): void {
        this.messages.push(message);
    }
    
    getMessages(startIndex: number = 0): Message[] {
        return this.messages.slice(startIndex);
    }
}

interface Message {
    id: string;
    data: any;
    timestamp: number;
}

interface Subscriber {
    id: string;
    onMessage(topic: string, message: Message): void;
    onSubscribe(topic: string): void;
    onUnsubscribe(topic: string): void;
}
Intermediate
11. What are Load Balancing Algorithms?

Load balancing algorithms determine how traffic is distributed across servers based on different strategies.

  • Round Robin: Sequential distribution
  • Weighted Round Robin: Weighted sequential
  • Least Connections: Server with fewest connections
  • Least Response Time: Fastest response
  • Consistent Hashing: Client-based routing
system-design
// System Design - Load Balancer Algorithms
// Weighted Round Robin
class WeightedRoundRobin {
    private servers: Server[];
    private currentIndex: number = 0;
    private currentWeight: number = 0;
    
    constructor(servers: Server[]) {
        this.servers = servers;
    }
    
    getNextServer(): Server {
        while (true) {
            this.currentIndex = (this.currentIndex + 1) % this.servers.length;
            
            if (this.currentIndex === 0) {
                this.currentWeight = this.currentWeight - 1;
                if (this.currentWeight <= 0) {
                    this.currentWeight = this.getMaxWeight();
                }
            }
            
            if (this.servers[this.currentIndex].weight >= this.currentWeight) {
                return this.servers[this.currentIndex];
            }
        }
    }
    
    private getMaxWeight(): number {
        return Math.max(...this.servers.map(s => s.weight));
    }
}

// Least Connections
class LeastConnections {
    private servers: Server[];
    
    constructor(servers: Server[]) {
        this.servers = servers;
    }
    
    getNextServer(): Server {
        return this.servers.reduce((min, server) => 
            server.connections < min.connections ? server : min
        );
    }
}

// Consistent Hashing Load Balancer
class ConsistentHashLoadBalancer {
    private ring: SortedMap<number, Server>;
    private virtualNodes: number;
    
    constructor(servers: Server[], virtualNodes: number = 100) {
        this.ring = new SortedMap();
        this.virtualNodes = virtualNodes;
        
        for (const server of servers) {
            this.addServer(server);
        }
    }
    
    addServer(server: Server): void {
        for (let i = 0; i < this.virtualNodes; i++) {
            const hash = this.hash(`${server.id}-${i}`);
            this.ring.set(hash, server);
        }
    }
    
    getServer(key: string): Server {
        const hash = this.hash(key);
        const entry = this.ring.ceilingEntry(hash);
        return entry ? entry.value : this.ring.firstEntry().value;
    }
    
    private hash(key: string): number {
        let hash = 0;
        for (let i = 0; i < key.length; i++) {
            hash = (hash << 5) - hash + key.charCodeAt(i);
            hash = hash & hash;
        }
        return hash;
    }
}
Intermediate
12. What is Database Replication?

Database replication copies data from one database server to another, providing redundancy, high availability, and load distribution.

  • Master-Slave: One master, multiple slaves
  • Master-Master: Multi-master replication
  • Synchronous: Immediate replication
  • Asynchronous: Delayed replication
  • Conflict Resolution: Handle write conflicts
system-design
// System Design - Database Replication
// Master-slave replication
class MasterSlaveReplication {
    private master: Database;
    private slaves: Database[];
    private replicationLog: LogEntry[];
    
    constructor(master: Database, slaves: Database[]) {
        this.master = master;
        this.slaves = slaves;
        this.replicationLog = [];
    }
    
    async write(data: any): Promise<void> {
        // Write to master
        await this.master.write(data);
        
        // Log the operation
        this.replicationLog.push({
            timestamp: Date.now(),
            data: data,
            type: 'WRITE'
        });
        
        // Replicate to slaves asynchronously
        this.replicateToSlaves(data);
    }
    
    async read(): Promise<any> {
        // Read from a random slave for load balancing
        const slave = this.slaves[Math.floor(Math.random() * this.slaves.length)];
        return await slave.read();
    }
    
    private async replicateToSlaves(data: any): Promise<void> {
        for (const slave of this.slaves) {
            try {
                await slave.write(data);
            } catch (error) {
                console.error(`Failed to replicate to slave: ${error}`);
                // Log failure for retry
                this.replicationLog.push({
                    timestamp: Date.now(),
                    data: data,
                    type: 'REPLICATION_FAILED',
                    slave: slave.id
                });
            }
        }
    }
    
    async syncSlave(slaveId: string): Promise<void> {
        const slave = this.slaves.find(s => s.id === slaveId);
        if (!slave) {
            throw new Error(`Slave ${slaveId} not found`);
        }
        
        // Sync missing data from master
        const missingData = await this.getMissingData(slave);
        for (const data of missingData) {
            await slave.write(data);
        }
    }
    
    private async getMissingData(slave: Database): Promise<any[]> {
        // Get data missing from slave
        return [];
    }
}
Intermediate
13. What are Microservices Communication Patterns?

Microservices communicate using various patterns including synchronous (REST, gRPC) and asynchronous (message queues, events).

  • REST API: Synchronous HTTP communication
  • gRPC: High-performance RPC
  • Message Queue: Asynchronous communication
  • Event-driven: Event-based communication
  • Service Mesh: Infrastructure layer for communication
system-design
// System Design - Microservices Communication
// Service communication patterns

// Synchronous communication (HTTP/REST)
class RestClient {
    private baseUrl: string;
    private timeout: number;
    
    constructor(baseUrl: string, timeout: number = 5000) {
        this.baseUrl = baseUrl;
        this.timeout = timeout;
    }
    
    async get(endpoint: string): Promise<any> {
        const response = await fetch(`${this.baseUrl}${endpoint}`, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            },
            signal: AbortSignal.timeout(this.timeout)
        });
        return response.json();
    }
    
    async post(endpoint: string, data: any): Promise<any> {
        const response = await fetch(`${this.baseUrl}${endpoint}`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data),
            signal: AbortSignal.timeout(this.timeout)
        });
        return response.json();
    }
}

// Asynchronous communication (Message Queue)
class AsyncCommunication {
    private messageQueue: MessageQueue;
    private serviceName: string;
    
    constructor(messageQueue: MessageQueue, serviceName: string) {
        this.messageQueue = messageQueue;
        this.serviceName = serviceName;
    }
    
    async sendMessage(service: string, message: any): Promise<void> {
        await this.messageQueue.publish(service, {
            from: this.serviceName,
            data: message,
            timestamp: Date.now()
        });
    }
    
    async receiveMessages(callback: (message: any) => Promise<void>): Promise<void> {
        await this.messageQueue.subscribe(this.serviceName, async (message) => {
            try {
                await callback(message);
            } catch (error) {
                console.error(`Error processing message: ${error}`);
                // Send to dead letter queue
                await this.messageQueue.publish('dlq', message);
            }
        });
    }
}

// Circuit breaker pattern
class CircuitBreakerService {
    private circuitBreaker: CircuitBreaker;
    private service: Service;
    private fallback: () => any;
    
    constructor(service: Service, fallback: () => any) {
        this.circuitBreaker = new CircuitBreaker();
        this.service = service;
        this.fallback = fallback;
    }
    
    async call(request: any): Promise<any> {
        try {
            return await this.circuitBreaker.execute(
                () => this.service.handle(request)
            );
        } catch (error) {
            return this.fallback();
        }
    }
}
Intermediate
14. What are Data Partitioning Strategies?

Data partitioning distributes data across multiple servers or shards to improve performance and scalability.

  • Range Partitioning: Based on value ranges
  • Hash Partitioning: Based on hash function
  • List Partitioning: Based on predefined lists
  • Composite Partitioning: Multiple partitioning strategies
  • Consistent Hashing: Minimal redistribution on changes
system-design
// System Design - Data Partitioning Strategies
// Range partitioning
class RangePartitioner {
    private partitions: Partition[];
    private partitionKey: string;
    
    constructor(partitions: Partition[], partitionKey: string) {
        this.partitions = partitions;
        this.partitionKey = partitionKey;
    }
    
    getPartition(data: any): Partition {
        const value = data[this.partitionKey];
        for (const partition of this.partitions) {
            if (value >= partition.start && value < partition.end) {
                return partition;
            }
        }
        return this.partitions[this.partitions.length - 1];
    }
}

// Hash partitioning
class HashPartitioner {
    private numPartitions: number;
    private partitions: Partition[];
    
    constructor(numPartitions: number) {
        this.numPartitions = numPartitions;
        this.partitions = [];
        for (let i = 0; i < numPartitions; i++) {
            this.partitions.push({ id: i });
        }
    }
    
    getPartition(key: string): Partition {
        const hash = this.hash(key);
        const partitionId = hash % this.numPartitions;
        return this.partitions[partitionId];
    }
    
    private hash(key: string): number {
        let hash = 0;
        for (let i = 0; i < key.length; i++) {
            hash = (hash << 5) - hash + key.charCodeAt(i);
            hash = hash & hash;
        }
        return Math.abs(hash);
    }
}

// List partitioning
class ListPartitioner {
    private partitionMap: Map<string, Partition>;
    
    constructor(partitionMap: Map<string, Partition>) {
        this.partitionMap = partitionMap;
    }
    
    getPartition(key: string): Partition | undefined {
        return this.partitionMap.get(key);
    }
}

// Composite partitioning
class CompositePartitioner {
    private partitioners: Partitioner[];
    
    constructor(partitioners: Partitioner[]) {
        this.partitioners = partitioners;
    }
    
    getPartition(data: any): Partition {
        let partition = data;
        for (const partitioner of this.partitioners) {
            partition = partitioner.getPartition(partition);
        }
        return partition;
    }
}
Intermediate
15. What are Replication Strategies?

Replication strategies define how data is copied and synchronized across multiple nodes in a distributed system.

  • Single-Leader: One primary node
  • Multi-Leader: Multiple primary nodes
  • Leaderless: No designated leader
  • Quorum-based: Majority consensus
  • Conflict-free: CRDTs (Conflict-free Replicated Data Types)
system-design
// System Design - Replication Strategies
// Multi-master replication
class MultiMasterReplication {
    private nodes: Node[];
    private conflictResolution: ConflictResolutionStrategy;
    
    constructor(nodes: Node[], conflictResolution: ConflictResolutionStrategy) {
        this.nodes = nodes;
        this.conflictResolution = conflictResolution;
    }
    
    async write(data: any): Promise<void> {
        const writes = this.nodes.map(async (node) => {
            try {
                await node.write(data);
                return { success: true, node: node.id };
            } catch (error) {
                return { success: false, node: node.id, error };
            }
        });
        
        const results = await Promise.all(writes);
        const failed = results.filter(r => !r.success);
        
        if (failed.length > 0) {
            // Handle failures
            console.warn(`Writes failed on nodes: ${failed.map(f => f.node).join(', ')}`);
        }
    }
    
    async read(key: string): Promise<any> {
        const reads = this.nodes.map(async (node) => {
            try {
                return await node.read(key);
            } catch (error) {
                return null;
            }
        });
        
        const results = await Promise.all(reads);
        const validResults = results.filter(r => r !== null);
        
        if (validResults.length === 0) {
            throw new Error('No data available');
        }
        
        // Resolve conflicts
        return this.conflictResolution.resolve(validResults);
    }
}

// Quorum-based replication
class QuorumReplication {
    private nodes: Node[];
    private readQuorum: number;
    private writeQuorum: number;
    
    constructor(nodes: Node[], readQuorum: number, writeQuorum: number) {
        this.nodes = nodes;
        this.readQuorum = readQuorum;
        this.writeQuorum = writeQuorum;
    }
    
    async write(data: any): Promise<void> {
        const writes = this.nodes.map(node => node.write(data));
        const results = await Promise.allSettled(writes);
        const successCount = results.filter(r => r.status === 'fulfilled').length;
        
        if (successCount < this.writeQuorum) {
            throw new Error(`Write quorum not met: ${successCount} of ${this.writeQuorum}`);
        }
    }
    
    async read(key: string): Promise<any> {
        const reads = this.nodes.map(node => node.read(key));
        const results = await Promise.allSettled(reads);
        const successfulReads = results
            .filter(r => r.status === 'fulfilled')
            .map(r => (r as PromiseFulfilledResult<any>).value);
        
        if (successfulReads.length < this.readQuorum) {
            throw new Error(`Read quorum not met: ${successfulReads.length} of ${this.readQuorum}`);
        }
        
        return this.resolveReads(successfulReads);
    }
    
    private resolveReads(reads: any[]): any {
        // Implement read resolution (e.g., version-based)
        return reads[0];
    }
}
Intermediate
16. What are API Gateway Patterns?

API Gateway patterns define how the gateway handles routing, authentication, rate limiting, and other cross-cutting concerns.

  • Gateway Routing: Route requests to services
  • Gateway Aggregation: Combine multiple responses
  • Gateway Authentication: JWT/OAuth validation
  • Gateway Rate Limiting: Throttle requests
  • Gateway Caching: Cache responses
system-design
// System Design - API Gateway Patterns
// Gateway routing pattern
class GatewayRouter {
    private routes: Route[];
    private loadBalancer: LoadBalancer;
    
    constructor(routes: Route[], loadBalancer: LoadBalancer) {
        this.routes = routes;
        this.loadBalancer = loadBalancer;
    }
    
    async route(request: Request): Promise<Response> {
        const route = this.matchRoute(request);
        if (!route) {
            return new Response('Not Found', { status: 404 });
        }
        
        const service = this.loadBalancer.getService(route.serviceName);
        if (!service) {
            return new Response('Service Unavailable', { status: 503 });
        }
        
        const response = await service.handle(request);
        return response;
    }
    
    private matchRoute(request: Request): Route | undefined {
        for (const route of this.routes) {
            if (request.url.pathname.startsWith(route.path)) {
                return route;
            }
        }
        return undefined;
    }
}

// Authentication gateway
class AuthGateway {
    private authService: AuthService;
    private allowedPaths: string[];
    
    constructor(authService: AuthService, allowedPaths: string[]) {
        this.authService = authService;
        this.allowedPaths = allowedPaths;
    }
    
    async authenticate(request: Request): Promise<boolean> {
        // Skip authentication for public paths
        if (this.isPublicPath(request.url.pathname)) {
            return true;
        }
        
        const token = this.extractToken(request);
        if (!token) {
            return false;
        }
        
        return await this.authService.validateToken(token);
    }
    
    private isPublicPath(path: string): boolean {
        return this.allowedPaths.some(p => path.startsWith(p));
    }
    
    private extractToken(request: Request): string | null {
        const authHeader = request.headers.get('Authorization');
        if (authHeader && authHeader.startsWith('Bearer ')) {
            return authHeader.substring(7);
        }
        return null;
    }
}

// Rate limiting gateway
class RateLimitGateway {
    private rateLimiter: RateLimiter;
    private config: RateLimitConfig;
    
    constructor(rateLimiter: RateLimiter, config: RateLimitConfig) {
        this.rateLimiter = rateLimiter;
        this.config = config;
    }
    
    async allowRequest(request: Request): Promise<boolean> {
        const clientId = this.getClientId(request);
        return await this.rateLimiter.allowRequest(clientId);
    }
    
    private getClientId(request: Request): string {
        // Use IP address or API key
        return request.ip || request.headers.get('X-API-Key') || 'unknown';
    }
}
Intermediate
17. What are Caching Patterns?

Caching patterns define how and when to cache data to optimize performance and reduce latency.

  • Cache-Aside: Application manages cache
  • Read-Through: Cache reads from database
  • Write-Through: Writes to cache and database
  • Write-Behind: Asynchronous write to database
  • Cache Invalidation: Remove stale data
system-design
// System Design - Caching Patterns
// Cache-Aside (Lazy Loading)
class CacheAsidePattern<K, V> {
    private cache: Cache<K, V>;
    private dataStore: DataStore<K, V>;
    
    constructor(cache: Cache<K, V>, dataStore: DataStore<K, V>) {
        this.cache = cache;
        this.dataStore = dataStore;
    }
    
    async get(key: K): Promise<V | null> {
        // Try cache first
        let value = await this.cache.get(key);
        if (value !== null) {
            return value;
        }
        
        // Cache miss - get from data store
        value = await this.dataStore.get(key);
        if (value !== null) {
            // Store in cache
            await this.cache.set(key, value);
        }
        return value;
    }
    
    async set(key: K, value: V): Promise<void> {
        await this.dataStore.set(key, value);
        await this.cache.set(key, value);
    }
    
    async invalidate(key: K): Promise<void> {
        await this.cache.delete(key);
    }
}

// Write-Through Cache
class WriteThroughCache<K, V> {
    private cache: Cache<K, V>;
    private dataStore: DataStore<K, V>;
    
    constructor(cache: Cache<K, V>, dataStore: DataStore<K, V>) {
        this.cache = cache;
        this.dataStore = dataStore;
    }
    
    async get(key: K): Promise<V | null> {
        return await this.cache.get(key);
    }
    
    async set(key: K, value: V): Promise<void> {
        // Write to both cache and data store
        await Promise.all([
            this.cache.set(key, value),
            this.dataStore.set(key, value)
        ]);
    }
    
    async delete(key: K): Promise<void> {
        await Promise.all([
            this.cache.delete(key),
            this.dataStore.delete(key)
        ]);
    }
}

// Write-Behind Cache
class WriteBehindCache<K, V> {
    private cache: Cache<K, V>;
    private dataStore: DataStore<K, V>;
    private writeQueue: Queue<{key: K, value: V}>;
    
    constructor(cache: Cache<K, V>, dataStore: DataStore<K, V>) {
        this.cache = cache;
        this.dataStore = dataStore;
        this.writeQueue = new Queue();
        this.processQueue();
    }
    
    async get(key: K): Promise<V | null> {
        return await this.cache.get(key);
    }
    
    async set(key: K, value: V): Promise<void> {
        await this.cache.set(key, value);
        this.writeQueue.enqueue({ key, value });
    }
    
    private async processQueue(): Promise<void> {
        while (true) {
            const item = await this.writeQueue.dequeue();
            if (item) {
                await this.dataStore.set(item.key, item.value);
            }
        }
    }
}
Intermediate
18. What is Eventual Consistency?

Eventual consistency guarantees that all replicas will converge to the same state, but not necessarily immediately after a write.

  • Vector Clocks: Version tracking
  • Conflict Resolution: Handle concurrent updates
  • Quorum: Read/Write quorum for consistency
  • Asynchronous Replication: Delay between writes and reads
  • CRDTs: Conflict-free Replicated Data Types
system-design
// System Design - Eventual Consistency
// Eventual consistency implementation
class EventualConsistency {
    private nodes: Node[];
    private replicationQueue: Queue<Update>;
    private conflictResolver: ConflictResolver;
    
    constructor(nodes: Node[], conflictResolver: ConflictResolver) {
        this.nodes = nodes;
        this.conflictResolver = conflictResolver;
        this.replicationQueue = new Queue();
    }
    
    async update(key: string, value: any): Promise<void> {
        // Update local node
        const localNode = this.nodes[0];
        await localNode.update(key, value);
        
        // Queue for replication
        this.replicationQueue.enqueue({
            key,
            value,
            timestamp: Date.now(),
            source: localNode.id
        });
        
        // Start replication process
        this.processReplication();
    }
    
    async read(key: string): Promise<any> {
        // Read from a random node
        const node = this.nodes[Math.floor(Math.random() * this.nodes.length)];
        return await node.read(key);
    }
    
    private async processReplication(): Promise<void> {
        while (true) {
            const update = await this.replicationQueue.dequeue();
            if (update) {
                await this.replicate(update);
            }
        }
    }
    
    private async replicate(update: Update): Promise<void> {
        for (const node of this.nodes) {
            if (node.id !== update.source) {
                try {
                    await node.update(update.key, update.value);
                } catch (error) {
                    console.error(`Failed to replicate to node ${node.id}: ${error}`);
                    // Retry later
                    this.replicationQueue.enqueue(update);
                }
            }
        }
    }
    
    // Vector clock for versioning
    private vectorClock: Map<string, number> = new Map();
    
    incrementClock(nodeId: string): void {
        const current = this.vectorClock.get(nodeId) || 0;
        this.vectorClock.set(nodeId, current + 1);
    }
    
    getClock(): Map<string, number> {
        return new Map(this.vectorClock);
    }
}
Intermediate
19. What are Distributed Transactions?

Distributed transactions coordinate operations across multiple services or databases, ensuring consistency and atomicity.

  • Two-Phase Commit: Prepare and commit phases
  • Saga Pattern: Compensation transactions
  • Compensation: Rollback operations
  • Idempotency: Handle duplicate operations
  • Distributed ACID: Atomicity, Consistency, Isolation, Durability
system-design
// System Design - Distributed Transactions
// Two-phase commit
class TwoPhaseCommit {
    private participants: Participant[];
    private coordinator: Coordinator;
    
    constructor(participants: Participant[]) {
        this.participants = participants;
        this.coordinator = new Coordinator(participants);
    }
    
    async execute(transaction: Transaction): Promise<boolean> {
        // Phase 1: Prepare
        const prepareResults = await this.coordinator.prepare(transaction);
        
        if (prepareResults.every(r => r === 'ready')) {
            // Phase 2: Commit
            await this.coordinator.commit(transaction);
            return true;
        } else {
            // Rollback
            await this.coordinator.rollback(transaction);
            return false;
        }
    }
}

// Saga pattern
class SagaOrchestrator {
    private steps: SagaStep[];
    private compensationSteps: SagaStep[];
    
    constructor(steps: SagaStep[], compensationSteps: SagaStep[]) {
        this.steps = steps;
        this.compensationSteps = compensationSteps;
    }
    
    async execute(data: any): Promise<void> {
        let completedSteps = 0;
        
        try {
            for (let i = 0; i < this.steps.length; i++) {
                await this.steps[i].execute(data);
                completedSteps++;
            }
        } catch (error) {
            // Compensate for completed steps
            for (let i = completedSteps - 1; i >= 0; i--) {
                await this.compensationSteps[i].execute(data);
            }
            throw error;
        }
    }
}

// Compensation transaction
class CompensationTransaction {
    private operations: Operation[];
    
    constructor(operations: Operation[]) {
        this.operations = operations;
    }
    
    async execute(): Promise<void> {
        for (const operation of this.operations) {
            try {
                await operation.execute();
            } catch (error) {
                // Log failure and continue
                console.error(`Compensation failed: ${error}`);
            }
        }
    }
}
Intermediate
20. What is Service Discovery?

Service discovery enables services to dynamically discover and communicate with each other without hardcoded addresses.

  • Service Registry: Store service instances
  • Health Checks: Monitor service health
  • Load Balancing: Distribute across instances
  • DNS-based: Service discovery via DNS
  • Consul/etcd: Service discovery tools
system-design
// System Design - Service Discovery
// Service discovery implementation
class ServiceDiscovery {
    private services: Map<string, ServiceInstance[]>;
    private healthCheck: HealthCheck;
    private loadBalancer: LoadBalancer;
    
    constructor(healthCheck: HealthCheck, loadBalancer: LoadBalancer) {
        this.services = new Map();
        this.healthCheck = healthCheck;
        this.loadBalancer = loadBalancer;
        this.startHealthCheck();
    }
    
    register(serviceName: string, instance: ServiceInstance): void {
        if (!this.services.has(serviceName)) {
            this.services.set(serviceName, []);
        }
        this.services.get(serviceName).push(instance);
        console.log(`Service ${serviceName} registered: ${instance.id}`);
    }
    
    deregister(serviceName: string, instanceId: string): void {
        const instances = this.services.get(serviceName);
        if (instances) {
            this.services.set(
                serviceName,
                instances.filter(i => i.id !== instanceId)
            );
            console.log(`Service ${serviceName} deregistered: ${instanceId}`);
        }
    }
    
    discover(serviceName: string): ServiceInstance | null {
        const instances = this.services.get(serviceName);
        if (!instances || instances.length === 0) {
            return null;
        }
        
        // Load balance and return a healthy instance
        const healthyInstances = instances.filter(i => i.isHealthy());
        if (healthyInstances.length === 0) {
            return null;
        }
        
        return this.loadBalancer.select(healthyInstances);
    }
    
    private startHealthCheck(): void {
        setInterval(async () => {
            for (const [serviceName, instances] of this.services) {
                const healthyInstances = await Promise.all(
                    instances.map(async (instance) => {
                        const isHealthy = await this.healthCheck.check(instance);
                        instance.setHealth(isHealthy);
                        return instance;
                    })
                );
                
                this.services.set(
                    serviceName,
                    healthyInstances.filter(i => i.isHealthy())
                );
            }
        }, 30000);
    }
}

// Health check implementation
class HealthCheck {
    async check(instance: ServiceInstance): Promise<boolean> {
        try {
            const response = await fetch(`${instance.url}/health`, {
                timeout: 5000
            });
            return response.status === 200;
        } catch (error) {
            return false;
        }
    }
}

// Load balancer for service discovery
class ServiceLoadBalancer {
    private strategy: LoadBalancingStrategy;
    
    constructor(strategy: LoadBalancingStrategy) {
        this.strategy = strategy;
    }
    
    select(instances: ServiceInstance[]): ServiceInstance {
        return this.strategy.select(instances);
    }
}
Advanced
21. What is a Distributed Cache?

A distributed cache stores data across multiple nodes, providing high availability, scalability, and fault tolerance.

  • Consistent Hashing: Data distribution
  • Replication: Copy data across nodes
  • Cache Invalidation: Remove stale data
  • Cache Coherency: Consistency across nodes
  • Cache Eviction: LRU, LFU, TTL
system-design
// System Design - Distributed Cache
// Distributed cache implementation
class DistributedCache {
    private nodes: CacheNode[];
    private consistentHash: ConsistentHash;
    private replicationFactor: number;
    
    constructor(nodes: CacheNode[], replicationFactor: number = 2) {
        this.nodes = nodes;
        this.replicationFactor = replicationFactor;
        this.consistentHash = new ConsistentHash(nodes.map(n => n.id));
    }
    
    async get(key: string): Promise<any> {
        const primaryNode = this.getNode(key);
        const value = await primaryNode.get(key);
        
        if (value === null && this.replicationFactor > 1) {
            // Try replica nodes
            const replicaNodes = this.getReplicaNodes(key);
            for (const node of replicaNodes) {
                const value = await node.get(key);
                if (value !== null) {
                    // Write back to primary
                    await primaryNode.set(key, value);
                    return value;
                }
            }
        }
        
        return value;
    }
    
    async set(key: string, value: any): Promise<void> {
        const primaryNode = this.getNode(key);
        await primaryNode.set(key, value);
        
        // Replicate to other nodes
        const replicaNodes = this.getReplicaNodes(key);
        for (const node of replicaNodes) {
            try {
                await node.set(key, value);
            } catch (error) {
                console.error(`Failed to replicate to node ${node.id}: ${error}`);
            }
        }
    }
    
    private getNode(key: string): CacheNode {
        const nodeId = this.consistentHash.getNode(key);
        return this.nodes.find(n => n.id === nodeId);
    }
    
    private getReplicaNodes(key: string): CacheNode[] {
        const replicas = [];
        let currentKey = key;
        
        for (let i = 0; i < this.replicationFactor - 1; i++) {
            currentKey = `${currentKey}-replica`;
            const nodeId = this.consistentHash.getNode(currentKey);
            const node = this.nodes.find(n => n.id === nodeId);
            if (node && !replicas.includes(node)) {
                replicas.push(node);
            }
        }
        
        return replicas;
    }
}
Advanced
22. What is a Job Queue?

A job queue manages background tasks and long-running operations, providing retries, scheduling, and failure handling.

  • Producer: Enqueues jobs
  • Consumer: Processes jobs
  • Retry: Automatic retry on failure
  • Backoff: Exponential backoff for retries
  • Dead Letter Queue: Failed job handling
system-design
// System Design - Job Queue
// Job queue implementation
class JobQueue {
    private queues: Map<string, Queue>;
    private workers: Worker[];
    private maxRetries: number;
    
    constructor(maxRetries: number = 3) {
        this.queues = new Map();
        this.workers = [];
        this.maxRetries = maxRetries;
    }
    
    createQueue(name: string): void {
        this.queues.set(name, new Queue(name));
    }
    
    enqueue(queueName: string, job: Job): void {
        const queue = this.queues.get(queueName);
        if (!queue) {
            throw new Error(`Queue ${queueName} not found`);
        }
        queue.enqueue(job);
        this.processQueue(queueName);
    }
    
    private async processQueue(queueName: string): Promise<void> {
        const queue = this.queues.get(queueName);
        if (!queue) return;
        
        while (queue.hasJobs()) {
            const job = queue.dequeue();
            if (job) {
                await this.executeJob(job);
            }
        }
    }
    
    private async executeJob(job: Job): Promise<void> {
        let attempts = 0;
        let success = false;
        
        while (attempts < this.maxRetries && !success) {
            try {
                await job.execute();
                success = true;
                job.status = 'completed';
            } catch (error) {
                attempts++;
                job.retries = attempts;
                job.status = 'failed';
                console.error(`Job ${job.id} failed (attempt ${attempts}): ${error}`);
                
                if (attempts < this.maxRetries) {
                    // Exponential backoff
                    const delay = Math.pow(2, attempts) * 1000;
                    await this.sleep(delay);
                }
            }
        }
    }
    
    private sleep(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

class Queue {
    private name: string;
    private jobs: Job[];
    
    constructor(name: string) {
        this.name = name;
        this.jobs = [];
    }
    
    enqueue(job: Job): void {
        job.status = 'pending';
        this.jobs.push(job);
    }
    
    dequeue(): Job | null {
        return this.jobs.shift() || null;
    }
    
    hasJobs(): boolean {
        return this.jobs.length > 0;
    }
}
Advanced
23. What is Realtime Communication?

Realtime communication enables instant message delivery between clients and servers using WebSockets, Server-Sent Events, or other protocols.

  • WebSockets: Bi-directional communication
  • Server-Sent Events: Server to client streaming
  • WebRTC: Peer-to-peer communication
  • Room Management: Group communication
  • Presence: Online/offline status
system-design
// System Design - Realtime Communication
// WebSocket server implementation
class WebSocketServer {
    private clients: Map<string, WebSocket>;
    private rooms: Map<string, Set<string>>;
    
    constructor() {
        this.clients = new Map();
        this.rooms = new Map();
    }
    
    onConnection(ws: WebSocket, clientId: string): void {
        this.clients.set(clientId, ws);
        
        ws.on('message', (message) => {
            this.handleMessage(clientId, message);
        });
        
        ws.on('close', () => {
            this.handleDisconnect(clientId);
        });
    }
    
    private handleMessage(clientId: string, message: any): void {
        const data = JSON.parse(message);
        
        switch (data.type) {
            case 'join':
                this.joinRoom(clientId, data.room);
                break;
            case 'leave':
                this.leaveRoom(clientId, data.room);
                break;
            case 'message':
                this.broadcastMessage(data.room, {
                    from: clientId,
                    data: data.payload
                });
                break;
        }
    }
    
    private joinRoom(clientId: string, room: string): void {
        if (!this.rooms.has(room)) {
            this.rooms.set(room, new Set());
        }
        this.rooms.get(room).add(clientId);
        
        this.sendToClient(clientId, {
            type: 'joined',
            room: room
        });
    }
    
    private leaveRoom(clientId: string, room: string): void {
        const clients = this.rooms.get(room);
        if (clients) {
            clients.delete(clientId);
        }
    }
    
    private broadcastMessage(room: string, message: any): void {
        const clients = this.rooms.get(room);
        if (!clients) return;
        
        for (const clientId of clients) {
            this.sendToClient(clientId, message);
        }
    }
    
    private sendToClient(clientId: string, message: any): void {
        const ws = this.clients.get(clientId);
        if (ws) {
            ws.send(JSON.stringify(message));
        }
    }
    
    private handleDisconnect(clientId: string): void {
        this.clients.delete(clientId);
        for (const [room, clients] of this.rooms) {
            clients.delete(clientId);
        }
    }
}
Advanced
24. What is Monitoring and Observability?

Monitoring and observability provide insights into system behavior, performance, and health through metrics, logs, and traces.

  • Metrics: Performance indicators
  • Logs: Event records
  • Traces: Request flows
  • Alerts: Notification on anomalies
  • Dashboards: Visualization
system-design
// System Design - Monitoring and Observability
// Metrics collection
class MetricsCollector {
    private metrics: Map<string, Metric>;
    private registry: Registry;
    
    constructor(registry: Registry) {
        this.metrics = new Map();
        this.registry = registry;
    }
    
    counter(name: string, labels?: Record<string, string>): Counter {
        const key = this.getMetricKey(name, labels);
        if (!this.metrics.has(key)) {
            const counter = new Counter(name, labels);
            this.metrics.set(key, counter);
            this.registry.register(counter);
        }
        return this.metrics.get(key) as Counter;
    }
    
    gauge(name: string, labels?: Record<string, string>): Gauge {
        const key = this.getMetricKey(name, labels);
        if (!this.metrics.has(key)) {
            const gauge = new Gauge(name, labels);
            this.metrics.set(key, gauge);
            this.registry.register(gauge);
        }
        return this.metrics.get(key) as Gauge;
    }
    
    histogram(name: string, labels?: Record<string, string>): Histogram {
        const key = this.getMetricKey(name, labels);
        if (!this.metrics.has(key)) {
            const histogram = new Histogram(name, labels);
            this.metrics.set(key, histogram);
            this.registry.register(histogram);
        }
        return this.metrics.get(key) as Histogram;
    }
    
    private getMetricKey(name: string, labels?: Record<string, string>): string {
        if (!labels) return name;
        const labelString = Object.entries(labels)
            .map(([k, v]) => `${k}=${v}`)
            .join(',');
        return `${name}{${labelString}}`;
    }
}

// Logging system
class LoggingSystem {
    private loggers: Logger[];
    private logLevel: LogLevel;
    
    constructor(logLevel: LogLevel = 'info') {
        this.loggers = [];
        this.logLevel = logLevel;
    }
    
    addLogger(logger: Logger): void {
        this.loggers.push(logger);
    }
    
    log(level: LogLevel, message: string, metadata?: any): void {
        if (this.shouldLog(level)) {
            const logEntry = {
                timestamp: new Date().toISOString(),
                level,
                message,
                metadata,
                traceId: this.getTraceId()
            };
            
            for (const logger of this.loggers) {
                logger.log(logEntry);
            }
        }
    }
    
    info(message: string, metadata?: any): void {
        this.log('info', message, metadata);
    }
    
    error(message: string, metadata?: any): void {
        this.log('error', message, metadata);
    }
    
    debug(message: string, metadata?: any): void {
        this.log('debug', message, metadata);
    }
    
    warn(message: string, metadata?: any): void {
        this.log('warn', message, metadata);
    }
    
    private shouldLog(level: LogLevel): boolean {
        const levels = ['debug', 'info', 'warn', 'error'];
        return levels.indexOf(level) >= levels.indexOf(this.logLevel);
    }
    
    private getTraceId(): string {
        // Get trace ID from context
        return 'trace-' + Date.now();
    }
}
Advanced
25. What is Distributed Tracing?

Distributed tracing tracks requests across multiple services, providing visibility into the flow and performance of distributed systems.

  • Spans: Individual operations
  • Trace ID: Unique request identifier
  • Context Propagation: Pass tracing context
  • Instrumentation: Code instrumentation
  • Jaeger/Zipkin: Tracing tools
system-design
// System Design - Distributed Tracing
// Distributed tracing implementation
class Tracer {
    private spans: Span[];
    private activeSpans: Map<string, Span>;
    
    constructor() {
        this.spans = [];
        this.activeSpans = new Map();
    }
    
    startSpan(operationName: string, parentSpanId?: string): Span {
        const spanId = this.generateSpanId();
        const span = new Span(spanId, operationName, parentSpanId);
        this.activeSpans.set(spanId, span);
        return span;
    }
    
    finishSpan(spanId: string): void {
        const span = this.activeSpans.get(spanId);
        if (span) {
            span.finish();
            this.spans.push(span);
            this.activeSpans.delete(spanId);
        }
    }
    
    getTrace(traceId: string): Span[] {
        return this.spans.filter(s => s.traceId === traceId);
    }
    
    private generateSpanId(): string {
        return `span-${Date.now()}-${Math.random()}`;
    }
}

class Span {
    id: string;
    traceId: string;
    operationName: string;
    parentSpanId: string;
    startTime: number;
    endTime: number;
    tags: Map<string, any>;
    logs: LogEntry[];
    
    constructor(id: string, operationName: string, parentSpanId?: string) {
        this.id = id;
        this.traceId = this.generateTraceId();
        this.operationName = operationName;
        this.parentSpanId = parentSpanId || '';
        this.startTime = Date.now();
        this.endTime = 0;
        this.tags = new Map();
        this.logs = [];
    }
    
    setTag(key: string, value: any): void {
        this.tags.set(key, value);
    }
    
    log(message: string, fields?: any): void {
        this.logs.push({
            timestamp: Date.now(),
            message,
            fields
        });
    }
    
    finish(): void {
        this.endTime = Date.now();
    }
    
    private generateTraceId(): string {
        return `trace-${Date.now()}-${Math.random()}`;
    }
}
Advanced
26. What is a Data Pipeline?

A data pipeline moves and transforms data from sources to destinations, enabling data processing, analysis, and integration.

  • Sources: Data origins
  • Processors: Data transformation
  • Sinks: Data destinations
  • Streaming: Real-time processing
  • Batch: Periodic processing
system-design
// System Design - Data Pipeline
// Data pipeline implementation
class DataPipeline {
    private stages: Stage[];
    private errorHandlers: ErrorHandler[];
    
    constructor(stages: Stage[]) {
        this.stages = stages;
        this.errorHandlers = [];
    }
    
    async process(data: any): Promise<any> {
        let currentData = data;
        
        for (const stage of this.stages) {
            try {
                currentData = await stage.process(currentData);
            } catch (error) {
                await this.handleError(error, stage, currentData);
                throw error;
            }
        }
        
        return currentData;
    }
    
    private async handleError(error: Error, stage: Stage, data: any): Promise<void> {
        for (const handler of this.errorHandlers) {
            try {
                await handler.handle(error, stage, data);
            } catch (e) {
                console.error(`Error handler failed: ${e}`);
            }
        }
    }
}

// Streaming pipeline
class StreamingPipeline {
    private sources: Source[];
    private processors: Processor[];
    private sinks: Sink[];
    
    constructor() {
        this.sources = [];
        this.processors = [];
        this.sinks = [];
    }
    
    addSource(source: Source): void {
        this.sources.push(source);
    }
    
    addProcessor(processor: Processor): void {
        this.processors.push(processor);
    }
    
    addSink(sink: Sink): void {
        this.sinks.push(sink);
    }
    
    async start(): Promise<void> {
        for (const source of this.sources) {
            source.onData(async (data) => {
                let processed = data;
                for (const processor of this.processors) {
                    processed = await processor.process(processed);
                }
                for (const sink of this.sinks) {
                    await sink.write(processed);
                }
            });
            await source.start();
        }
    }
}
Advanced
27. What is a Data Warehouse?

A data warehouse is a centralized repository that stores structured data from multiple sources for analysis and reporting.

  • ETL: Extract, Transform, Load
  • OLAP: Online Analytical Processing
  • Star Schema: Fact and dimension tables
  • Data Marts: Departmental data
  • Historical Data: Time-based data
system-design
// System Design - Data Warehouse
// Data warehouse implementation
class DataWarehouse {
    private tables: Map<string, Table>;
    private partitions: Map<string, Partition>;
    private indices: Map<string, Index>;
    
    constructor() {
        this.tables = new Map();
        this.partitions = new Map();
        this.indices = new Map();
    }
    
    createTable(name: string, schema: Schema): void {
        this.tables.set(name, new Table(name, schema));
    }
    
    createPartition(tableName: string, partitionKey: string): void {
        const table = this.tables.get(tableName);
        if (!table) {
            throw new Error(`Table ${tableName} not found`);
        }
        this.partitions.set(`${tableName}.${partitionKey}`, new Partition(table, partitionKey));
    }
    
    createIndex(tableName: string, column: string): void {
        const table = this.tables.get(tableName);
        if (!table) {
            throw new Error(`Table ${tableName} not found`);
        }
        this.indices.set(`${tableName}.${column}`, new Index(table, column));
    }
    
    async query(sql: string): Promise<any[]> {
        // Parse SQL and execute query
        const parsed = this.parseSQL(sql);
        const table = this.tables.get(parsed.table);
        if (!table) {
            throw new Error(`Table ${parsed.table} not found`);
        }
        return table.query(parsed);
    }
    
    private parseSQL(sql: string): ParsedQuery {
        // Simple SQL parser
        return { table: 'users', columns: ['*'], where: {} };
    }
}

// ETL process
class ETLProcess {
    private extractors: Extractor[];
    private transformers: Transformer[];
    private loaders: Loader[];
    
    constructor() {
        this.extractors = [];
        this.transformers = [];
        this.loaders = [];
    }
    
    addExtractor(extractor: Extractor): void {
        this.extractors.push(extractor);
    }
    
    addTransformer(transformer: Transformer): void {
        this.transformers.push(transformer);
    }
    
    addLoader(loader: Loader): void {
        this.loaders.push(loader);
    }
    
    async run(): Promise<void> {
        for (const extractor of this.extractors) {
            const data = await extractor.extract();
            let transformed = data;
            for (const transformer of this.transformers) {
                transformed = await transformer.transform(transformed);
            }
            for (const loader of this.loaders) {
                await loader.load(transformed);
            }
        }
    }
}
Advanced
28. What is a Content Delivery Network (CDN)?

A CDN is a distributed network of servers that delivers web content to users based on their geographic location, improving performance and availability.

  • Edge Locations: Geographic distribution
  • Caching: Content storage at edge
  • Origin: Primary content source
  • DNS Routing: Geographic routing
  • DDoS Protection: Security features
system-design
// System Design - Content Delivery Network
// CDN implementation
class CDN {
    private edgeLocations: EdgeLocation[];
    private originServer: OriginServer;
    private cache: Cache;
    
    constructor(originServer: OriginServer, edgeLocations: EdgeLocation[]) {
        this.originServer = originServer;
        this.edgeLocations = edgeLocations;
        this.cache = new Cache();
    }
    
    async serveContent(request: Request): Promise<Response> {
        // Find closest edge location
        const edgeLocation = this.getClosestEdge(request.ip);
        
        // Check cache
        const cacheKey = this.getCacheKey(request);
        const cached = await this.cache.get(cacheKey);
        if (cached) {
            return cached;
        }
        
        // Fetch from origin
        const response = await this.originServer.fetch(request);
        
        // Cache response
        if (response.status === 200) {
            await this.cache.set(cacheKey, response);
        }
        
        return response;
    }
    
    private getClosestEdge(ip: string): EdgeLocation {
        // Geo-location based routing
        const location = this.getGeoLocation(ip);
        return this.edgeLocations
            .sort((a, b) => this.getDistance(location, a.location))
            [0];
    }
    
    private getCacheKey(request: Request): string {
        return `${request.url.pathname}${request.url.query || ''}`;
    }
    
    private getGeoLocation(ip: string): { lat: number; lon: number } {
        // IP to location mapping
        return { lat: 40.7128, lon: -74.0060 };
    }
    
    private getDistance(loc1: { lat: number; lon: number }, loc2: { lat: number; lon: number }): number {
        // Haversine formula for distance calculation
        return 0;
    }
}
Advanced
29. What is a Search Engine?

A search engine indexes and searches documents, providing relevant results based on user queries using various ranking algorithms.

  • Inverted Index: Word-to-document mapping
  • Tokenization: Text processing
  • Ranking: Relevance scoring
  • Query Parsing: Understand search intent
  • Elasticsearch/Solr: Search engines
system-design
// System Design - Search Engine
// Search engine implementation
class SearchEngine {
    private index: InvertedIndex;
    private tokenizer: Tokenizer;
    private ranker: Ranker;
    
    constructor() {
        this.index = new InvertedIndex();
        this.tokenizer = new Tokenizer();
        this.ranker = new Ranker();
    }
    
    indexDocument(doc: Document): void {
        const tokens = this.tokenizer.tokenize(doc.content);
        for (const token of tokens) {
            this.index.addToken(token, doc.id);
        }
    }
    
    search(query: string): SearchResult[] {
        const tokens = this.tokenizer.tokenize(query);
        const results = this.index.search(tokens);
        return this.ranker.rank(results, query);
    }
}

// Inverted index implementation
class InvertedIndex {
    private index: Map<string, Set<string>>;
    
    constructor() {
        this.index = new Map();
    }
    
    addToken(token: string, docId: string): void {
        if (!this.index.has(token)) {
            this.index.set(token, new Set());
        }
        this.index.get(token).add(docId);
    }
    
    search(tokens: string[]): SearchResult[] {
        const resultSets = tokens
            .map(token => this.index.get(token) || new Set());
        
        // Intersection of sets
        const intersection = resultSets.reduce(
            (acc, set) => new Set([...acc].filter(x => set.has(x))),
            resultSets[0] || new Set()
        );
        
        return Array.from(intersection).map(docId => ({
            docId,
            score: 0
        }));
    }
}
Advanced
30. What is Real-time Analytics?

Real-time analytics processes and analyzes data as it arrives, enabling immediate insights and decision-making.

  • Stream Processing: Continuous data processing
  • Sliding Window: Time-based analysis
  • Aggregations: Real-time metrics
  • Dashboards: Real-time visualization
  • Alerting: Immediate notifications
system-design
// System Design - Real-time Analytics
// Real-time analytics implementation
class RealTimeAnalytics {
    private aggregators: Map<string, Aggregator>;
    private windowSize: number;
    private slidingWindow: SlidingWindow;
    
    constructor(windowSize: number = 60) {
        this.aggregators = new Map();
        this.windowSize = windowSize;
        this.slidingWindow = new SlidingWindow(windowSize);
    }
    
    addEvent(event: AnalyticsEvent): void {
        this.slidingWindow.add(event);
        this.updateAggregations(event);
    }
    
    private updateAggregations(event: AnalyticsEvent): void {
        for (const [key, aggregator] of this.aggregators) {
            aggregator.process(event);
        }
    }
    
    getMetrics(metric: string): Metric {
        const aggregator = this.aggregators.get(metric);
        if (!aggregator) {
            throw new Error(`Metric ${metric} not found`);
        }
        return aggregator.getMetric();
    }
    
    addAggregator(name: string, aggregator: Aggregator): void {
        this.aggregators.set(name, aggregator);
    }
}

// Sliding window for events
class SlidingWindow {
    private windowSize: number;
    private events: Event[];
    
    constructor(windowSize: number) {
        this.windowSize = windowSize;
        this.events = [];
    }
    
    add(event: Event): void {
        this.events.push(event);
        this.cleanup();
    }
    
    getEvents(): Event[] {
        this.cleanup();
        return this.events;
    }
    
    private cleanup(): void {
        const cutoff = Date.now() - this.windowSize * 1000;
        this.events = this.events.filter(e => e.timestamp >= cutoff);
    }
}
Coding Round
31. What is CAP Theorem?

CAP theorem states that a distributed system can only provide two of three guarantees: Consistency, Availability, and Partition Tolerance.

  • Consistency: All nodes see same data
  • Availability: Every request receives a response
  • Partition Tolerance: System continues despite network partitions
  • CP Systems: Consistency + Partition Tolerance
  • AP Systems: Availability + Partition Tolerance
system-design
// System Design - CAP Theorem
// CAP theorem implementation examples

// Consistency (Strong)
class StrongConsistency {
    private nodes: Node[];
    private version: Map<string, number>;
    
    async write(key: string, value: any): Promise<void> {
        const writes = this.nodes.map(node => node.write(key, value));
        await Promise.all(writes);
    }
    
    async read(key: string): Promise<any> {
        const reads = this.nodes.map(node => node.read(key));
        const results = await Promise.all(reads);
        return results[0];
    }
}

// Availability (Eventual)
class EventualConsistency2 {
    private nodes: Node[];
    private replication: Replication;
    
    async write(key: string, value: any): Promise<void> {
        await this.nodes[0].write(key, value);
        this.replication.asyncReplicate(key, value);
    }
    
    async read(key: string): Promise<any> {
        return await this.nodes[0].read(key);
    }
}

// Partition tolerance
class PartitionTolerance {
    private nodes: Node[];
    private partitionStrategy: PartitionStrategy;
    
    async handleNetworkPartition(): Promise<void> {
        // Split nodes into partitions
        const partitions = this.partitionStrategy.partition(this.nodes);
        for (const partition of partitions) {
            this.processPartition(partition);
        }
    }
    
    private processPartition(partition: Node[]): void {
        // Process requests within partition
    }
}
Coding Round
32. What are ACID Transactions?

ACID transactions ensure reliable processing of database operations with Atomicity, Consistency, Isolation, and Durability.

  • Atomicity: All or nothing
  • Consistency: Valid state after transaction
  • Isolation: Concurrent execution isolation
  • Durability: Persistence after commit
  • Isolation Levels: Read Uncommitted, Read Committed, Repeatable Read, Serializable
system-design
// System Design - ACID Transactions
// ACID transaction implementation
class ACIDTransaction {
    private transactions: Transaction[];
    private log: TransactionLog;
    private lockManager: LockManager;
    
    async begin(): Promise<Transaction> {
        const tx = new Transaction();
        this.transactions.push(tx);
        this.log.write('BEGIN', tx.id);
        return tx;
    }
    
    async commit(tx: Transaction): Promise<void> {
        // Commit all changes
        for (const change of tx.changes) {
            await change.apply();
        }
        this.log.write('COMMIT', tx.id);
        tx.status = 'committed';
    }
    
    async rollback(tx: Transaction): Promise<void> {
        // Rollback all changes
        for (const change of tx.changes) {
            await change.undo();
        }
        this.log.write('ROLLBACK', tx.id);
        tx.status = 'aborted';
    }
}

// Isolation levels
class IsolationLevels {
    async serializable(operations: Operation[]): Promise<void> {
        // Strictest isolation level
        const lockManager = new LockManager();
        for (const op of operations) {
            await lockManager.acquire(op.key, 'exclusive');
            await op.execute();
            await lockManager.release(op.key);
        }
    }
    
    async readCommitted(operations: Operation[]): Promise<void> {
        // Write locks only
        const lockManager = new LockManager();
        for (const op of operations) {
            if (op.type === 'write') {
                await lockManager.acquire(op.key, 'exclusive');
                await op.execute();
                await lockManager.release(op.key);
            } else {
                await op.execute();
            }
        }
    }
}
Coding Round
33. What are BASE Properties?

BASE properties describe the behavior of distributed systems: Basically Available, Soft state, Eventual consistency.

  • Basically Available: System remains available
  • Soft State: State may change over time
  • Eventual Consistency: System converges over time
  • Trade-offs: Consistency vs Availability
  • Use cases: NoSQL databases, distributed systems
system-design
// System Design - BASE Properties
// BASE (Basically Available, Soft state, Eventually consistent)
class BASESystem {
    private nodes: Node[];
    private consistencyLevel: ConsistencyLevel;
    
    constructor(consistencyLevel: ConsistencyLevel = 'eventual') {
        this.nodes = nodes;
        this.consistencyLevel = consistencyLevel;
    }
    
    async write(key: string, value: any): Promise<void> {
        // Write to local node
        await this.nodes[0].write(key, value);
        
        // Asynchronously replicate
        this.asyncReplicate(key, value);
    }
    
    async read(key: string): Promise<any> {
        // Read from any available node
        const node = this.getAvailableNode();
        return await node.read(key);
    }
    
    private async asyncReplicate(key: string, value: any): Promise<void> {
        for (const node of this.nodes.slice(1)) {
            try {
                await node.write(key, value);
            } catch (error) {
                // Log failure, continue with other nodes
                console.error(`Replication failed: ${error}`);
            }
        }
    }
    
    private getAvailableNode(): Node {
        for (const node of this.nodes) {
            if (node.isAvailable()) {
                return node;
            }
        }
        return this.nodes[0];
    }
}
Coding Round
34. What is Quorum Consensus?

Quorum consensus ensures data consistency in distributed systems by requiring a majority of nodes to agree on operations.

  • Read Quorum: Minimum nodes for read
  • Write Quorum: Minimum nodes for write
  • Quorum Formula: R + W > N
  • Consistency Levels: Strong, Eventual
  • Trade-offs: Performance vs Consistency
system-design
// System Design - Quorum Consensus
// Quorum consensus implementation
class QuorumConsensus {
    private nodes: Node[];
    private readQuorum: number;
    private writeQuorum: number;
    
    constructor(nodes: Node[], readQuorum: number, writeQuorum: number) {
        this.nodes = nodes;
        this.readQuorum = readQuorum;
        this.writeQuorum = writeQuorum;
    }
    
    async write(key: string, value: any): Promise<void> {
        const writes = this.nodes.map(node => node.write(key, value));
        const results = await Promise.allSettled(writes);
        const successCount = results.filter(r => r.status === 'fulfilled').length;
        
        if (successCount < this.writeQuorum) {
            throw new Error('Write quorum not met');
        }
    }
    
    async read(key: string): Promise<any> {
        const reads = this.nodes.map(node => node.read(key));
        const results = await Promise.allSettled(reads);
        const values = results
            .filter(r => r.status === 'fulfilled')
            .map(r => r.value);
        
        if (values.length < this.readQuorum) {
            throw new Error('Read quorum not met');
        }
        
        return this.resolveVersion(values);
    }
    
    private resolveVersion(values: any[]): any {
        // Return the value with the highest version
        return values[0];
    }
}
Coding Round
35. What is Distributed ID Generation?

Distributed ID generation creates unique identifiers across multiple nodes without centralized coordination.

  • Snowflake: Twitter's ID generator
  • UUID: Universally Unique Identifier
  • Sequential: Ordered IDs
  • ZooKeeper: Coordination service
  • Distributed counters: Atomic increments
system-design
// System Design - Distributed ID Generation
// Snowflake ID generator
class SnowflakeIDGenerator {
    private workerId: number;
    private datacenterId: number;
    private sequence: number = 0;
    private lastTimestamp: number = -1;
    
    private readonly workerIdBits = 5;
    private readonly datacenterIdBits = 5;
    private readonly maxWorkerId = -1 ^ (-1 << this.workerIdBits);
    private readonly maxDatacenterId = -1 ^ (-1 << this.datacenterIdBits);
    private readonly sequenceBits = 12;
    private readonly workerIdShift = this.sequenceBits;
    private readonly datacenterIdShift = this.sequenceBits + this.workerIdBits;
    private readonly timestampShift = this.sequenceBits + this.workerIdBits + this.datacenterIdBits;
    private readonly epoch = 1609459200000; // 2021-01-01
    
    constructor(workerId: number, datacenterId: number) {
        if (workerId > this.maxWorkerId || workerId < 0) {
            throw new Error(`Worker ID must be between 0 and ${this.maxWorkerId}`);
        }
        if (datacenterId > this.maxDatacenterId || datacenterId < 0) {
            throw new Error(`Datacenter ID must be between 0 and ${this.maxDatacenterId}`);
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }
    
    nextId(): bigint {
        let timestamp = this.timestamp();
        
        if (timestamp < this.lastTimestamp) {
            throw new Error('Clock moved backwards');
        }
        
        if (timestamp === this.lastTimestamp) {
            this.sequence = (this.sequence + 1) & ((1 << this.sequenceBits) - 1);
            if (this.sequence === 0) {
                timestamp = this.waitForNextMillisecond(this.lastTimestamp);
            }
        } else {
            this.sequence = 0;
        }
        
        this.lastTimestamp = timestamp;
        
        return (BigInt(timestamp - this.epoch) << BigInt(this.timestampShift)) |
               (BigInt(this.datacenterId) << BigInt(this.datacenterIdShift)) |
               (BigInt(this.workerId) << BigInt(this.workerIdShift)) |
               BigInt(this.sequence);
    }
    
    private timestamp(): number {
        return Date.now();
    }
    
    private waitForNextMillisecond(lastTimestamp: number): number {
        let timestamp = this.timestamp();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timestamp();
        }
        return timestamp;
    }
}
Coding Round
36. What is Data Replication with Failover?

Data replication with failover ensures high availability by automatically switching to a replica when the primary fails.

  • Master-Slave: Primary and backup
  • Failover Detection: Health monitoring
  • Automatic Failover: Automated recovery
  • Promotion: Slave to master
  • Recovery: Restore after failure
system-design
// System Design - Data Replication
// Master-slave replication with failover
class ReplicationWithFailover {
    private master: Node;
    private slaves: Node[];
    private failoverHandler: FailoverHandler;
    
    constructor(master: Node, slaves: Node[]) {
        this.master = master;
        this.slaves = slaves;
        this.failoverHandler = new FailoverHandler();
    }
    
    async write(data: any): Promise<void> {
        try {
            await this.master.write(data);
            this.replicateToSlaves(data);
        } catch (error) {
            await this.handleWriteFailure(data);
        }
    }
    
    async read(): Promise<any> {
        // Read from a random slave for load balancing
        const slave = this.slaves[Math.floor(Math.random() * this.slaves.length)];
        return await slave.read();
    }
    
    private async replicateToSlaves(data: any): Promise<void> {
        for (const slave of this.slaves) {
            try {
                await slave.write(data);
            } catch (error) {
                console.error(`Failed to replicate: ${error}`);
            }
        }
    }
    
    private async handleWriteFailure(data: any): Promise<void> {
        // Promote a slave to master
        const newMaster = await this.failoverHandler.failover(this.master, this.slaves);
        this.master = newMaster;
        await this.master.write(data);
    }
}
Coding Round
37. What is Leader Election?

Leader election is the process of selecting a single node as the leader among a group of nodes in a distributed system.

  • Raft: Consensus algorithm
  • Bully Algorithm: Highest ID wins
  • Election Timeout: Timer for election
  • Heartbeat: Leader communication
  • Term: Election rounds
system-design
// System Design - Leader Election
// Leader election using Raft algorithm
class RaftLeaderElection {
    private nodes: Node[];
    private currentLeader: Node | null;
    private electionTimeout: number;
    
    constructor(nodes: Node[]) {
        this.nodes = nodes;
        this.currentLeader = null;
        this.electionTimeout = 5000;
    }
    
    async startElection(): Promise<void> {
        this.currentLeader = null;
        this.nodes.forEach(node => node.resetVote());
        
        const candidate = this.nodes[0];
        candidate.incrementTerm();
        candidate.requestVotes(this.nodes);
        
        const votes = await this.collectVotes(candidate);
        if (votes > this.nodes.length / 2) {
            candidate.becomeLeader();
            this.currentLeader = candidate;
            console.log(`Leader elected: ${candidate.id}`);
        }
    }
    
    private async collectVotes(candidate: Node): Promise<number> {
        const votePromises = this.nodes.map(node => node.voteFor(candidate));
        const votes = await Promise.all(votePromises);
        return votes.filter(v => v).length;
    }
}
Coding Round
38. What is Distributed Consensus?

Distributed consensus algorithms ensure multiple nodes agree on a single value, enabling coordination and consistency.

  • Paxos: Classic consensus algorithm
  • Raft: Understandable consensus
  • ZAB: ZooKeeper Atomic Broadcast
  • Quorum: Majority agreement
  • Term: Logical time periods
system-design
// System Design - Distributed Consensus
// Paxos consensus algorithm
class PaxosConsensus {
    private nodes: Node[];
    private proposals: Proposal[];
    
    constructor(nodes: Node[]) {
        this.nodes = nodes;
        this.proposals = [];
    }
    
    async propose(value: any): Promise<void> {
        const proposal = new Proposal(value);
        this.proposals.push(proposal);
        
        // Phase 1: Prepare
        const prepareResponses = await this.prepare(proposal);
        if (prepareResponses.length < this.nodes.length / 2) {
            throw new Error('Prepare phase failed');
        }
        
        // Phase 2: Accept
        const acceptResponses = await this.accept(proposal);
        if (acceptResponses.length < this.nodes.length / 2) {
            throw new Error('Accept phase failed');
        }
        
        // Phase 3: Commit
        await this.commit(proposal);
    }
    
    private async prepare(proposal: Proposal): Promise<any[]> {
        const responses = this.nodes.map(node => node.prepare(proposal));
        return Promise.all(responses);
    }
    
    private async accept(proposal: Proposal): Promise<any[]> {
        const responses = this.nodes.map(node => node.accept(proposal));
        return Promise.all(responses);
    }
    
    private async commit(proposal: Proposal): Promise<void> {
        await Promise.all(this.nodes.map(node => node.commit(proposal)));
    }
}
Coding Round
39. What is Service Mesh?

A service mesh is a dedicated infrastructure layer for handling service-to-service communication, providing observability, security, and reliability.

  • Sidecar Proxy: Per-service proxy
  • Control Plane: Configuration management
  • Data Plane: Traffic routing
  • Istio/Linkerd: Service mesh tools
  • Traffic Management: Routing, load balancing
system-design
// System Design - Service Mesh
// Service mesh implementation
class ServiceMesh {
    private sidecarProxies: SidecarProxy[];
    private controlPlane: ControlPlane;
    private dataPlane: DataPlane;
    
    constructor() {
        this.sidecarProxies = [];
        this.controlPlane = new ControlPlane();
        this.dataPlane = new DataPlane();
    }
    
    addService(service: Service): void {
        const proxy = new SidecarProxy(service);
        this.sidecarProxies.push(proxy);
        this.controlPlane.registerService(service);
        this.dataPlane.addRoute(service);
    }
    
    async routeRequest(request: Request): Promise<Response> {
        const service = this.controlPlane.getService(request.service);
        const proxy = this.sidecarProxies.find(p => p.service.id === service.id);
        if (!proxy) {
            throw new Error('Service not found');
        }
        return proxy.handle(request);
    }
}

// Traffic management
class TrafficManagement {
    private routes: Route[];
    private loadBalancer: LoadBalancer;
    
    constructor(routes: Route[], loadBalancer: LoadBalancer) {
        this.routes = routes;
        this.loadBalancer = loadBalancer;
    }
    
    async route(request: Request): Promise<Response> {
        const route = this.findRoute(request);
        if (!route) {
            return new Response('Not Found', { status: 404 });
        }
        
        const service = this.loadBalancer.select(route.services);
        return service.handle(request);
    }
    
    private findRoute(request: Request): Route | null {
        for (const route of this.routes) {
            if (request.url.startsWith(route.path)) {
                return route;
            }
        }
        return null;
    }
}
Coding Round
40. What is Data Migration?

Data migration is the process of moving data from one system to another, often involving transformation and validation.

  • ETL: Extract, Transform, Load
  • Blue-Green: Zero-downtime migration
  • Validation: Data integrity checks
  • Rollback: Revert on failure
  • Migration Strategies: Big Bang, Trickle
system-design
// System Design - Data Migration
// Data migration strategies
class DataMigration {
    private source: DataSource;
    private destination: DataDestination;
    private migrationStrategy: MigrationStrategy;
    
    constructor(source: DataSource, destination: DataDestination, strategy: MigrationStrategy) {
        this.source = source;
        this.destination = destination;
        this.migrationStrategy = strategy;
    }
    
    async migrate(): Promise<void> {
        await this.migrationStrategy.migrate(this.source, this.destination);
    }
}

// Blue-green deployment for database migration
class BlueGreenMigration {
    private blueEnvironment: Database;
    private greenEnvironment: Database;
    private activeEnvironment: 'blue' | 'green';
    
    constructor(blue: Database, green: Database) {
        this.blueEnvironment = blue;
        this.greenEnvironment = green;
        this.activeEnvironment = 'blue';
    }
    
    async migrate(): Promise<void> {
        // Prepare green environment
        await this.prepareGreen();
        
        // Switch traffic
        await this.switchTraffic('green');
        
        // Verify green
        if (await this.verifyGreen()) {
            // Decommission blue
            await this.decommissionBlue();
        } else {
            // Rollback to blue
            await this.rollback();
        }
    }
    
    private async prepareGreen(): Promise<void> {
        // Prepare green environment
        await this.greenEnvironment.migrate();
    }
    
    private async switchTraffic(environment: 'blue' | 'green'): Promise<void> {
        this.activeEnvironment = environment;
        // Switch traffic to active environment
    }
    
    private async verifyGreen(): Promise<boolean> {
        // Verify green environment
        return true;
    }
    
    private async decommissionBlue(): Promise<void> {
        // Decommission blue environment
        await this.blueEnvironment.decommission();
    }
    
    private async rollback(): Promise<void> {
        // Rollback to blue
        this.activeEnvironment = 'blue';
    }
}
Coding Round
41. What is Load Shedding?

Load shedding selectively drops requests when system resources are overloaded to prevent complete failure.

  • Priority-based: Drop low-priority requests
  • Graceful Degradation: Partial functionality
  • Backpressure: Signal overload
  • Rate Limiting: Control request rate
  • Circuit Breaking: Stop failing requests
system-design
// System Design - Load Shedding
// Load shedding implementation
class LoadShedder {
    private thresholds: Map<string, number>;
    private currentLoad: number;
    
    constructor(thresholds: Map<string, number>) {
        this.thresholds = thresholds;
        this.currentLoad = 0;
    }
    
    shouldShed(): boolean {
        return this.currentLoad > this.thresholds.get('cpu') || 
               this.currentLoad > this.thresholds.get('memory');
    }
    
    shed(request: Request): boolean {
        if (!this.shouldShed()) {
            return true;
        }
        
        // Priority-based shedding
        const priority = this.getPriority(request);
        return priority <= this.thresholds.get('priorityThreshold');
    }
    
    private getPriority(request: Request): number {
        // Determine request priority
        return 0;
    }
}
Coding Round
42. What is Backpressure?

Backpressure is a mechanism to prevent system overload by signaling upstream components to slow down or stop sending data.

  • Flow Control: Regulate data flow
  • Reactive Streams: Backpressure protocol
  • Buffering: Temporary storage
  • Dropping: Discard excess data
  • Blocking: Block producer
system-design
// System Design - Backpressure
// Backpressure implementation
class BackpressureHandler {
    private queues: Queue[];
    private maxQueueSize: number;
    
    constructor(maxQueueSize: number) {
        this.queues = [];
        this.maxQueueSize = maxQueueSize;
    }
    
    async process(data: any): Promise<void> {
        const queue = this.getQueue(data);
        
        if (queue.size() >= this.maxQueueSize) {
            // Backpressure: wait or reject
            await this.waitForSpace(queue);
        }
        
        await queue.push(data);
        this.processQueue(queue);
    }
    
    private async waitForSpace(queue: Queue): Promise<void> {
        while (queue.size() >= this.maxQueueSize) {
            await this.sleep(100);
        }
    }
    
    private sleep(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}
Coding Round
43. What is Circuit Breaker with Retry?

Circuit breaker with retry combines failure detection with automatic retry mechanisms to improve reliability.

  • Retry Policy: Number of retries
  • Backoff: Exponential backoff
  • Timeout: Operation timeout
  • Circuit State: Closed, Open, Half-Open
  • Fallback: Alternative response
system-design
// System Design - Circuit Breaker with Retry
// Circuit breaker with retry logic
class CircuitBreakerWithRetry {
    private maxRetries: number;
    private backoffMultiplier: number;
    private breaker: CircuitBreaker;
    
    constructor(maxRetries: number = 3, backoffMultiplier: number = 2) {
        this.maxRetries = maxRetries;
        this.backoffMultiplier = backoffMultiplier;
        this.breaker = new CircuitBreaker();
    }
    
    async execute<T>(fn: () => Promise<T>): Promise<T> {
        let retries = 0;
        let delay = 1000;
        
        while (retries < this.maxRetries) {
            try {
                return await this.breaker.execute(fn);
            } catch (error) {
                retries++;
                if (retries < this.maxRetries) {
                    await this.sleep(delay);
                    delay *= this.backoffMultiplier;
                } else {
                    throw error;
                }
            }
        }
        
        throw new Error('Max retries exceeded');
    }
    
    private sleep(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}
Coding Round
44. What is Health Check?

Health checks monitor the status and availability of system components, enabling automated recovery and load balancing.

  • Liveness Probe: Is the service running?
  • Readiness Probe: Is the service ready?
  • Startup Probe: Is the service started?
  • Grace Period: Time to recover
  • Health Endpoints: /health, /ready
system-design
// System Design - Health Check
// Health check implementation
class HealthChecker {
    private services: Service[];
    private checkInterval: number;
    private healthStatus: Map<string, boolean>;
    
    constructor(services: Service[], checkInterval: number = 30000) {
        this.services = services;
        this.checkInterval = checkInterval;
        this.healthStatus = new Map();
        this.startHealthCheck();
    }
    
    async checkHealth(service: Service): Promise<boolean> {
        try {
            const response = await fetch(`${service.url}/health`, {
                timeout: 5000
            });
            const status = response.status === 200;
            this.healthStatus.set(service.id, status);
            return status;
        } catch (error) {
            this.healthStatus.set(service.id, false);
            return false;
        }
    }
    
    isHealthy(serviceId: string): boolean {
        return this.healthStatus.get(serviceId) || false;
    }
    
    private startHealthCheck(): void {
        setInterval(async () => {
            for (const service of this.services) {
                await this.checkHealth(service);
            }
        }, this.checkInterval);
    }
}
Coding Round
45. What is a Dead Letter Queue?

A dead letter queue stores messages that cannot be processed successfully, allowing for later analysis and recovery.

  • Failed Messages: Unprocessable messages
  • Retry Exhaustion: Max retries reached
  • Manual Processing: Human intervention
  • Analysis: Debugging failures
  • Replay: Reprocess messages
system-design
// System Design - Dead Letter Queue
// Dead letter queue implementation
class DeadLetterQueue {
    private dlq: Queue;
    private maxRetries: number;
    
    constructor(maxRetries: number = 3) {
        this.dlq = new Queue('dlq');
        this.maxRetries = maxRetries;
    }
    
    async process(message: Message): Promise<void> {
        try {
            await this.processMessage(message);
        } catch (error) {
            message.retries = (message.retries || 0) + 1;
            
            if (message.retries >= this.maxRetries) {
                await this.dlq.enqueue(message);
                console.error(`Message moved to DLQ: ${message.id}`);
            } else {
                // Re-queue with delay
                await this.reQueue(message);
            }
        }
    }
    
    private async processMessage(message: Message): Promise<void> {
        // Process message
    }
    
    private async reQueue(message: Message): Promise<void> {
        // Re-queue with exponential backoff
        const delay = Math.pow(2, message.retries) * 1000;
        setTimeout(async () => {
            await this.process(message);
        }, delay);
    }
    
    async processDLQ(): Promise<void> {
        const messages = await this.dlq.dequeueAll();
        for (const message of messages) {
            try {
                await this.processMessage(message);
            } catch (error) {
                console.error(`DLQ processing failed: ${error}`);
            }
        }
    }
}
Coding Round
46. What is Bulkhead Pattern?

The bulkhead pattern isolates failures by partitioning resources into separate pools, preventing cascading failures.

  • Resource Isolation: Separate resource pools
  • Circuit Breaker: Failure isolation
  • Bulkhead: Partition by use case
  • Concurrency Limits: Max concurrent requests
  • Thread Pools: Isolated thread pools
system-design
// System Design - Bulkhead Pattern
// Bulkhead pattern implementation
class Bulkhead {
    private pools: Map<string, Pool>;
    private maxConcurrent: number;
    
    constructor(maxConcurrent: number) {
        this.pools = new Map();
        this.maxConcurrent = maxConcurrent;
    }
    
    async execute<T>(poolName: string, fn: () => Promise<T>): Promise<T> {
        if (!this.pools.has(poolName)) {
            this.pools.set(poolName, new Pool(this.maxConcurrent));
        }
        
        const pool = this.pools.get(poolName);
        return await pool.execute(fn);
    }
}

class Pool {
    private maxConcurrent: number;
    private current: number = 0;
    private queue: Function[];
    
    constructor(maxConcurrent: number) {
        this.maxConcurrent = maxConcurrent;
        this.queue = [];
    }
    
    async execute<T>(fn: () => Promise<T>): Promise<T> {
        if (this.current < this.maxConcurrent) {
            this.current++;
            try {
                return await fn();
            } finally {
                this.current--;
                this.processQueue();
            }
        } else {
            return new Promise((resolve, reject) => {
                this.queue.push(() => {
                    this.execute(fn).then(resolve).catch(reject);
                });
            });
        }
    }
    
    private processQueue(): void {
        if (this.queue.length > 0 && this.current < this.maxConcurrent) {
            const next = this.queue.shift();
            next();
        }
    }
}
Coding Round
47. What is Exponential Backoff?

Exponential backoff is a retry strategy where the delay between retries increases exponentially to reduce system load.

  • Delay: Increasing wait time
  • Jitter: Add randomness
  • Max Retries: Limit retry attempts
  • Backoff Factors: 2x, 4x, 8x
  • Use case: API calls, network operations
system-design
// System Design - Retry with Exponential Backoff
// Exponential backoff implementation
class ExponentialBackoff {
    private maxRetries: number;
    private baseDelay: number;
    private maxDelay: number;
    
    constructor(maxRetries: number = 5, baseDelay: number = 100, maxDelay: number = 10000) {
        this.maxRetries = maxRetries;
        this.baseDelay = baseDelay;
        this.maxDelay = maxDelay;
    }
    
    async execute<T>(fn: () => Promise<T>): Promise<T> {
        let retries = 0;
        let delay = this.baseDelay;
        
        while (retries < this.maxRetries) {
            try {
                return await fn();
            } catch (error) {
                if (retries === this.maxRetries - 1) {
                    throw error;
                }
                
                await this.sleep(delay);
                delay = Math.min(delay * 2, this.maxDelay);
                retries++;
            }
        }
        
        throw new Error('Max retries exceeded');
    }
    
    private sleep(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}
Coding Round
48. What are Rate Limiting Algorithms?

Rate limiting algorithms control the rate of requests to prevent system overload and ensure fair usage.

  • Token Bucket: Tokens refill over time
  • Leaky Bucket: Constant rate output
  • Fixed Window: Count per time window
  • Sliding Window: Rolling time window
  • Sliding Log: Request timestamps
system-design
// System Design - Rate Limiting Algorithms
// Token bucket algorithm
class TokenBucket {
    private capacity: number;
    private tokens: number;
    private refillRate: number;
    private lastRefill: number;
    
    constructor(capacity: number, refillRate: number) {
        this.capacity = capacity;
        this.tokens = capacity;
        this.refillRate = refillRate;
        this.lastRefill = Date.now();
    }
    
    allow(): boolean {
        this.refill();
        if (this.tokens >= 1) {
            this.tokens--;
            return true;
        }
        return false;
    }
    
    private refill(): void {
        const now = Date.now();
        const elapsed = (now - this.lastRefill) / 1000;
        this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillRate);
        this.lastRefill = now;
    }
}

// Leaky bucket algorithm
class LeakyBucket {
    private capacity: number;
    private leakRate: number;
    private water: number;
    private lastLeak: number;
    
    constructor(capacity: number, leakRate: number) {
        this.capacity = capacity;
        this.leakRate = leakRate;
        this.water = 0;
        this.lastLeak = Date.now();
    }
    
    allow(): boolean {
        this.leak();
        if (this.water < this.capacity) {
            this.water++;
            return true;
        }
        return false;
    }
    
    private leak(): void {
        const now = Date.now();
        const elapsed = (now - this.lastLeak) / 1000;
        this.water = Math.max(0, this.water - elapsed * this.leakRate);
        this.lastLeak = now;
    }
}
Coding Round
49. What is Leader-Follower Replication?

Leader-follower replication designates one node as the leader for writes and replicates changes to followers for reads.

  • Leader: Writes allowed
  • Followers: Read-only replicas
  • Replication Log: Write operations
  • Read Consistency: From leader or followers
  • Failover: Promote follower to leader
system-design
// System Design - Leader-Follower Replication
// Leader-follower replication implementation
class LeaderFollowerReplication {
    private leader: Node;
    private followers: Node[];
    private replicationLog: Log[];
    
    constructor(leader: Node, followers: Node[]) {
        this.leader = leader;
        this.followers = followers;
        this.replicationLog = [];
    }
    
    async write(data: any): Promise<void> {
        // Write to leader
        await this.leader.write(data);
        this.replicationLog.push({
            timestamp: Date.now(),
            data,
            type: 'WRITE'
        });
        
        // Replicate to followers asynchronously
        this.replicateToFollowers(data);
    }
    
    async read(): Promise<any> {
        // Read from leader for consistency
        return await this.leader.read();
    }
    
    private async replicateToFollowers(data: any): Promise<void> {
        for (const follower of this.followers) {
            try {
                await follower.write(data);
            } catch (error) {
                console.error(`Failed to replicate to follower: ${error}`);
            }
        }
    }
}
Coding Round
50. What is Multi-Paxos?

Multi-Paxos extends the Paxos consensus algorithm to handle multiple instances of consensus, enabling state machine replication.

  • Multiple Instances: Many consensus rounds
  • Leaders: Single leader per instance
  • State Machine: Deterministic operations
  • Replication: Replicate state machine
  • Stable Leaders: Reduce overhead
system-design
// System Design - Multi-Paxos
// Multi-Paxos implementation
class MultiPaxos {
    private nodes: Node[];
    private currentLeader: Node | null;
    private proposals: Map<number, Proposal>;
    private instanceId: number;
    
    constructor(nodes: Node[]) {
        this.nodes = nodes;
        this.currentLeader = null;
        this.proposals = new Map();
        this.instanceId = 0;
    }
    
    async propose(value: any): Promise<void> {
        if (!this.currentLeader) {
            await this.electLeader();
        }
        
        const proposal = new Proposal(++this.instanceId, value);
        this.proposals.set(proposal.id, proposal);
        await this.currentLeader.propose(proposal);
    }
    
    private async electLeader(): Promise<void> {
        // Leader election
        for (const node of this.nodes) {
            const votes = await node.requestVotes();
            if (votes > this.nodes.length / 2) {
                this.currentLeader = node;
                node.becomeLeader();
                break;
            }
        }
    }
}
Coding Round
51. What is a Distributed Queue?

A distributed queue is a messaging system that stores and processes messages across multiple nodes, providing scalability and fault tolerance.

  • Partitions: Data sharding
  • Consumer Groups: Load balancing
  • Offsets: Message position
  • Replication: Data redundancy
  • Delivery Guarantees: At-least-once, At-most-once
system-design
// System Design - Distributed Queue
// Distributed queue implementation
class DistributedQueue {
    private partitions: Partition[];
    private consumerGroups: Map<string, ConsumerGroup>;
    
    constructor(partitions: Partition[]) {
        this.partitions = partitions;
        this.consumerGroups = new Map();
    }
    
    async publish(key: string, message: any): Promise<void> {
        const partition = this.getPartition(key);
        await partition.append(message);
    }
    
    async subscribe(groupId: string, callback: (message: any) => void): Promise<void> {
        if (!this.consumerGroups.has(groupId)) {
            this.consumerGroups.set(groupId, new ConsumerGroup(groupId));
        }
        
        const group = this.consumerGroups.get(groupId);
        group.addConsumer(callback);
        
        // Start consuming
        this.consume(group);
    }
    
    private getPartition(key: string): Partition {
        const hash = this.hash(key);
        return this.partitions[hash % this.partitions.length];
    }
    
    private async consume(group: ConsumerGroup): Promise<void> {
        // Consumer loop
        while (true) {
            for (const partition of this.partitions) {
                const messages = await partition.poll();
                for (const message of messages) {
                    group.distribute(message);
                }
            }
        }
    }
    
    private hash(key: string): number {
        let hash = 0;
        for (let i = 0; i < key.length; i++) {
            hash = (hash << 5) - hash + key.charCodeAt(i);
            hash = hash & hash;
        }
        return Math.abs(hash);
    }
}
Coding Round
52. What is Distributed Lock with TTL?

Distributed lock with TTL (Time-To-Live) automatically releases locks after a timeout to prevent deadlocks.

  • TTL: Time-based expiration
  • Renewal: Extend lock before expiration
  • Fencing Token: Prevent stale locks
  • Redlock: Redis-based lock
  • Watchdog: Automatic renewal
system-design
// System Design - Distributed Locking with TTL
// Distributed lock with TTL and renewal
class DistributedLockWithTTL {
    private redis: Redis;
    private lockKey: string;
    private lockValue: string;
    private ttl: number;
    private renewalInterval: number;
    
    constructor(redis: Redis, lockKey: string, ttl: number = 30000, renewalInterval: number = 10000) {
        this.redis = redis;
        this.lockKey = lockKey;
        this.lockValue = `${process.pid}-${Date.now()}`;
        this.ttl = ttl;
        this.renewalInterval = renewalInterval;
    }
    
    async acquire(): Promise<boolean> {
        const result = await this.redis.set(
            this.lockKey,
            this.lockValue,
            'NX',
            'PX',
            this.ttl
        );
        
        if (result === 'OK') {
            this.startRenewal();
            return true;
        }
        return false;
    }
    
    async release(): Promise<void> {
        const script = `
            if redis.call("get", KEYS[1]) == ARGV[1] then
                return redis.call("del", KEYS[1])
            else
                return 0
            end
        `;
        await this.redis.eval(script, 1, this.lockKey, this.lockValue);
        this.stopRenewal();
    }
    
    private startRenewal(): void {
        this.renewalIntervalId = setInterval(async () => {
            const script = `
                if redis.call("get", KEYS[1]) == ARGV[1] then
                    return redis.call("pexpire", KEYS[1], ARGV[2])
                else
                    return 0
                end
            `;
            await this.redis.eval(script, 1, this.lockKey, this.lockValue, this.ttl);
        }, this.renewalInterval);
    }
    
    private stopRenewal(): void {
        if (this.renewalIntervalId) {
            clearInterval(this.renewalIntervalId);
        }
    }
}
Coding Round
53. What is Read-Through Cache?

Read-through cache automatically loads data from the database into the cache when a cache miss occurs.

  • Cache Miss: Data not in cache
  • Auto-load: Load from database
  • Cache Fill: Populate cache
  • TTL: Cache expiration
  • Consistency: Cache invalidation
system-design
// System Design - Read-Through Cache
// Read-through cache implementation
class ReadThroughCache<K, V> {
    private cache: Cache<K, V>;
    private dataStore: DataStore<K, V>;
    
    constructor(cache: Cache<K, V>, dataStore: DataStore<K, V>) {
        this.cache = cache;
        this.dataStore = dataStore;
    }
    
    async get(key: K): Promise<V | null> {
        let value = await this.cache.get(key);
        if (value === null) {
            value = await this.dataStore.get(key);
            if (value !== null) {
                await this.cache.set(key, value);
            }
        }
        return value;
    }
    
    async set(key: K, value: V): Promise<void> {
        await this.dataStore.set(key, value);
        await this.cache.set(key, value);
    }
    
    async invalidate(key: K): Promise<void> {
        await this.cache.delete(key);
    }
}
Coding Round
54. What is Conflict Resolution in Data Replication?

Conflict resolution handles concurrent updates to the same data in distributed systems using various strategies.

  • Last Write Wins: Latest timestamp wins
  • Version Vectors: Track versions
  • Merge: Combine conflicting values
  • Application-specific: Custom resolution
  • CRDTs: Conflict-free data types
system-design
// System Design - Data Replication with Conflict Resolution
// Conflict resolution strategies
class ConflictResolver {
    resolve(versions: Version[]): Version {
        // Last write wins
        return this.lastWriteWins(versions);
    }
    
    private lastWriteWins(versions: Version[]): Version {
        return versions.reduce((latest, current) => {
            return current.timestamp > latest.timestamp ? current : latest;
        });
    }
    
    private highestVersionWins(versions: Version[]): Version {
        return versions.reduce((latest, current) => {
            return current.version > latest.version ? current : latest;
        });
    }
    
    private mergeValues(versions: Version[]): Version {
        // Merge values from all versions
        // This is application-specific
        return versions[0];
    }
}

// Vector clock conflict resolution
class VectorClockResolver {
    resolve(versions: VectorClockVersion[]): VectorClockVersion {
        // Find versions with concurrent updates
        const concurrentVersions = this.findConcurrent(versions);
        if (concurrentVersions.length === 1) {
            return concurrentVersions[0];
        }
        
        // Merge concurrent updates
        return this.merge(concurrentVersions);
    }
    
    private findConcurrent(versions: VectorClockVersion[]): VectorClockVersion[] {
        // Find concurrent versions
        return versions;
    }
    
    private merge(versions: VectorClockVersion[]): VectorClockVersion {
        // Merge concurrent versions
        return versions[0];
    }
}
Coding Round
55. What is Distributed Configuration?

Distributed configuration manages configuration settings across multiple services and environments in a centralized way.

  • Centralized Store: Single source of truth
  • Dynamic Updates: Change without restart
  • Versioning: Configuration history
  • Watch/Notify: Configuration change detection
  • Security: Access control
system-design
// System Design - Distributed Configuration
// Distributed configuration management
class DistributedConfig {
    private config: Map<string, any>;
    private watchers: Map<string, ((value: any) => void)[]>;
    private storage: ConfigStorage;
    
    constructor(storage: ConfigStorage) {
        this.config = new Map();
        this.watchers = new Map();
        this.storage = storage;
        this.loadConfig();
    }
    
    async get(key: string): Promise<any> {
        return this.config.get(key);
    }
    
    async set(key: string, value: any): Promise<void> {
        this.config.set(key, value);
        await this.storage.save(key, value);
        this.notifyWatchers(key, value);
    }
    
    watch(key: string, callback: (value: any) => void): void {
        if (!this.watchers.has(key)) {
            this.watchers.set(key, []);
        }
        this.watchers.get(key).push(callback);
    }
    
    private async loadConfig(): Promise<void> {
        const keys = await this.storage.getAllKeys();
        for (const key of keys) {
            const value = await this.storage.get(key);
            this.config.set(key, value);
        }
    }
    
    private notifyWatchers(key: string, value: any): void {
        const watchers = this.watchers.get(key);
        if (watchers) {
            for (const watcher of watchers) {
                watcher(value);
            }
        }
    }
}
Coding Round
56. What are Feature Flags?

Feature flags enable dynamic feature toggling without code deployment, supporting A/B testing and gradual rollouts.

  • Toggle: Enable/disable features
  • Targeting: User-based rollout
  • Percentage Rollout: Gradual release
  • Kill Switch: Emergency disable
  • Control Plane: Flag management
system-design
// System Design - Feature Flags
// Feature flag system
class FeatureFlags {
    private flags: Map<string, FeatureFlag>;
    private storage: FlagStorage;
    private contexts: Map<string, any>;
    
    constructor(storage: FlagStorage) {
        this.flags = new Map();
        this.storage = storage;
        this.contexts = new Map();
        this.loadFlags();
    }
    
    async isEnabled(flagName: string, context?: any): Promise<boolean> {
        const flag = this.flags.get(flagName);
        if (!flag) {
            return false;
        }
        
        // Check if flag is active
        if (!flag.active) {
            return false;
        }
        
        // Check targeting
        if (flag.targeting) {
            return this.evaluateTargeting(flag.targeting, context);
        }
        
        // Rollout percentage
        if (flag.rolloutPercentage !== undefined) {
            return this.evaluateRollout(flag.rolloutPercentage, context);
        }
        
        return flag.defaultValue || false;
    }
    
    async setFlag(flag: FeatureFlag): Promise<void> {
        this.flags.set(flag.name, flag);
        await this.storage.save(flag);
    }
    
    private evaluateTargeting(targeting: Targeting, context: any): boolean {
        // Evaluate targeting rules
        return true;
    }
    
    private evaluateRollout(percentage: number, context: any): boolean {
        // Evaluate rollout percentage
        return Math.random() * 100 < percentage;
    }
    
    private async loadFlags(): Promise<void> {
        const flags = await this.storage.getAll();
        for (const flag of flags) {
            this.flags.set(flag.name, flag);
        }
    }
}
Coding Round
57. What is Service Discovery with Health Checks?

Service discovery with health checks dynamically registers and deregisters services based on their health status.

  • Health Check: Monitor service health
  • Registration: Register healthy services
  • Deregistration: Remove unhealthy services
  • Load Balancing: Select healthy instances
  • Consul/etcd: Service discovery tools
system-design
// System Design - Service Discovery with Health Checks
// Service discovery with health checks
class ServiceDiscoveryWithHealth {
    private services: Map<string, ServiceInstance[]>;
    private healthCheck: HealthCheck;
    private loadBalancer: LoadBalancer;
    private deregisterTimeout: number;
    
    constructor(healthCheck: HealthCheck, loadBalancer: LoadBalancer, deregisterTimeout: number = 30000) {
        this.services = new Map();
        this.healthCheck = healthCheck;
        this.loadBalancer = loadBalancer;
        this.deregisterTimeout = deregisterTimeout;
        this.startHealthCheck();
    }
    
    register(serviceName: string, instance: ServiceInstance): void {
        if (!this.services.has(serviceName)) {
            this.services.set(serviceName, []);
        }
        this.services.get(serviceName).push(instance);
    }
    
    deregister(serviceName: string, instanceId: string): void {
        const instances = this.services.get(serviceName);
        if (instances) {
            this.services.set(
                serviceName,
                instances.filter(i => i.id !== instanceId)
            );
        }
    }
    
    discover(serviceName: string): ServiceInstance | null {
        const instances = this.services.get(serviceName);
        if (!instances || instances.length === 0) {
            return null;
        }
        
        // Filter healthy instances
        const healthyInstances = instances.filter(i => i.isHealthy());
        if (healthyInstances.length === 0) {
            // Try to revive unhealthy instances
            this.tryRevive(serviceName);
            return null;
        }
        
        return this.loadBalancer.select(healthyInstances);
    }
    
    private startHealthCheck(): void {
        setInterval(async () => {
            for (const [serviceName, instances] of this.services) {
                const updatedInstances = await Promise.all(
                    instances.map(async (instance) => {
                        const isHealthy = await this.healthCheck.check(instance);
                        instance.setHealth(isHealthy);
                        return instance;
                    })
                );
                
                // Keep only healthy instances or those that can be revived
                const validInstances = updatedInstances.filter(
                    instance => instance.isHealthy() || 
                    (Date.now() - instance.lastCheck < this.deregisterTimeout)
                );
                
                this.services.set(serviceName, validInstances);
            }
        }, 10000);
    }
    
    private async tryRevive(serviceName: string): Promise<void> {
        const instances = this.services.get(serviceName);
        if (!instances) return;
        
        for (const instance of instances) {
            if (await this.healthCheck.check(instance)) {
                instance.setHealth(true);
                break;
            }
        }
    }
}
Coding Round
58. What is API Versioning?

API versioning allows multiple versions of an API to coexist, enabling backward-compatible evolution.

  • URL Path: /api/v1/users
  • Headers: Accept-Version: v1
  • Query Parameters: ?version=v1
  • Media Type: Content-Type: application/vnd.api.v1+json
  • Versioning Strategy: Semantic versioning
system-design
// System Design - API Versioning
// API versioning strategies
class APIVersioning {
    private versions: Map<string, APIVersion>;
    private defaultVersion: string;
    
    constructor(defaultVersion: string = 'v1') {
        this.versions = new Map();
        this.defaultVersion = defaultVersion;
    }
    
    registerVersion(version: APIVersion): void {
        this.versions.set(version.name, version);
    }
    
    getVersion(request: Request): APIVersion {
        // URL path versioning: /api/v1/users
        const pathVersion = this.extractPathVersion(request.url);
        if (pathVersion && this.versions.has(pathVersion)) {
            return this.versions.get(pathVersion);
        }
        
        // Header versioning: Accept-Version: v1
        const headerVersion = this.extractHeaderVersion(request.headers);
        if (headerVersion && this.versions.has(headerVersion)) {
            return this.versions.get(headerVersion);
        }
        
        // Query parameter versioning: ?version=v1
        const queryVersion = this.extractQueryVersion(request.url);
        if (queryVersion && this.versions.has(queryVersion)) {
            return this.versions.get(queryVersion);
        }
        
        return this.versions.get(this.defaultVersion);
    }
    
    private extractPathVersion(url: string): string | null {
        const match = url.match(//api/(vd+)/);
        return match ? match[1] : null;
    }
    
    private extractHeaderVersion(headers: Headers): string | null {
        return headers.get('Accept-Version') || null;
    }
    
    private extractQueryVersion(url: string): string | null {
        const params = new URLSearchParams(url);
        return params.get('version') || null;
    }
}
Coding Round
59. What is API Documentation?

API documentation provides comprehensive information about API endpoints, parameters, responses, and usage examples.

  • OpenAPI/Swagger: Specification format
  • Endpoints: Paths and methods
  • Parameters: Input requirements
  • Responses: Output formats
  • Examples: Usage examples
system-design
// System Design - API Documentation
// API documentation generation
class APIDocumentation {
    private endpoints: Endpoint[];
    private schemas: Schema[];
    
    constructor() {
        this.endpoints = [];
        this.schemas = [];
    }
    
    addEndpoint(endpoint: Endpoint): void {
        this.endpoints.push(endpoint);
    }
    
    addSchema(schema: Schema): void {
        this.schemas.push(schema);
    }
    
    generateOpenAPI(): OpenAPIDocument {
        return {
            openapi: '3.0.0',
            info: {
                title: 'API Documentation',
                version: '1.0.0'
            },
            paths: this.generatePaths(),
            components: {
                schemas: this.generateSchemas()
            }
        };
    }
    
    private generatePaths(): Paths {
        const paths: Paths = {};
        for (const endpoint of this.endpoints) {
            paths[endpoint.path] = {
                [endpoint.method]: {
                    summary: endpoint.summary,
                    description: endpoint.description,
                    parameters: endpoint.parameters,
                    responses: endpoint.responses
                }
            };
        }
        return paths;
    }
    
    private generateSchemas(): Schemas {
        const schemas: Schemas = {};
        for (const schema of this.schemas) {
            schemas[schema.name] = {
                type: schema.type,
                properties: schema.properties,
                required: schema.required
            };
        }
        return schemas;
    }
}
Coding Round
60. What is Rate Limiting with Redis?

Rate limiting with Redis uses Redis data structures to implement distributed rate limiting across multiple nodes.

  • Sorted Sets: Track requests by timestamp
  • Atomic Operations: Redis Lua scripts
  • Sliding Window: Time-based window
  • Token Bucket: Redis-based token bucket
  • Distributed: Rate limiting across nodes
system-design
// System Design - API Rate Limiting with Redis
// Rate limiting with Redis
class RedisRateLimiter {
    private redis: Redis;
    private maxRequests: number;
    private windowSize: number;
    
    constructor(redis: Redis, maxRequests: number, windowSize: number) {
        this.redis = redis;
        this.maxRequests = maxRequests;
        this.windowSize = windowSize;
    }
    
    async allowRequest(key: string): Promise<boolean> {
        const now = Date.now();
        const windowStart = now - this.windowSize;
        const redisKey = `rate_limit:${key}`;
        
        // Remove old requests
        await this.redis.zremrangebyscore(redisKey, 0, windowStart);
        
        // Count requests in current window
        const count = await this.redis.zcard(redisKey);
        
        if (count < this.maxRequests) {
            await this.redis.zadd(redisKey, now, now.toString());
            await this.redis.expire(redisKey, this.windowSize / 1000);
            return true;
        }
        
        return false;
    }
}
Coding Round
61. What is API Gateway with Authentication?

API gateway with authentication handles user authentication and authorization before routing requests to services.

  • JWT: JSON Web Token validation
  • OAuth2: Authorization framework
  • API Keys: Simple authentication
  • User Context: Pass user info to services
  • Role-based: Access control
system-design
// System Design - API Gateway with Authentication
// API gateway with JWT authentication
class JWTGateway {
    private secret: string;
    private routes: Route[];
    
    constructor(secret: string, routes: Route[]) {
        this.secret = secret;
        this.routes = routes;
    }
    
    async handle(request: Request): Promise<Response> {
        // Extract JWT token
        const token = this.extractToken(request);
        if (!token) {
            return new Response('Unauthorized', { status: 401 });
        }
        
        // Verify JWT
        try {
            const payload = await this.verifyToken(token);
            // Add user info to request context
            request.user = payload;
            
            // Route request
            return await this.routeRequest(request);
        } catch (error) {
            return new Response('Invalid token', { status: 401 });
        }
    }
    
    private extractToken(request: Request): string | null {
        const authHeader = request.headers.get('Authorization');
        if (authHeader && authHeader.startsWith('Bearer ')) {
            return authHeader.substring(7);
        }
        return null;
    }
    
    private async verifyToken(token: string): Promise<any> {
        // Verify JWT token
        return { userId: '123', roles: ['user'] };
    }
    
    private async routeRequest(request: Request): Promise<Response> {
        // Route to appropriate service
        return new Response('OK');
    }
}
Coding Round
62. What is API Gateway with Caching?

API gateway with caching improves performance by caching responses at the gateway level.

  • Cache Key: Based on request
  • TTL: Cache expiration
  • Cache Invalidation: Remove stale cache
  • Response Caching: Cache API responses
  • Cache Control: Cache headers
system-design
// System Design - API Gateway with Caching
// API gateway with caching
class CachingGateway {
    private cache: Cache;
    private routes: Route[];
    private ttl: number;
    
    constructor(cache: Cache, routes: Route[], ttl: number = 300) {
        this.cache = cache;
        this.routes = routes;
        this.ttl = ttl;
    }
    
    async handle(request: Request): Promise<Response> {
        // Check cache
        const cacheKey = this.getCacheKey(request);
        const cachedResponse = await this.cache.get(cacheKey);
        if (cachedResponse) {
            return cachedResponse;
        }
        
        // Route request
        const response = await this.routeRequest(request);
        
        // Cache successful responses
        if (response.status === 200) {
            await this.cache.set(cacheKey, response, this.ttl);
        }
        
        return response;
    }
    
    private getCacheKey(request: Request): string {
        return `${request.method}:${request.url}`;
    }
    
    private async routeRequest(request: Request): Promise<Response> {
        // Route to appropriate service
        return new Response('OK');
    }
}
Coding Round
63. What is GraphQL Gateway?

A GraphQL gateway provides a single GraphQL endpoint that combines multiple underlying GraphQL or REST services.

  • Schema Federation: Combine schemas
  • Query Planning: Optimize queries
  • Federation: Apollo Federation
  • Delegation: Forward subqueries
  • Batching: Batch multiple requests
system-design
// System Design - GraphQL Gateway
// GraphQL gateway implementation
class GraphQLGateway {
    private schemas: Schema[];
    private resolvers: Resolvers;
    
    constructor(schemas: Schema[], resolvers: Resolvers) {
        this.schemas = schemas;
        this.resolvers = resolvers;
    }
    
    async execute(query: string, variables: any): Promise<any> {
        // Parse and validate query
        const parsed = this.parseQuery(query);
        this.validateQuery(parsed);
        
        // Execute query
        return await this.executeQuery(parsed, variables);
    }
    
    private parseQuery(query: string): ParsedQuery {
        // Parse GraphQL query
        return { operation: 'query', fields: [] };
    }
    
    private validateQuery(query: ParsedQuery): void {
        // Validate against schema
    }
    
    private async executeQuery(query: ParsedQuery, variables: any): Promise<any> {
        // Execute resolvers
        const result = {};
        for (const field of query.fields) {
            const resolver = this.resolvers[field.name];
            if (resolver) {
                result[field.name] = await resolver(variables);
            }
        }
        return result;
    }
}
Coding Round
64. What is gRPC Gateway?

A gRPC gateway enables RESTful HTTP/JSON access to gRPC services, providing interoperability.

  • Protobuf: Protocol buffers
  • HTTP/JSON: REST API access
  • Transcoding: Convert between formats
  • Interceptors: Middleware support
  • Load Balancing: Distribute requests
system-design
// System Design - gRPC Gateway
// gRPC gateway implementation
class GRPCGateway {
    private services: Service[];
    private interceptors: Interceptor[];
    
    constructor(services: Service[], interceptors: Interceptor[] = []) {
        this.services = services;
        this.interceptors = interceptors;
    }
    
    async call(serviceName: string, method: string, request: any): Promise<any> {
        const service = this.services.find(s => s.name === serviceName);
        if (!service) {
            throw new Error(`Service ${serviceName} not found`);
        }
        
        const methodHandler = service.methods[method];
        if (!methodHandler) {
            throw new Error(`Method ${method} not found`);
        }
        
        // Apply interceptors
        let context = { request };
        for (const interceptor of this.interceptors) {
            context = await interceptor(context);
        }
        
        // Execute method
        return await methodHandler(context.request);
    }
}
Coding Round
65. What is WebSocket Gateway?

A WebSocket gateway manages WebSocket connections, providing real-time bidirectional communication.

  • Connection Management: Handle WebSocket connections
  • Authentication: Secure WebSocket
  • Room Management: Group communication
  • Message Broadcasting: Send to multiple clients
  • Scalability: Horizontal scaling
system-design
// System Design - WebSocket Gateway
// WebSocket gateway implementation
class WebSocketGateway {
    private connections: Map<string, WebSocket>;
    private rooms: Map<string, Set<string>>;
    private authentication: AuthService;
    
    constructor(authentication: AuthService) {
        this.connections = new Map();
        this.rooms = new Map();
        this.authentication = authentication;
    }
    
    async handleConnection(ws: WebSocket, token: string): Promise<void> {
        // Authenticate
        const user = await this.authentication.authenticate(token);
        if (!user) {
            ws.close(1008, 'Unauthorized');
            return;
        }
        
        const clientId = user.id;
        this.connections.set(clientId, ws);
        
        ws.on('message', (message) => {
            this.handleMessage(clientId, message);
        });
        
        ws.on('close', () => {
            this.handleDisconnect(clientId);
        });
    }
    
    private handleMessage(clientId: string, message: any): void {
        const data = JSON.parse(message);
        
        switch (data.type) {
            case 'join':
                this.joinRoom(clientId, data.room);
                break;
            case 'leave':
                this.leaveRoom(clientId, data.room);
                break;
            case 'message':
                this.broadcast(data.room, {
                    from: clientId,
                    data: data.payload
                });
                break;
        }
    }
    
    private joinRoom(clientId: string, room: string): void {
        if (!this.rooms.has(room)) {
            this.rooms.set(room, new Set());
        }
        this.rooms.get(room).add(clientId);
    }
    
    private leaveRoom(clientId: string, room: string): void {
        const clients = this.rooms.get(room);
        if (clients) {
            clients.delete(clientId);
        }
    }
    
    private broadcast(room: string, message: any): void {
        const clients = this.rooms.get(room);
        if (!clients) return;
        
        for (const clientId of clients) {
            const ws = this.connections.get(clientId);
            if (ws) {
                ws.send(JSON.stringify(message));
            }
        }
    }
    
    private handleDisconnect(clientId: string): void {
        this.connections.delete(clientId);
        for (const [room, clients] of this.rooms) {
            clients.delete(clientId);
        }
    }
}
Coding Round
66. What is Server-Sent Events (SSE)?

Server-Sent Events enable servers to push real-time updates to clients over HTTP connections.

  • Event Stream: Continuous updates
  • Auto-reconnect: Automatic reconnection
  • Event Types: Named events
  • Last-Event-ID: Resume from last event
  • Use cases: Notifications, live updates
system-design
// System Design - Server-Sent Events
// SSE implementation
class SSEHandler {
    private clients: Map<string, Client>;
    private events: Event[];
    
    constructor() {
        this.clients = new Map();
        this.events = [];
    }
    
    subscribe(clientId: string, response: Response): void {
        const client = {
            id: clientId,
            response,
            lastEventId: 0
        };
        this.clients.set(clientId, client);
        this.sendInitialEvents(client);
    }
    
    unsubscribe(clientId: string): void {
        this.clients.delete(clientId);
    }
    
    emit(event: Event): void {
        this.events.push(event);
        this.broadcast(event);
    }
    
    private sendInitialEvents(client: Client): void {
        const events = this.events.slice(client.lastEventId);
        for (const event of events) {
            this.sendEvent(client, event);
        }
        client.lastEventId = this.events.length;
    }
    
    private sendEvent(client: Client, event: Event): void {
        const data = `event: ${event.type}\ndata: ${JSON.stringify(event.data)}\n\n`;
        client.response.write(data);
    }
    
    private broadcast(event: Event): void {
        for (const [id, client] of this.clients) {
            this.sendEvent(client, event);
            client.lastEventId = this.events.length;
        }
    }
}
Coding Round
67. What is Data Streaming?

Data streaming enables continuous processing of data as it arrives, supporting real-time analytics and event-driven applications.

  • Streams: Continuous data flow
  • Partitions: Parallel processing
  • Consumer Groups: Load balancing
  • Exactly-Once: Delivery guarantees
  • Kafka/Kinesis: Streaming platforms
system-design
// System Design - Data Streaming
// Data streaming implementation
class DataStream {
    private streams: Map<string, Stream>;
    private consumers: Map<string, Consumer>;
    private partitions: Map<string, Partition>;
    
    constructor() {
        this.streams = new Map();
        this.consumers = new Map();
        this.partitions = new Map();
    }
    
    createStream(name: string, partitions: number): void {
        this.streams.set(name, new Stream(name, partitions));
    }
    
    produce(streamName: string, key: string, value: any): void {
        const stream = this.streams.get(streamName);
        if (!stream) {
            throw new Error(`Stream ${streamName} not found`);
        }
        stream.produce(key, value);
    }
    
    consume(streamName: string, consumerGroup: string): Consumer {
        const stream = this.streams.get(streamName);
        if (!stream) {
            throw new Error(`Stream ${streamName} not found`);
        }
        
        const consumer = new Consumer(consumerGroup, stream);
        this.consumers.set(consumer.id, consumer);
        return consumer;
    }
}
Coding Round
68. What is a Data Lake?

A data lake is a centralized repository that stores vast amounts of raw data in its native format for future analysis.

  • Raw Data: Unprocessed data
  • Schema-on-Read: Apply schema when reading
  • Scalability: Petabyte-scale storage
  • Data Catalog: Data discovery
  • Use cases: Big data, analytics
system-design
// System Design - Data Lake
// Data lake implementation
class DataLake {
    private storage: Storage;
    private catalog: Catalog;
    private partitions: Partition[];
    
    constructor(storage: Storage, catalog: Catalog) {
        this.storage = storage;
        this.catalog = catalog;
        this.partitions = [];
    }
    
    async write(path: string, data: any): Promise<void> {
        await this.storage.write(path, data);
        this.catalog.addEntry(path, data);
    }
    
    async read(path: string): Promise<any> {
        return await this.storage.read(path);
    }
    
    async query(query: string): Promise<any[]> {
        // Query data lake
        const entries = this.catalog.search(query);
        const results = [];
        for (const entry of entries) {
            const data = await this.storage.read(entry.path);
            results.push(data);
        }
        return results;
    }
    
    addPartition(partition: Partition): void {
        this.partitions.push(partition);
    }
}
Coding Round
69. What is Data Validation?

Data validation ensures data quality by checking data against predefined rules and schemas.

  • Schema Validation: Structure validation
  • Type Validation: Data type checks
  • Range Validation: Value bounds
  • Format Validation: Pattern matching
  • Business Rules: Domain-specific validation
system-design
// System Design - Data Validation
// Data validation framework
class DataValidator {
    private schemas: Map<string, Schema>;
    
    constructor() {
        this.schemas = new Map();
    }
    
    registerSchema(name: string, schema: Schema): void {
        this.schemas.set(name, schema);
    }
    
    validate(data: any, schemaName: string): ValidationResult {
        const schema = this.schemas.get(schemaName);
        if (!schema) {
            return { valid: false, errors: [`Schema ${schemaName} not found`] };
        }
        
        return this.validateAgainstSchema(data, schema);
    }
    
    private validateAgainstSchema(data: any, schema: Schema): ValidationResult {
        const errors = [];
        
        // Validate required fields
        for (const field of schema.required) {
            if (!data[field]) {
                errors.push(`Missing required field: ${field}`);
            }
        }
        
        // Validate types
        for (const [field, type] of Object.entries(schema.properties)) {
            if (data[field] !== undefined) {
                if (!this.validateType(data[field], type)) {
                    errors.push(`Invalid type for field: ${field}`);
                }
            }
        }
        
        return {
            valid: errors.length === 0,
            errors
        };
    }
    
    private validateType(value: any, type: string): boolean {
        switch (type) {
            case 'string':
                return typeof value === 'string';
            case 'number':
                return typeof value === 'number';
            case 'boolean':
                return typeof value === 'boolean';
            case 'array':
                return Array.isArray(value);
            case 'object':
                return typeof value === 'object' && !Array.isArray(value);
            default:
                return false;
        }
    }
}
Coding Round
70. What is Data Encryption?

Data encryption protects sensitive data by converting it into an unreadable format using cryptographic algorithms.

  • Symmetric Encryption: Same key for encrypt/decrypt
  • Asymmetric Encryption: Public/private keys
  • AES: Advanced Encryption Standard
  • RSA: Public-key cryptography
  • TLS/SSL: Transport layer security
system-design
// System Design - Data Encryption
// Data encryption implementation
class DataEncryption {
    private algorithm: string;
    private key: Buffer;
    private iv: Buffer;
    
    constructor(algorithm: string = 'aes-256-cbc') {
        this.algorithm = algorithm;
        this.key = Buffer.from(process.env.ENCRYPTION_KEY || 'default-key-32-characters-long!', 'utf-8');
        this.iv = Buffer.from(process.env.IV || 'default-iv-16chars', 'utf-8');
    }
    
    encrypt(text: string): string {
        const cipher = crypto.createCipheriv(this.algorithm, this.key, this.iv);
        let encrypted = cipher.update(text, 'utf8', 'hex');
        encrypted += cipher.final('hex');
        return encrypted;
    }
    
    decrypt(encrypted: string): string {
        const decipher = crypto.createDecipheriv(this.algorithm, this.key, this.iv);
        let decrypted = decipher.update(encrypted, 'hex', 'utf8');
        decrypted += decipher.final('utf8');
        return decrypted;
    }
    
    encryptObject(obj: any): string {
        return this.encrypt(JSON.stringify(obj));
    }
    
    decryptObject(encrypted: string): any {
        return JSON.parse(this.decrypt(encrypted));
    }
}
Coding Round
71. What is Data Compression?

Data compression reduces the size of data to save storage space and bandwidth using various algorithms.

  • Lossless: Perfect reconstruction
  • Lossy: Some data loss
  • gzip: DEFLATE algorithm
  • Zstandard: High compression ratio
  • Use cases: Storage optimization, network transfer
system-design
// System Design - Data Compression
// Data compression implementation
class DataCompression {
    compress(data: any): Buffer {
        const json = JSON.stringify(data);
        return zlib.gzipSync(json);
    }
    
    decompress(compressed: Buffer): any {
        const decompressed = zlib.gunzipSync(compressed);
        return JSON.parse(decompressed.toString());
    }
    
    async compressStream(stream: Readable): Promise<Buffer> {
        return new Promise((resolve, reject) => {
            const chunks: Buffer[] = [];
            const gzip = zlib.createGzip();
            
            stream.pipe(gzip);
            gzip.on('data', (chunk) => chunks.push(chunk));
            gzip.on('end', () => resolve(Buffer.concat(chunks)));
            gzip.on('error', reject);
        });
    }
    
    async decompressStream(compressed: Buffer): Promise<Readable> {
        const decompressed = zlib.gunzipSync(compressed);
        return Readable.from(decompressed);
    }
}
Coding Round
72. What is Data Masking?

Data masking protects sensitive data by replacing it with fictional but realistic data for non-production environments.

  • Redaction: Remove sensitive data
  • Partial Masking: Show part of data
  • Format Preserving: Same format, different values
  • Encryption: Encrypt sensitive data
  • Use cases: Testing, development, analytics
system-design
// System Design - Data Masking
// Data masking implementation
class DataMasker {
    private rules: Map<string, MaskingRule>;
    
    constructor() {
        this.rules = new Map();
    }
    
    addRule(field: string, rule: MaskingRule): void {
        this.rules.set(field, rule);
    }
    
    mask(data: any): any {
        const masked = { ...data };
        for (const [field, rule] of this.rules) {
            if (masked[field] !== undefined) {
                masked[field] = this.applyRule(masked[field], rule);
            }
        }
        return masked;
    }
    
    private applyRule(value: any, rule: MaskingRule): any {
        switch (rule.type) {
            case 'redact':
                return '***';
            case 'partial':
                return this.partialMask(value, rule);
            case 'replace':
                return rule.replacement || '***';
            case 'encrypt':
                return this.encrypt(value);
            default:
                return value;
        }
    }
    
    private partialMask(value: string, rule: MaskingRule): string {
        const visible = rule.visible || 4;
        if (value.length <= visible * 2) {
            return '***';
        }
        return value.substring(0, visible) + '***' + value.substring(value.length - visible);
    }
    
    private encrypt(value: string): string {
        // Basic encryption for masking
        return Buffer.from(value).toString('base64');
    }
}
Coding Round
73. What is Data Retention?

Data retention policies define how long data should be kept and when it should be deleted based on business and regulatory requirements.

  • Time-based: Retention period
  • Size-based: Storage limits
  • Compliance: Regulatory requirements
  • Automated Cleanup: Scheduled deletion
  • Archiving: Move to cold storage
system-design
// System Design - Data Retention
// Data retention policy
class DataRetention {
    private policies: Map<string, RetentionPolicy>;
    private storage: Storage;
    private cleanupSchedule: number;
    
    constructor(storage: Storage, cleanupSchedule: number = 86400000) { // 24 hours
        this.policies = new Map();
        this.storage = storage;
        this.cleanupSchedule = cleanupSchedule;
        this.startCleanup();
    }
    
    addPolicy(collection: string, policy: RetentionPolicy): void {
        this.policies.set(collection, policy);
    }
    
    async applyRetention(): Promise<void> {
        for (const [collection, policy] of this.policies) {
            await this.cleanupCollection(collection, policy);
        }
    }
    
    private async cleanupCollection(collection: string, policy: RetentionPolicy): Promise<void> {
        const cutoff = Date.now() - policy.duration;
        const query = {
            timestamp: { $lt: cutoff }
        };
        
        if (policy.maxSize) {
            const count = await this.storage.count(collection);
            if (count > policy.maxSize) {
                const deleteCount = count - policy.maxSize;
                await this.storage.deleteOldest(collection, deleteCount);
            }
        }
        
        await this.storage.delete(collection, query);
    }
    
    private startCleanup(): void {
        setInterval(async () => {
            await this.applyRetention();
        }, this.cleanupSchedule);
    }
}
Coding Round
74. What is Data Archiving?

Data archiving moves infrequently accessed data to long-term storage while keeping it accessible if needed.

  • Cold Storage: Low-cost storage
  • Compression: Space optimization
  • Indexing: Searchable archives
  • Retention: Long-term preservation
  • Restoration: Access archived data
system-design
// System Design - Data Archiving
// Data archiving implementation
class DataArchiver {
    private storage: Storage;
    private archiveStorage: Storage;
    private archivePolicy: ArchivePolicy;
    
    constructor(storage: Storage, archiveStorage: Storage, archivePolicy: ArchivePolicy) {
        this.storage = storage;
        this.archiveStorage = archiveStorage;
        this.archivePolicy = archivePolicy;
    }
    
    async archive(): Promise<void> {
        const cutoff = Date.now() - this.archivePolicy.duration;
        const query = {
            timestamp: { $lt: cutoff }
        };
        
        const data = await this.storage.find(query);
        if (data.length > 0) {
            await this.archiveStorage.save(data);
            await this.storage.delete(query);
            console.log(`Archived ${data.length} records`);
        }
    }
    
    async restore(archiveId: string): Promise<void> {
        const data = await this.archiveStorage.findById(archiveId);
        if (data) {
            await this.storage.save(data);
            await this.archiveStorage.delete(archiveId);
        }
    }
}
Coding Round
75. What is Data Backup?

Data backup creates copies of data to protect against loss, corruption, or disaster.

  • Full Backup: Complete data copy
  • Incremental: Changes since last backup
  • Differential: Changes since full backup
  • Off-site: Remote backup storage
  • Restore: Recover from backup
system-design
// System Design - Data Backup
// Data backup implementation
class DataBackup {
    private storage: Storage;
    private backupStorage: Storage;
    private backupInterval: number;
    
    constructor(storage: Storage, backupStorage: Storage, backupInterval: number = 86400000) {
        this.storage = storage;
        this.backupStorage = backupStorage;
        this.backupInterval = backupInterval;
        this.startBackup();
    }
    
    async createBackup(): Promise<string> {
        const backupId = `backup-${Date.now()}`;
        const data = await this.storage.getAll();
        await this.backupStorage.save(backupId, data);
        return backupId;
    }
    
    async restoreBackup(backupId: string): Promise<void> {
        const data = await this.backupStorage.get(backupId);
        if (data) {
            await this.storage.restore(data);
        }
    }
    
    private startBackup(): void {
        setInterval(async () => {
            try {
                await this.createBackup();
                console.log('Backup created successfully');
            } catch (error) {
                console.error('Backup failed:', error);
            }
        }, this.backupInterval);
    }
}
Coding Round
76. What is Data Recovery?

Data recovery restores data from backups or recovery points after data loss or corruption.

  • Recovery Point: Restore point
  • RPO: Recovery Point Objective
  • RTO: Recovery Time Objective
  • Restore: Data restoration
  • Recovery Testing: Regular testing
system-design
// System Design - Data Recovery
// Data recovery implementation
class DataRecovery {
    private recoveryPoints: Map<string, RecoveryPoint>;
    private storage: Storage;
    
    constructor(storage: Storage) {
        this.recoveryPoints = new Map();
        this.storage = storage;
    }
    
    createRecoveryPoint(): string {
        const id = `recovery-${Date.now()}`;
        const data = this.storage.getState();
        this.recoveryPoints.set(id, {
            id,
            timestamp: Date.now(),
            data
        });
        return id;
    }
    
    recover(id: string): boolean {
        const recoveryPoint = this.recoveryPoints.get(id);
        if (!recoveryPoint) {
            return false;
        }
        this.storage.restore(recoveryPoint.data);
        return true;
    }
    
    listRecoveryPoints(): RecoveryPoint[] {
        return Array.from(this.recoveryPoints.values());
    }
}
Coding Round
77. What is Data Auditing?

Data auditing tracks and logs data access and modifications for compliance, security, and troubleshooting.

  • Audit Log: Track changes
  • User Activity: Who accessed what
  • Compliance: Regulatory requirements
  • Filtering: Focus on specific events
  • Reporting: Audit reports
system-design
// System Design - Data Auditing
// Data auditing implementation
class DataAuditor {
    private logs: AuditLog[];
    private storage: Storage;
    private filters: AuditFilter[];
    
    constructor(storage: Storage) {
        this.logs = [];
        this.storage = storage;
        this.filters = [];
    }
    
    logAction(action: AuditAction): void {
        const log: AuditLog = {
            id: `audit-${Date.now()}`,
            action,
            timestamp: Date.now(),
            user: action.user,
            details: action.details
        };
        this.logs.push(log);
        this.storage.save('audit', log);
    }
    
    addFilter(filter: AuditFilter): void {
        this.filters.push(filter);
    }
    
    query(startDate: Date, endDate: Date): AuditLog[] {
        let results = this.logs.filter(log => {
            return log.timestamp >= startDate.getTime() && log.timestamp <= endDate.getTime();
        });
        
        for (const filter of this.filters) {
            results = filter.apply(results);
        }
        
        return results;
    }
}
Coding Round
78. What is Data Governance?

Data governance ensures data quality, security, compliance, and proper management across the organization.

  • Policies: Rules and standards
  • Compliance: Regulatory adherence
  • Data Quality: Accuracy and completeness
  • Data Catalog: Data discovery
  • Lineage: Data origin and flow
system-design
// System Design - Data Governance
// Data governance implementation
class DataGovernance {
    private policies: Map<string, GovernancePolicy>;
    private compliance: ComplianceFramework;
    private dataCatalog: DataCatalog;
    
    constructor(compliance: ComplianceFramework, dataCatalog: DataCatalog) {
        this.policies = new Map();
        this.compliance = compliance;
        this.dataCatalog = dataCatalog;
    }
    
    addPolicy(name: string, policy: GovernancePolicy): void {
        this.policies.set(name, policy);
    }
    
    async enforcePolicies(data: any): Promise<boolean> {
        for (const policy of this.policies.values()) {
            if (!await policy.validate(data)) {
                return false;
            }
        }
        return true;
    }
    
    async classifyData(data: any): Promise<DataClassification> {
        return await this.compliance.classify(data);
    }
    
    async getLineage(dataId: string): Promise<DataLineage> {
        return await this.dataCatalog.getLineage(dataId);
    }
}
Coding Round
79. What is Data Privacy?

Data privacy protects personal and sensitive information, ensuring proper handling and consent management.

  • Consent: User permission
  • Anonymization: Remove PII
  • Pseudonymization: Replace identifiers
  • Compliance: GDPR, CCPA
  • Data Subject Rights: Access, deletion
system-design
// System Design - Data Privacy
// Data privacy implementation
class DataPrivacy {
    private privacyPolicies: PrivacyPolicy[];
    private consentManager: ConsentManager;
    
    constructor(consentManager: ConsentManager) {
        this.privacyPolicies = [];
        this.consentManager = consentManager;
    }
    
    addPolicy(policy: PrivacyPolicy): void {
        this.privacyPolicies.push(policy);
    }
    
    async processData(data: any, userId: string): Promise<any> {
        // Check consent
        const consent = await this.consentManager.getConsent(userId);
        if (!consent) {
            throw new Error('User consent not provided');
        }
        
        // Apply privacy policies
        let processedData = data;
        for (const policy of this.privacyPolicies) {
            processedData = await policy.apply(processedData, consent);
        }
        
        return processedData;
    }
    
    async anonymize(data: any): Promise<any> {
        // Remove PII (Personally Identifiable Information)
        const anonymized = { ...data };
        delete anonymized.name;
        delete anonymized.email;
        delete anonymized.phone;
        return anonymized;
    }
}
Coding Round
80. What is Data Federation?

Data federation provides a unified view of data from multiple sources without physically moving the data.

  • Virtualization: Logical view
  • Query Federation: Query across sources
  • Data Sources: Multiple databases
  • Transformation: Data normalization
  • Performance: Query optimization
system-design
// System Design - Data Federation
// Data federation implementation
class DataFederation {
    private dataSources: Map<string, DataSource>;
    private queryEngine: QueryEngine;
    
    constructor(queryEngine: QueryEngine) {
        this.dataSources = new Map();
        this.queryEngine = queryEngine;
    }
    
    addDataSource(name: string, source: DataSource): void {
        this.dataSources.set(name, source);
    }
    
    async query(query: string): Promise<any[]> {
        const parsedQuery = this.queryEngine.parse(query);
        const results = [];
        
        for (const source of this.dataSources.values()) {
            if (this.isRelevantSource(source, parsedQuery)) {
                const result = await source.query(parsedQuery);
                results.push(result);
            }
        }
        
        return this.queryEngine.merge(results);
    }
    
    private isRelevantSource(source: DataSource, query: ParsedQuery): boolean {
        return source.supports(query);
    }
}
Coding Round
81. What is Data Warehousing Design?

Data warehousing design involves creating structures for efficient analytical querying and reporting.

  • Fact Tables: Measure data
  • Dimension Tables: Descriptive attributes
  • Star Schema: Central fact table
  • Snowflake Schema: Normalized dimensions
  • OLAP Cubes: Multi-dimensional analysis
system-design
// System Design - Data Warehousing
// Data warehouse design
class DataWarehouseDesign {
    private factTables: FactTable[];
    private dimensionTables: DimensionTable[];
    private aggregations: Aggregation[];
    
    constructor() {
        this.factTables = [];
        this.dimensionTables = [];
        this.aggregations = [];
    }
    
    addFactTable(fact: FactTable): void {
        this.factTables.push(fact);
    }
    
    addDimensionTable(dimension: DimensionTable): void {
        this.dimensionTables.push(dimension);
    }
    
    addAggregation(aggregation: Aggregation): void {
        this.aggregations.push(aggregation);
    }
    
    async query(sql: string): Promise<any[]> {
        // Execute OLAP query
        return [];
    }
}
Coding Round
82. What is a Data Lakehouse?

A data lakehouse combines the flexibility of data lakes with the structure and performance of data warehouses.

  • ACID Transactions: Data consistency
  • Schema Enforcement: Data quality
  • Time Travel: Historical data access
  • Open Format: Parquet, ORC
  • Delta Lake: Lakehouse implementation
system-design
// System Design - Data Lakehouse
// Data lakehouse implementation
class DataLakehouse {
    private storage: Storage;
    private catalog: Catalog;
    private compute: ComputeEngine;
    
    constructor(storage: Storage, catalog: Catalog, compute: ComputeEngine) {
        this.storage = storage;
        this.catalog = catalog;
        this.compute = compute;
    }
    
    async write(path: string, data: any): Promise<void> {
        await this.storage.write(path, data);
        await this.catalog.index(path, data);
    }
    
    async read(path: string): Promise<any> {
        return await this.storage.read(path);
    }
    
    async query(sql: string): Promise<any[]> {
        const plan = await this.compute.optimize(sql);
        return await this.compute.execute(plan);
    }
}
Coding Round
83. What is Data Mesh?

Data mesh is a decentralized data architecture that treats data as a product, with domain-oriented ownership.

  • Domain Ownership: Data owned by domains
  • Data Products: Self-contained data services
  • Self-serve: Data infrastructure
  • Federated Governance: Distributed governance
  • Data-as-a-Product: Data product mindset
system-design
// System Design - Data Mesh
// Data mesh implementation
class DataMesh {
    private domains: Domain[];
    private dataProducts: DataProduct[];
    private governance: DataGovernance;
    
    constructor(governance: DataGovernance) {
        this.domains = [];
        this.dataProducts = [];
        this.governance = governance;
    }
    
    addDomain(domain: Domain): void {
        this.domains.push(domain);
    }
    
    addDataProduct(product: DataProduct): void {
        this.dataProducts.push(product);
    }
    
    async query(domainName: string, query: string): Promise<any[]> {
        const domain = this.domains.find(d => d.name === domainName);
        if (!domain) {
            throw new Error(`Domain ${domainName} not found`);
        }
        return await domain.query(query);
    }
    
    async discover(query: string): Promise<DataProduct[]> {
        return this.dataProducts.filter(p => p.matches(query));
    }
}
Coding Round
84. What is Data Integration?

Data integration combines data from different sources into a unified view, enabling comprehensive analysis.

  • ETL: Extract, Transform, Load
  • ELT: Extract, Load, Transform
  • Data Pipeline: Automated data flow
  • Data Quality: Validation and cleaning
  • Batch/Streaming: Processing modes
system-design
// System Design - Data Integration
// Data integration implementation
class DataIntegration {
    private sources: DataSource[];
    private targets: DataTarget[];
    private transformations: Transformation[];
    private schedule: Schedule;
    
    constructor(schedule: Schedule) {
        this.sources = [];
        this.targets = [];
        this.transformations = [];
        this.schedule = schedule;
        this.start();
    }
    
    addSource(source: DataSource): void {
        this.sources.push(source);
    }
    
    addTarget(target: DataTarget): void {
        this.targets.push(target);
    }
    
    addTransformation(transformation: Transformation): void {
        this.transformations.push(transformation);
    }
    
    async run(): Promise<void> {
        for (const source of this.sources) {
            let data = await source.extract();
            for (const transformation of this.transformations) {
                data = await transformation.transform(data);
            }
            for (const target of this.targets) {
                await target.load(data);
            }
        }
    }
    
    private start(): void {
        this.schedule.run(async () => {
            await this.run();
        });
    }
}
Coding Round
85. What is Data Synchronization?

Data synchronization ensures data consistency across multiple systems by propagating changes in real-time or near-real-time.

  • Change Data Capture: Detect changes
  • Conflict Resolution: Handle conflicts
  • Bidirectional: Two-way sync
  • Polling: Periodic sync
  • Event-driven: Sync on events
system-design
// System Design - Data Synchronization
// Data synchronization implementation
class DataSync {
    private sources: DataSource[];
    private target: DataTarget;
    private conflictResolver: ConflictResolver;
    private syncStrategy: SyncStrategy;
    
    constructor(target: DataTarget, conflictResolver: ConflictResolver, syncStrategy: SyncStrategy) {
        this.sources = [];
        this.target = target;
        this.conflictResolver = conflictResolver;
        this.syncStrategy = syncStrategy;
    }
    
    addSource(source: DataSource): void {
        this.sources.push(source);
    }
    
    async sync(): Promise<void> {
        const changes = [];
        for (const source of this.sources) {
            const sourceChanges = await source.getChanges();
            changes.push(...sourceChanges);
        }
        
        const resolved = await this.conflictResolver.resolve(changes);
        const merged = await this.syncStrategy.merge(resolved);
        await this.target.apply(merged);
    }
}
Coding Round
86. What is Data Quality?

Data quality ensures data is accurate, complete, consistent, and fit for its intended purpose.

  • Accuracy: Correct data
  • Completeness: All required data
  • Consistency: Uniform data
  • Timeliness: Up-to-date data
  • Validity: Data meets rules
system-design
// System Design - Data Quality
// Data quality framework
class DataQuality {
    private rules: QualityRule[];
    private metrics: QualityMetric[];
    private reporter: QualityReporter;
    
    constructor(reporter: QualityReporter) {
        this.rules = [];
        this.metrics = [];
        this.reporter = reporter;
    }
    
    addRule(rule: QualityRule): void {
        this.rules.push(rule);
    }
    
    addMetric(metric: QualityMetric): void {
        this.metrics.push(metric);
    }
    
    async assess(data: any): Promise<QualityReport> {
        const results = [];
        
        // Apply rules
        for (const rule of this.rules) {
            const result = await rule.check(data);
            results.push(result);
        }
        
        // Calculate metrics
        const metrics = {};
        for (const metric of this.metrics) {
            metrics[metric.name] = await metric.calculate(data);
        }
        
        return {
            results,
            metrics,
            timestamp: Date.now()
        };
    }
}
Coding Round
87. What is Data Observability?

Data observability monitors and alerts on data quality, health, and anomalies in data pipelines and systems.

  • Data Monitoring: Track data quality
  • Alerting: Notify on issues
  • Data Lineage: Track data flow
  • Dashboard: Visualize metrics
  • Anomaly Detection: Identify outliers
system-design
// System Design - Data Observability
// Data observability implementation
class DataObservability {
    private monitors: DataMonitor[];
    private alerts: Alert[];
    private dashboard: Dashboard;
    
    constructor(dashboard: Dashboard) {
        this.monitors = [];
        this.alerts = [];
        this.dashboard = dashboard;
    }
    
    addMonitor(monitor: DataMonitor): void {
        this.monitors.push(monitor);
    }
    
    addAlert(alert: Alert): void {
        this.alerts.push(alert);
    }
    
    async check(): Promise<void> {
        for (const monitor of this.monitors) {
            const status = await monitor.check();
            if (status === 'critical') {
                for (const alert of this.alerts) {
                    await alert.trigger(monitor);
                }
            }
            this.dashboard.update(monitor, status);
        }
    }
}
Coding Round
88. What is Data Lineage?

Data lineage tracks the flow of data from its origin to its destination, showing transformations and dependencies.

  • Data Flow: Movement of data
  • Transformations: Data changes
  • Dependencies: Data relationships
  • Impact Analysis: Change effects
  • Audit: Data provenance
system-design
// System Design - Data Lineage
// Data lineage implementation
class DataLineage {
    private nodes: LineageNode[];
    private edges: LineageEdge[];
    private graph: Graph;
    
    constructor() {
        this.nodes = [];
        this.edges = [];
        this.graph = new Graph();
    }
    
    addNode(node: LineageNode): void {
        this.nodes.push(node);
        this.graph.addNode(node);
    }
    
    addEdge(edge: LineageEdge): void {
        this.edges.push(edge);
        this.graph.addEdge(edge);
    }
    
    getLineage(dataId: string): LineageGraph {
        const path = this.graph.findPath(dataId);
        return {
            nodes: path.nodes,
            edges: path.edges
        };
    }
}
Coding Round
89. What is a Data Catalog?

A data catalog organizes and manages metadata, enabling data discovery and understanding across the organization.

  • Metadata: Data about data
  • Search: Data discovery
  • Tagging: Data classification
  • Data Dictionary: Field descriptions
  • Collaboration: Data sharing
system-design
// System Design - Data Catalog
// Data catalog implementation
class DataCatalog {
    private assets: DataAsset[];
    private tags: Map<string, string[]>;
    private searchEngine: SearchEngine;
    
    constructor(searchEngine: SearchEngine) {
        this.assets = [];
        this.tags = new Map();
        this.searchEngine = searchEngine;
    }
    
    addAsset(asset: DataAsset): void {
        this.assets.push(asset);
        this.searchEngine.index(asset);
    }
    
    addTag(assetId: string, tag: string): void {
        if (!this.tags.has(assetId)) {
            this.tags.set(assetId, []);
        }
        this.tags.get(assetId).push(tag);
    }
    
    search(query: string): DataAsset[] {
        return this.searchEngine.search(query);
    }
    
    getAsset(id: string): DataAsset | undefined {
        return this.assets.find(a => a.id === id);
    }
}
Coding Round
90. What is a Data Marketplace?

A data marketplace enables data providers to publish and monetize data, and consumers to discover and purchase data.

  • Data Providers: Data publishers
  • Data Consumers: Data buyers
  • Pricing: Data pricing models
  • Access Control: Data access management
  • Billing: Usage-based billing
system-design
// System Design - Data Marketplace
// Data marketplace implementation
class DataMarketplace {
    private providers: DataProvider[];
    private consumers: DataConsumer[];
    private products: DataProduct[];
    private pricing: PricingEngine;
    private billing: BillingSystem;
    
    constructor(pricing: PricingEngine, billing: BillingSystem) {
        this.providers = [];
        this.consumers = [];
        this.products = [];
        this.pricing = pricing;
        this.billing = billing;
    }
    
    registerProvider(provider: DataProvider): void {
        this.providers.push(provider);
    }
    
    registerConsumer(consumer: DataConsumer): void {
        this.consumers.push(consumer);
    }
    
    publishProduct(product: DataProduct): void {
        this.products.push(product);
    }
    
    async purchase(consumerId: string, productId: string): Promise<void> {
        const product = this.products.find(p => p.id === productId);
        if (!product) {
            throw new Error('Product not found');
        }
        
        const price = await this.pricing.calculate(product);
        await this.billing.charge(consumerId, price);
        await this.provideAccess(consumerId, product);
    }
    
    private async provideAccess(consumerId: string, product: DataProduct): Promise<void> {
        // Provide access to the data
    }
}
Coding Round
91. What is a Data API?

A data API provides programmatic access to data, enabling integration with applications and services.

  • REST API: HTTP-based API
  • GraphQL: Query language
  • Rate Limiting: Usage control
  • Authentication: Access control
  • Documentation: API documentation
system-design
// System Design - Data API
// Data API implementation
class DataAPI {
    private endpoints: APIEndpoint[];
    private authentication: AuthService;
    private rateLimit: RateLimiter;
    private cache: Cache;
    
    constructor(authentication: AuthService, rateLimit: RateLimiter, cache: Cache) {
        this.endpoints = [];
        this.authentication = authentication;
        this.rateLimit = rateLimit;
        this.cache = cache;
    }
    
    addEndpoint(endpoint: APIEndpoint): void {
        this.endpoints.push(endpoint);
    }
    
    async handle(request: Request): Promise<Response> {
        // Authenticate
        const user = await this.authentication.authenticate(request);
        if (!user) {
            return new Response('Unauthorized', { status: 401 });
        }
        
        // Rate limit
        if (!await this.rateLimit.allow(user.id)) {
            return new Response('Too Many Requests', { status: 429 });
        }
        
        // Route to endpoint
        const endpoint = this.findEndpoint(request);
        if (!endpoint) {
            return new Response('Not Found', { status: 404 });
        }
        
        // Cache
        const cacheKey = this.getCacheKey(request);
        const cached = await this.cache.get(cacheKey);
        if (cached) {
            return cached;
        }
        
        // Execute
        const response = await endpoint.execute(request);
        await this.cache.set(cacheKey, response);
        
        return response;
    }
    
    private findEndpoint(request: Request): APIEndpoint | undefined {
        return this.endpoints.find(e => e.path === request.url.pathname);
    }
    
    private getCacheKey(request: Request): string {
        return `${request.method}:${request.url}`;
    }
}
Coding Round
92. What is Data Export?

Data export extracts data from a system into various formats for analysis, reporting, or integration.

  • Formats: CSV, JSON, Excel
  • Batch: Scheduled export
  • Streaming: Real-time export
  • Filtering: Selective export
  • Compression: Space optimization
system-design
// System Design - Data Export
// Data export implementation
class DataExporter {
    private formats: Map<string, ExportFormat>;
    private storage: Storage;
    
    constructor(storage: Storage) {
        this.formats = new Map();
        this.storage = storage;
    }
    
    addFormat(name: string, format: ExportFormat): void {
        this.formats.set(name, format);
    }
    
    async exportData(data: any, format: string, options?: ExportOptions): Promise<string> {
        const exporter = this.formats.get(format);
        if (!exporter) {
            throw new Error(`Format ${format} not supported`);
        }
        
        const exported = await exporter.export(data, options);
        const path = `exports/${Date.now()}.${format}`;
        await this.storage.write(path, exported);
        return path;
    }
}
Coding Round
93. What is Data Import?

Data import loads data from external sources into a system, with validation and transformation.

  • Formats: CSV, JSON, Excel
  • Validation: Data validation
  • Transformation: Data mapping
  • Batch: Bulk import
  • Error Handling: Failed records
system-design
// System Design - Data Import
// Data import implementation
class DataImporter {
    private parsers: Map<string, DataParser>;
    private validators: DataValidator[];
    private transformers: DataTransformer[];
    
    constructor() {
        this.parsers = new Map();
        this.validators = [];
        this.transformers = [];
    }
    
    addParser(format: string, parser: DataParser): void {
        this.parsers.set(format, parser);
    }
    
    addValidator(validator: DataValidator): void {
        this.validators.push(validator);
    }
    
    addTransformer(transformer: DataTransformer): void {
        this.transformers.push(transformer);
    }
    
    async importData(file: Buffer, format: string): Promise<any> {
        const parser = this.parsers.get(format);
        if (!parser) {
            throw new Error(`Format ${format} not supported`);
        }
        
        let data = await parser.parse(file);
        
        for (const validator of this.validators) {
            if (!await validator.validate(data)) {
                throw new Error('Data validation failed');
            }
        }
        
        for (const transformer of this.transformers) {
            data = await transformer.transform(data);
        }
        
        return data;
    }
}
Coding Round
94. What is Data Transformation?

Data transformation converts data from one format or structure to another, enabling integration and analysis.

  • Mapping: Field mapping
  • Cleaning: Data cleansing
  • Enrichment: Add data
  • Aggregation: Summarize data
  • Normalization: Standardize format
system-design
// System Design - Data Transformation
// Data transformation pipeline
class DataTransformationPipeline {
    private stages: TransformationStage[];
    
    constructor() {
        this.stages = [];
    }
    
    addStage(stage: TransformationStage): void {
        this.stages.push(stage);
    }
    
    async transform(data: any): Promise<any> {
        let current = data;
        for (const stage of this.stages) {
            current = await stage.process(current);
        }
        return current;
    }
}
Coding Round
95. What is Data Enrichment?

Data enrichment enhances data by adding additional information from internal or external sources.

  • External Data: Third-party data
  • Geocoding: Location data
  • Demographic: Demographic data
  • Real-time: Live enrichment
  • Batch: Periodic enrichment
system-design
// System Design - Data Enrichment
// Data enrichment implementation
class DataEnricher {
    private sources: EnrichmentSource[];
    private cache: Cache;
    private batchSize: number;
    
    constructor(cache: Cache, batchSize: number = 100) {
        this.sources = [];
        this.cache = cache;
        this.batchSize = batchSize;
    }
    
    addSource(source: EnrichmentSource): void {
        this.sources.push(source);
    }
    
    async enrich(data: any[]): Promise<any[]> {
        const enriched = [];
        const batches = this.chunk(data, this.batchSize);
        
        for (const batch of batches) {
            const results = await Promise.all(
                batch.map(item => this.enrichItem(item))
            );
            enriched.push(...results);
        }
        
        return enriched;
    }
    
    private async enrichItem(item: any): Promise<any> {
        let enriched = { ...item };
        
        for (const source of this.sources) {
            const key = this.getKey(item, source);
            const cached = await this.cache.get(key);
            
            if (cached) {
                enriched = { ...enriched, ...cached };
            } else {
                const result = await source.get(item);
                if (result) {
                    await this.cache.set(key, result);
                    enriched = { ...enriched, ...result };
                }
            }
        }
        
        return enriched;
    }
    
    private getKey(item: any, source: EnrichmentSource): string {
        return `${source.name}:${item.id}`;
    }
    
    private chunk<T>(arr: T[], size: number): T[][] {
        const chunks = [];
        for (let i = 0; i < arr.length; i += size) {
            chunks.push(arr.slice(i, i + size));
        }
        return chunks;
    }
}
Coding Round
96. What is Data Purging?

Data purging permanently deletes data that is no longer needed, freeing up storage and improving performance.

  • Retention Policy: Keep criteria
  • Compliance: Regulatory compliance
  • Performance: Improve performance
  • Archive: Move to archive first
  • Secure Delete: Irreversible deletion
system-design
// System Design - Data Purging
// Data purging implementation
class DataPurger {
    private policies: Map<string, PurgePolicy>;
    private storage: Storage;
    
    constructor(storage: Storage) {
        this.policies = new Map();
        this.storage = storage;
    }
    
    addPolicy(collection: string, policy: PurgePolicy): void {
        this.policies.set(collection, policy);
    }
    
    async purge(): Promise<void> {
        for (const [collection, policy] of this.policies) {
            await this.purgeCollection(collection, policy);
        }
    }
    
    private async purgeCollection(collection: string, policy: PurgePolicy): Promise<void> {
        const cutoff = Date.now() - policy.duration;
        const query = {
            timestamp: { $lt: cutoff }
        };
        
        await this.storage.delete(collection, query);
        console.log(`Purged records from ${collection}`);
    }
}
Coding Round
97. What is Data Normalization?

Data normalization organizes data to reduce redundancy and improve integrity, following normal forms.

  • 1NF: Atomic values
  • 2NF: Remove partial dependencies
  • 3NF: Remove transitive dependencies
  • BCNF: Boyce-Codd Normal Form
  • Denormalization: Performance optimization
system-design
// System Design - Data Normalization
// Data normalization implementation
class DataNormalizer {
    private rules: NormalizationRule[];
    
    constructor() {
        this.rules = [];
    }
    
    addRule(rule: NormalizationRule): void {
        this.rules.push(rule);
    }
    
    normalize(data: any): any {
        let normalized = { ...data };
        
        for (const rule of this.rules) {
            normalized = this.applyRule(normalized, rule);
        }
        
        return normalized;
    }
    
    private applyRule(data: any, rule: NormalizationRule): any {
        const result = { ...data };
        
        switch (rule.type) {
            case 'format':
                if (data[rule.field]) {
                    result[rule.field] = this.formatValue(data[rule.field], rule.format);
                }
                break;
            case 'convert':
                if (data[rule.field]) {
                    result[rule.field] = this.convertValue(data[rule.field], rule.targetType);
                }
                break;
            case 'transform':
                if (data[rule.field]) {
                    result[rule.field] = rule.transformation(data[rule.field]);
                }
                break;
            case 'validate':
                if (!rule.validation(data[rule.field])) {
                    result[rule.field] = rule.defaultValue || null;
                }
                break;
        }
        
        return result;
    }
    
    private formatValue(value: any, format: string): any {
        // Apply formatting
        return value;
    }
    
    private convertValue(value: any, targetType: string): any {
        // Convert to target type
        return value;
    }
}
Coding Round
98. What is Data Deduplication?

Data deduplication removes duplicate copies of data to save storage space and improve efficiency.

  • Hash-based: Identify duplicates by hash
  • Block-level: Deduplicate at block level
  • File-level: Deduplicate entire files
  • In-line: Real-time deduplication
  • Post-process: Batch deduplication
system-design
// System Design - Data Deduplication
// Data deduplication implementation
class DataDeduplicator {
    private storage: Storage;
    private hashAlgorithm: string;
    private cache: Cache;
    
    constructor(storage: Storage, cache: Cache, hashAlgorithm: string = 'sha256') {
        this.storage = storage;
        this.cache = cache;
        this.hashAlgorithm = hashAlgorithm;
    }
    
    async deduplicate(data: any): Promise<any> {
        const hash = this.hash(data);
        const existing = await this.cache.get(hash);
        
        if (existing) {
            return existing;
        }
        
        await this.storage.save(data);
        await this.cache.set(hash, data);
        return data;
    }
    
    private hash(data: any): string {
        const json = JSON.stringify(data);
        return crypto.createHash(this.hashAlgorithm).update(json).digest('hex');
    }
}
Coding Round
99. What is Data Versioning?

Data versioning tracks and manages different versions of data, enabling rollback and historical analysis.

  • Version Control: Track changes
  • Snapshot: Point-in-time capture
  • Rollback: Revert to previous version
  • Audit Trail: Change history
  • Conflict Resolution: Handle concurrent updates
system-design
// System Design - Data Versioning
// Data versioning implementation
class DataVersioning {
    private versions: Map<string, Version[]>;
    private storage: Storage;
    private maxVersions: number;
    
    constructor(storage: Storage, maxVersions: number = 10) {
        this.versions = new Map();
        this.storage = storage;
        this.maxVersions = maxVersions;
    }
    
    async save(id: string, data: any): Promise<void> {
        const version: Version = {
            id: `v${Date.now()}`,
            data,
            timestamp: Date.now()
        };
        
        if (!this.versions.has(id)) {
            this.versions.set(id, []);
        }
        
        const versions = this.versions.get(id);
        versions.push(version);
        
        if (versions.length > this.maxVersions) {
            const oldest = versions.shift();
            await this.storage.archive(id, oldest);
        }
        
        await this.storage.save(id, data);
    }
    
    async get(id: string, versionId?: string): Promise<any> {
        if (versionId) {
            const versions = this.versions.get(id);
            if (!versions) return null;
            const version = versions.find(v => v.id === versionId);
            return version ? version.data : null;
        }
        
        return await this.storage.get(id);
    }
    
    async getVersions(id: string): Promise<Version[]> {
        return this.versions.get(id) || [];
    }
}
Coding Round
100. What is Data Migration Strategy?

Data migration strategy defines how data is moved from source to target systems with minimal disruption and risk.

  • Big Bang: One-time migration
  • Trickle: Incremental migration
  • Parallel Run: Run both systems
  • Cutover: Switch to new system
  • Validation: Data integrity checks
system-design
// System Design - Data Migration Strategy
// Data migration strategy implementation
class DataMigrationStrategy {
    private stages: MigrationStage[];
    private validators: MigrationValidator[];
    private rollbackStrategy: RollbackStrategy;
    
    constructor(rollbackStrategy: RollbackStrategy) {
        this.stages = [];
        this.validators = [];
        this.rollbackStrategy = rollbackStrategy;
    }
    
    addStage(stage: MigrationStage): void {
        this.stages.push(stage);
    }
    
    addValidator(validator: MigrationValidator): void {
        this.validators.push(validator);
    }
    
    async migrate(): Promise<void> {
        let currentStage = 0;
        
        try {
            for (let i = 0; i < this.stages.length; i++) {
                currentStage = i;
                await this.stages[i].execute();
                
                // Validate after each stage
                for (const validator of this.validators) {
                    if (!await validator.validate()) {
                        throw new Error(`Validation failed at stage ${i}`);
                    }
                }
            }
        } catch (error) {
            console.error(`Migration failed at stage ${currentStage}: ${error}`);
            await this.rollbackStrategy.rollback(currentStage);
            throw error;
        }
    }
}