System Design

The Map That Made Me Rethink My System Design Approach

I stumbled upon a visual "System Design Topic Map" from ByteByteGo that stopped me mid-scroll. As someone who's built products, led teams, and spent too m...

10 Aug 2025

The Map That Made Me Rethink My System Design Approach

I stumbled upon a visual "System Design Topic Map" from ByteByteGo that stopped me mid-scroll. As someone who's built products, led teams, and spent too many late nights debugging scaling issues, this map felt like a cheat sheet for everything I wish I'd had years ago.

Why It Resonated

When you work on real-world systems, you realize "system design" isn't one skill. It's an entire ecosystem: application design, communication protocols, scalability patterns, security, data layers, and infrastructure.

Looking at the map, I immediately recalled moments from my career:

  • The time I learned why rate limiting isn't optional — after a DDoS attempt on one of our APIs.
  • When our "quick prototype" grew into a monolith so big that migrating to microservices felt like open-heart surgery.
  • The painful week I spent implementing leader election in a distributed system, wishing I'd studied it sooner.

How the Map Breaks Down

  • Core Concepts and Application Layer — patterns like Domain-Driven Design and Clean Architecture give you a mental framework. Without them, you're adding features without structure.
  • Network and Communication — if your system talks to anything else (and it does), you need to know your protocols. HTTP, gRPC, message queues (AMQP), real-time communication. Mastering real-time is where you unlock great user experiences.
  • Scalability and Reliability — sharding, caching, auto-scaling. You don't just learn these. You earn them through production incidents.
  • Security and Observability — I've seen brilliant products fail because security was an afterthought. And without monitoring and logging, you're flying blind.
  • Infrastructure and Deployment — Kubernetes or a single EC2 instance, the principles of Infrastructure as Code and CI/CD keep you sane.
  • Data Layer — choosing between SQL, NoSQL, and NewSQL isn't just a tech decision. It shapes your product's capabilities and limitations.

Deep Dive: Real-Time Communication — 3 Strategies I've Used

Real-time communication looks simple on the surface. In reality, the right approach depends on your requirements, scale, and infrastructure.

1. Long Polling

The client sends a request. The server holds the connection open until new data is available or a timeout occurs. Once the server responds, the client immediately sends another request.

I've used long polling when WebSockets weren't an option for our infrastructure, or for quick "real-time-ish" updates where SSE and WebSockets felt like overkill.

Tips from experience:

  • Keep timeouts reasonable (20-30 seconds).
  • Batch multiple updates in one response when possible.
  • Always implement retries for dropped connections.
Text
async function longPoll() {
  try {
    const res = await fetch('/updates');
    const data = await res.json();
    console.log('New data:', data);
  } catch (err) {
    console.error('Polling error:', err);
  } finally {
    longPoll();
  }
}
longPoll();

2. Server-Sent Events (SSE)

A one-way channel from server to client over HTTP. The server streams updates continuously over a single, long-lived connection.

I use SSE for live dashboards where only the server pushes updates. Notifications, feed updates, status changes — anything where the client doesn't need to send frequent messages back.

Benefit: Lightweight, simpler than WebSockets, built-in reconnection in most browsers.

Cost: One-way only. No sending data from client to server over the same channel.

Text
const events = new EventSource('/stream');
events.onmessage = (event) => {
  console.log('New message:', event.data);
};
events.onerror = (err) => {
  console.error('SSE error:', err);
};

Server-side (Node.js with Express):

Text
const express = require('express');
const app = express();
app.get('/stream', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  const sendMessage = (msg) => {
    res.write(`data: ${JSON.stringify(msg)}\n\n`);
  };

  sendMessage({ message: 'Connected to SSE' });

  const interval = setInterval(() => {
    sendMessage({ time: new Date().toISOString() });
  }, 2000);

  req.on('close', () => {
    clearInterval(interval);
  });
});

app.listen(3000, () => console.log('SSE server running on port 3000'));

3. WebSockets

Full-duplex (two-way) persistent connection between client and server. No repeated HTTP overhead. Messages go both ways in real-time.

I use WebSockets for chat apps, multiplayer games, collaborative editing — anywhere latency matters and messages flow in both directions.

Best practices:

  • Use ping/pong heartbeats to detect dropped connections.
  • Authenticate at connection handshake.
  • Monitor message rates to prevent abuse.
Text
const socket = new WebSocket('ws://localhost:3000');
socket.onopen = () => {
  console.log('Connected to WebSocket');
  socket.send(JSON.stringify({ type: 'hello', message: 'Hi server!' }));
};

socket.onmessage = (event) => {
  console.log('Received:', event.data);
};

Server-side (Node.js with ws):

Text
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3000 });
wss.on('connection', (ws) => {
  console.log('New client connected');
  ws.send(JSON.stringify({ message: 'Welcome to WebSocket server' }));
  ws.on('message', (message) => {
    console.log('Received from client:', message);
    ws.send(JSON.stringify({ echo: message }));
  });

  ws.on('close', () => {
    console.log('Client disconnected');
  });
});

console.log('WebSocket server running on ws://localhost:3000');

How I Choose Between Them

  • Long Polling — works everywhere, simple to implement, but least efficient. Good enough for low-frequency updates.
  • SSE — great for server-to-client streams with minimal complexity. My default for dashboards and notifications.
  • WebSockets — the right choice for full interactive, two-way communication at scale. More infrastructure overhead.

How I Use This Map

I've bookmarked it as a self-audit tool. Before starting any project, I run through each category:

  • Have we picked the right architecture pattern?
  • Is our communication protocol the best fit?
  • Do we have a scaling strategy from day one?
  • Is security baked in, not bolted on?

If you're building anything beyond a hobby app, keep a similar map on hand. It's like having a senior architect reviewing your decisions — without the meetings.