You open a food delivery app, pick a dosa and pay. The app then shows each step: placed, picked up, delivered.
Somebody decided which classes make that work, what each one stores, and which methods it has. That decision is low-level design. This course teaches you to make it, in an interview and at work.
From an idea to code
Software takes four steps from an idea to code. Each step zooms in on the one above it.
what to build
- Ideaorder food, track it
- split into boxes
design
- High-level designservices and databases
- open one boxLow-level designclasses and methodsthis course
- write it
build
- CodeJava, Python, TypeScript
- High-level design (HLD) draws the big boxes: an order service, a payment service, a database. It asks how they scale and talk over the network.
- Low-level design (LLD) opens one box. It names the classes inside, what each one stores, and how they call each other.
So LLD sits between the boxes and the code. You can write code without it, but the first change request shows the cost.
| High-level design | Low-level design | |
|---|---|---|
| The parts | services, databases | classes, methods |
| The question | how does it scale? | who owns what? |
| The picture | boxes and network arrows | class diagram |
| A prompt | design a URL shortener | design a parking lot |
What an LLD interview asks
You get a short prompt, such as "design a parking lot", and about 45 minutes. The prompt is vague on purpose. The interviewer wants to watch you turn it into classes.
They judge five things:
| They check | What good looks like |
|---|---|
| Requirements | you ask questions before you draw |
| Entities | the right classes, one job each |
| Relationships | clear owns, has, uses and extends |
| Extensibility | a new feature adds a class |
| Clean code | clear names, small methods, it runs |
Some rounds end at a class diagram. Others ask you to code the core classes. This course prepares you for both.
One requirement, start to finish
Read the requirement
Here is a small one, the size of an interview warm-up:
A customer orders a dish from a restaurant. A delivery partner picks the order up and delivers it. The customer can see the order's status at any time.
Nouns become classes, verbs become methods
Underline the nouns and the verbs. Nouns are candidate classes. Verbs are candidate methods, on the class that owns the data they change.
| Word | Kind | Becomes |
|---|---|---|
| customer | noun | class Customer |
| restaurant | noun | class Restaurant |
| dish | noun | class MenuItem |
| order | noun | class Order |
| delivery partner | noun | class DeliveryPartner |
| status | noun | field Order.status |
| orders | verb | Customer.placeOrder() |
| picks up, delivers | verbs | Order.markPickedUp(), markDelivered() |
| see the status | verb | Order.getStatus() |
Two words did not become what you might expect:
- Status is a fact about one order. So it is a field of
Order, with three values, not a class of its own. - Picks up is something the partner does, but it changes the order's status. So the method lives on
Order, and the partner calls it.
The rule behind both: a method lives with the data it changes.
Draw the classes
┌────────────────────────────────────────────────────┐ │ │ │ ┌─────────────────┐ uses ┌─────────────────┐ │ │ │ Customer ├───────▶│ Restaurant │ │ │ ├─────────────────┤ ├─────────────────┤ │ │ │ placeOrder() │ │ find(dish) │ │ │ └────────┬────────┘ └────────●────────┘ │ │ │ uses │ owns │ │ ▼ │ │ │ ┌─────────────────┐ has ┌────────┴────────┐ │ │ │ Order │ │ MenuItem │ │ │ ├─────────────────┤ ├─────────────────┤ │ │ │ - items ○────────┤ name │ │ │ │ - status │ │ price │ │ │ ├─────────────────┤ └─────────────────┘ │ │ │ markPickedUp() │ │ │ │ markDelivered() │ │ │ │ getStatus() │ │ │ └─────────────────┘ │ │ ▲ │ │ │ uses │ │ ┌────────┴────────┐ │ │ │ DeliveryPartner │ │ │ ├─────────────────┤ │ │ │ pickUp(order) │ │ │ │ deliver(order) │ │ │ └─────────────────┘ │ │ │ │ ──▶ uses ●── owns ○── has - private │ │ │ └────────────────────────────────────────────────────┘
Each box has the class name on top, then its fields, then its methods. The lines say how classes depend on each other:
- Uses (
──▶):CustomercallsRestaurant.find()and creates anOrder.DeliveryPartnercalls methods on anOrder. - Owns (
●──): a restaurant owns its menu. Remove the restaurant, and its menu items go too. - Has (
○──): an order points at menu items, but the items live on after the order is done.
Read and draw class diagrams covers these lines in detail. For now, read each one as a short sentence.
Watch the objects talk
A class diagram shows who knows whom. It does not show the order of the calls. A sequence diagram does.
- Customer to Restaurant:find(dish)
- Restaurant to Customer:a MenuItem
- Customer to Order:new Order(item)
- Delivery partner to Order:markPickedUp()
- Delivery partner to Order:markDelivered()
- Customer to Order:getStatus()
- Order to Customer:DELIVERED
Notice that every status change goes through Order. Nobody else writes to status.
The code
Here are Order and Customer, the two classes at the heart of the flow:
enum Status { PLACED, PICKED_UP, DELIVERED }
class Order {
private final List<MenuItem> items;
private Status status = Status.PLACED;
Order(List<MenuItem> items) { this.items = items; }
void markPickedUp() { status = Status.PICKED_UP; }
void markDelivered() { status = Status.DELIVERED; }
Status getStatus() { return status; }
}
class Customer {
private final String name;
Customer(String name) { this.name = name; }
Order placeOrder(Restaurant restaurant, String dish) {
MenuItem item = restaurant.find(dish);
return new Order(List.of(item));
}
}statusis private. Only the three methods ofOrdertouch it, so no other class can set a wrong value.placeOrderasks the restaurant for the item, then creates the order. The customer never builds aMenuItemitself.Restaurant,MenuItemandDeliveryPartnerfollow the same shape. A run of the whole flow printsPLACED,PICKED_UP,DELIVERED.- In TypeScript, a union of three strings does the job of the enum. In Python, a leading underscore marks a field as private.
Five moves for every problem
You made most of these moves above. The course uses the same five on every problem.
┌────────────────────────────────────────────────┐ │ │ │ 1 requirements what must it do? │ │ ▼ │ │ 2 entities which classes exist? │ │ ▼ │ │ 3 relationships who owns, has, uses? │ │ ▼ │ │ 4 patterns does a known shape fit? │ │ ▼ │ │ 5 code the core classes, run │ │ │ └────────────────────────────────────────────────┘
- Requirements. Write what the system must do, and ask about the limits.
- Entities. Pick classes from the nouns. Give each one job.
- Relationships. Draw the lines: owns, has, uses, extends.
- Patterns. Look for a problem with a known answer, such as "many ways to pay".
- Code. Write the core classes and run the main flow.
The order app skipped move 4. Three statuses and one kind of partner need no pattern. A pattern earns its place only when a change request needs it. Part two of the course shows when.
How this course works
Three parts
| Part | Lessons | What you learn |
|---|---|---|
| Foundations | 9 | objects, principles, class diagrams, SOLID |
| Design patterns | 23 | creational, structural, behavioural |
| LLD in practice | 39 | concurrency, real systems, interview problems |
The parts follow the order of the takeUforward LLD sheet. The last part designs and then codes 12 classic problems, such as a parking lot and an elevator.
One path in every lesson
Each principle and pattern lesson walks the same path:
- The problem: code that works today, then a change request that hurts it.
- The idea: the principle in one sentence, and a class diagram.
- The fix: the same code, rebuilt, so the change request becomes one new class.
- How it runs: the objects calling each other, as a sequence diagram.
- When to use it: the signals in a requirement, and when it is too much.
Code in three languages
Every code block has Java, Python and TypeScript tabs. Pick one once, and every block on the site follows it.
- The three versions use the same names: camelCase in Java and TypeScript, snake_case in Python.
- Each version was run, and all three print the same output.
- Abstract types are interfaces in Java and TypeScript, and
abc.ABCclasses in Python.
- 01
Low-level design sits between the boxes and the code: which classes exist, what each one owns, and how they call each other.
- 02
An LLD interview judges five things: requirements, entities, relationships, extensibility and clean code.
- 03
Nouns become candidate classes. Verbs become methods on the class that owns the data they change.
- 04
Use the same five moves on every problem: requirements, entities, relationships, patterns, code.
Read more
- takeUforward LLD sheet, the order this course follows
- Object-oriented programming concepts, the Java tutorial's short tour of objects and classes
- The PaymentIntents API and its status lifecycle, a real design built from nouns and verbs
Next: objects, classes and the four pillars, on a payments module you can run.