SwadhyAI Notes

All Low-Level Design notes

Low-level design

Same product. Two different design altitudes.

High-level design asks how many machines share the work: services, stores, traffic, and failure domains. Low-level design asks how objects inside one program share the work: types, methods, invariants, and threads. Same product name on the board — two different jobs.

Mix those altitudes and you will name Redis while they wanted a class with get and put. Confirm whether you are designing process boundaries or object responsibilities before you draw.

Distributed altitude

High-level design

is about , data stores, traffic, and failure. “Design a URL shortener” here means collisions at a billion links, a cache in front of the store, and a region going down. You draw boxes that can die independently.

The parking lot at this altitude is gates in two cities, a shared inventory service, and what happens when the payment provider is slow. That is a useful conversation. It is not this track.

In-process altitude

Low-level design

is about types, methods, rules that must stay true, and two threads inside one program. “Design a URL shortener” here means encode, decode, and a that a HashMap can fill this afternoon. You are unless they say otherwise.

The parking lot at this altitude is park, exit, occupancy, and a fee policy. Two gates are two threads, not two data centers.

A simple test you can use in the first minute

If the next sentence needs a network hop, you are in HLD. If it needs a class that should not know about SQL, you are in LLD. Say the test out loud. Get a nod. Then stay on that altitude for the rest of the round.

Several problems in this track share a name with system-design notes — URL shortener, rate limiter, parking lot. The LLD page is the in-process version: objects in one program. The HLD page is the distributed version. Keep those two talks apart even when the title on the board is identical.

SignalYou are in HLDYou are in LLD
Unit of workService, queue, region, replicaClass, interface, method, thread
StorePostgres, Redis, S3, shard keyUrlStore.put / get; a HashMap is legal
FailureAZ down, timeout, retry, fallbackLot full, unknown ticket, two threads, one spot
Scale talkQPS, p95, partition, cache hitO(n) scan of twenty spots is usually fine
ChangeAdd a region, change consistencyAdd EV pricing without editing the lot
DrawingBoxes and arrows across machinesTypes and who calls whom inside one process

Same product, two altitudes

URL shortener: do not mix the altitudes

In high-level design you worry about unique codes at a billion links and a cache in front of the database. In this round you write encode, decode, and a store. The HLD URL shortener note is the distributed version. This sketch is the in-process object model.

Browser
API service
Cache / DB
java
interface UrlStore {
  void put(String code, String longUrl);
  String get(String code);
}

class InMemoryUrlStore implements UrlStore {
  private final Map<String, String> byCode = new HashMap<>();

  public void put(String code, String longUrl) {
    byCode.put(code, longUrl);
  }

  public String get(String code) {
    return byCode.get(code);
  }
}

class UrlShortener {
  private final UrlStore store;
  private final CodeGenerator codes;

  UrlShortener(UrlStore store, CodeGenerator codes) {
    this.store = store;
    this.codes = codes;
  }

  String encode(String longUrl) {
    String code = codes.next();
    store.put(code, longUrl);
    return code;
  }

  String decode(String code) {
    String longUrl = store.get(code);
    if (longUrl == null) {
      throw new UnknownCodeException(code);
    }
    return longUrl;
  }
}

If you drop Redis into this round, you jumped altitudes. Unless they asked for HLD, a cache is a class with get and put. It is not a box on a region map. You can still say, “Later this store could wrap Redis.” That sentence shows you know the boundary. Implementing the product infrastructure is not the assignment.

A short conversation that saves the round

Strong candidates confirm the altitude before they draw. This is not delay. It is how you avoid building a distributed system when they wanted an object model.

You

Before I draw, I want to confirm scope. Are we designing objects in one program, or services across machines?

Interviewer

One program. Machine coding. HashMap is fine.

You

Good. Then encode and decode against a UrlStore. I will not place a load balancer. If two threads encode at once I will say how codes stay unique.

Interviewer

What if we need to scale later?

You

Then the store interface is the seam. Today InMemoryUrlStore. A later adapter could talk to a database. That is a different round.

The nod in minute two is worth more than a pretty region map. Once they say “one program,” stay there. Two threads are still in scope. Kafka is not.

Rate limiter: class versus cluster

The same title shows up in both tracks. HLD talks about a global counter, sliding windows across gateways, and what happens when Redis is partitioned. LLD talks about allow(key) in one process, and whether two threads can both think they have budget.

If they asked for LLD, write the policy object. Do not start with “we put a token bucket in Redis.” That sentence belongs on the HLD rate limiting page.

java
interface RateLimiter {
  boolean allow(String key);
}

class TokenBucketLimiter implements RateLimiter {
  private final Map<String, Bucket> buckets = new HashMap<>();
  private final Clock clock;
  private final long capacity;
  private final long refillPerSecond;

  public synchronized boolean allow(String key) {
    Bucket bucket = buckets.computeIfAbsent(key, k -> new Bucket(capacity, clock.millis()));
    bucket.refill(clock.millis(), refillPerSecond, capacity);
    if (bucket.tokens < 1) {
      return false;
    }
    bucket.tokens -= 1;
    return true;
  }
}

When a product name is a trap

They said Redis and you are in an LLD round

Translate it. “I will keep a Cache interface with get and put. An in-memory map today. If we later need a shared cache across processes, that becomes HLD.” You showed the seam without leaving in-process design.

They asked for classes and you drew Kafka

Load balancers and Kafka answers belong in system design. Here they want types, methods, and who talks to whom inside one program. An in-process observer or a blocking queue can stand in for “notify later.”

They want a little of both

Then time-box. Spend most of the round on the object model. In the last five minutes, say how the store interface would become a remote client. Do not let the distributed sketch eat the LLD work.

Parking lot in two cities

Confirm: one program with two gates as threads, or two sites with a shared inventory service? The parking lot case in this track is the in-process version.

What still counts as LLD even when it feels “systems-y”

Two threads sharing a spot is LLD. A lock, a synchronized method, or an atomic occupy is LLD. A repository interface that hides SQL is LLD. Idempotent park if the same vehicle is already inside is LLD. None of those need a region map.

What does not count: naming Kubernetes, picking Kafka partitions, or estimating QPS for a million gates. Those are good skills. They are the other job. Bring them only if the interviewer walks you into distributed scope on purpose.

java
// LLD: hide the database, do not design the cluster
interface TicketBook {
  Ticket issue(Vehicle vehicle, ParkingSpot spot, Instant at);
  Ticket require(TicketId id);
  void close(Ticket ticket);
}

class SqlTicketBook implements TicketBook {
  private final DataSource db;

  public Ticket require(TicketId id) {
    // SELECT ... WHERE id = ?
    // The SQL stays here. ParkingLot never sees ResultSet.
  }
}

// Not LLD: "we will put tickets in a sharded Cassandra ring
// with a cache in each AZ and a queue for receipt emails."

Keep going from here

Takeaway

Same product, two altitudes. If the next sentence needs a network hop, you are designing distributed systems. If it needs a class that should not know about SQL, you are designing objects in one program. Confirm the altitude, keep the store as an interface, and leave Redis as a later adapter. Next we run a forty-five-minute talking order so the last thirty minutes are code instead of panic.