DEV Community

Anurag Mahato
Anurag Mahato

Posted on

01_intro-to-LLD

Low-Level Design: Understanding the Basics

When building a software application, we don't just need to decide what the system should do. We also need to decide how the individual parts of the system will be designed and work together.

This is where Low-Level Design (LLD) comes in.

What is Low-Level Design?

Low-Level Design (LLD) is the process of designing the internal structure of an application.

It focuses on things like:

  • Classes and objects
  • Relationships between objects
  • Responsibilities of each class
  • Data flow
  • Interfaces
  • Implementation decisions
  • Code structure

For example, imagine we are building a food delivery application.

At the LLD level, we might identify classes such as:

User
Restaurant
Food
Order
Payment
DeliveryPartner
Enter fullscreen mode Exit fullscreen mode

We then decide what each class should do and how they interact.

For example:

User → places → Order
Order → contains → Food
Order → uses → Payment
Order → assigned to → DeliveryPartner
Enter fullscreen mode Exit fullscreen mode

The goal is to create a design where each component has a clear responsibility and the system can be easily changed later.


What Should We Think About Before LLD?

Before jumping directly into classes and code, there are a few things we should identify.

1. Objects / Entities

First, identify the important entities in the problem.

For a Parking Lot system:

ParkingLot
Floor
ParkingSpot
Vehicle
Ticket
Payment
Enter fullscreen mode Exit fullscreen mode

These entities will eventually become classes or components in our design.


2. Relationships

Next, understand how these objects interact.

For example:

ParkingLot
   |
   └── Floors
          |
          └── ParkingSpots
Enter fullscreen mode Exit fullscreen mode

A ParkingLot contains multiple Floor objects, and each floor contains multiple ParkingSpot objects.

Understanding these relationships helps us decide whether we need composition, inheritance, association, or interfaces.


3. Data Security

We should also think about what data needs to be protected.

For example, in a banking application:

User
 ├── name
 ├── accountNumber
 └── balance
Enter fullscreen mode Exit fullscreen mode

We shouldn't allow every class to directly modify balance.

Instead, we can encapsulate it:

class Account {
    private double balance;

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

This is one of the reasons encapsulation is important in LLD.


Core Goals of LLD

There are three important qualities we should aim for.

1. Scalability

Scalability means our design should be able to handle increasing requirements or usage without requiring a complete rewrite.

For example, suppose our payment system initially supports:

UPI
Enter fullscreen mode Exit fullscreen mode

Later we want:

UPI
Credit Card
Debit Card
PayPal
Enter fullscreen mode Exit fullscreen mode

A good design should allow us to add new payment methods without modifying a huge amount of existing code.


2. Maintainability

Maintainability means the code should be easy to understand, debug and modify.

Imagine having one class like:

OrderManager
Enter fullscreen mode Exit fullscreen mode

that handles:

Order creation
Payment
Notifications
Delivery
Database operations
Enter fullscreen mode Exit fullscreen mode

Changing one feature could break another.

Instead, we can separate responsibilities:

OrderService
PaymentService
NotificationService
DeliveryService
Enter fullscreen mode Exit fullscreen mode

Now each component has a clearer responsibility.


3. Extensibility

Extensibility means we should be able to add new functionality with minimal changes to existing code.

For example, consider:

interface Payment {
    void pay(double amount);
}
Enter fullscreen mode Exit fullscreen mode

We can have:

UPIPayment
CardPayment
PayPalPayment
Enter fullscreen mode Exit fullscreen mode

If we later introduce CryptoPayment, we can create another implementation without changing the existing payment classes.

This is where principles like SOLID and design patterns become very useful.


LLD vs HLD

A simple way to remember the difference is:

HLD decides what the system looks like. LLD decides how its components work internally.

High-Level Design

HLD deals with the overall architecture.

For example:

Client
   ↓
Load Balancer
   ↓
Application Servers
   ↓
Database
   ↓
Cache
Enter fullscreen mode Exit fullscreen mode

Questions include:

  • Should we use SQL or NoSQL?
  • How many servers do we need?
  • Do we need caching?
  • How do we scale the system?
  • What technology should we use?

Low-Level Design

LLD goes inside the application server.

For example:

OrderService
     |
     ├── Order
     ├── Payment
     ├── User
     └── Notification
Enter fullscreen mode Exit fullscreen mode

Questions include:

  • What classes do we need?
  • What should each class be responsible for?
  • Which classes should interact?
  • Should we use inheritance or composition?
  • Which design pattern fits the problem?
  • How can we make the code extensible?

A Simple Example

Suppose we need to design a vehicle rental system.

At the HLD level, we might think about:

Mobile App
    ↓
Backend
    ↓
Database
Enter fullscreen mode Exit fullscreen mode

At the LLD level, we think about:

Vehicle
   ↑
   ├── Car
   ├── Bike
   └── Truck

User
Rental
Payment
Enter fullscreen mode Exit fullscreen mode

We then define how these objects interact and what responsibilities they have.


Final Takeaway

LLD is not just about writing classes.

It's about thinking carefully about how code should be structured before writing it.

A good LLD should aim for:

  • Clear responsibilities
  • Low coupling
  • High cohesion
  • Maintainability
  • Extensibility
  • Reusable components
  • Clean relationships between objects

As I continue learning LLD, I'll be exploring OOP, SOLID principles, design patterns, UML diagrams, and real-world LLD problems and applying these concepts through code.

Good LLD is about making the right design decisions before the code becomes difficult to change.

Top comments (0)