Skip to content

Low Level DesignSOLID principles

SOLID principles

What the five SOLID principles are for, a one-line test for each, how they fit together, and when to ignore them. The starting point for the SOLID pages.

Foundation8 min read

SOLID is five principles for arranging classes so that code stays easy to change. Robert Martin collected them in a 2000 paper, Design Principles and Design Patterns, and Michael Feathers later noticed their initials spelled a word. None of them is a law. Each one is a response to a specific way that object-oriented code gets hard to change, and each has a cost.

They matter for interviews because almost every low level design question is really a question about change. “Add a new vehicle type.” “Now support a second payment provider.” “Make the pricing configurable per lot.” Each follow-up tests whether your design bends in the right places. SOLID is the vocabulary for explaining why it does.

Principle The question it asks You’re breaking it when
Single responsibility How many different groups ask for changes to this class? A change for one team breaks something another team relies on
Open/closed Can I add the next variant by adding code, not editing it? Every new type means another branch in the same switch
Liskov substitution Can every subtype be used wherever its parent is expected, with no surprises? Callers check instanceof, or a subclass throws “not supported”
Interface segregation Does each caller depend only on the methods it uses? Classes implement methods that do nothing, just to satisfy an interface
Dependency inversion Do business rules depend on details, or do details plug into business rules? You can’t test the core logic without a real database or API

The five aren’t independent. In a real design they work as a chain: each one sets up the next.

Each principle sets up the next

keeps it honest

Single responsibility
finds the seams:
where one actor's code ends

Interface segregation
keeps each seam small:
only what the caller needs

Dependency inversion
points dependencies
at the seams

Open/closed
adds new behavior
by plugging into a seam

Liskov substitution
makes anything plugged in
safe to use

keeps it honest

Single responsibility
finds the seams:
where one actor's code ends

Interface segregation
keeps each seam small:
only what the caller needs

Dependency inversion
points dependencies
at the seams

Open/closed
adds new behavior
by plugging into a seam

Liskov substitution
makes anything plugged in
safe to use

Scroll or pinch to zoom, drag to pan

A worked example from the parking lot: pricing changes for a different reason than spot tracking, so it gets its own class (single responsibility). The lot only needs “what does this ticket cost?”, so the interface has one method (interface segregation). The lot depends on that interface, not on HourlyPricing (dependency inversion). A weekend rate is a new class, with no edit to the lot (open/closed). And every pricing class must return a real amount for any ticket, never throw “not supported” (Liskov substitution).

Every principle adds structure, and structure has a cost: more types, more files, more indirection to follow when reading.

Lean away from them when:

  • The code is small, young or short-lived. A script, a prototype, or a feature whose shape you don’t know yet. Wait for the second variant before adding an interface for it.
  • There is one actor and one implementation, and no test needs a fake. An interface with one implementation that will never have a second is a cost with no benefit.
  • The language has a lighter tool. A function parameter, a Go interface declared by the caller, or a TypeScript union with an exhaustive switch often does the job of a class hierarchy, with less code.
  • The hot path needs speed. Virtual calls and small objects can matter in tight loops, though far less often than people assume. Measure first.

Interviewers rarely ask “what does the L stand for?” They create a situation where a principle matters and watch what you do.

Interviewer

Good. Now we want to support electric vehicle charging spots. Walk me through the changes.

What they are testing

Whether your design takes the change as new classes, plus one line of wiring. And whether you can name why: the spot types sit behind an interface the lot depends on. The red flag is answering with a list of if statements across three classes. So is reciting all five principles, instead of showing the one that matters here.

When you explain a design choice, name the principle and the change it protects against, in one sentence. Then say what it costs: “Pricing is behind an interface, so a new rate is a new class. The cost is one more type to read.”

Read them in the order of the acronym. But if you only have time for two, read single responsibility and dependency inversion. Those two drive most of the class splits in a low level design interview. The other three refine them.

Each page teaches its principle through three real examples at Easy, Medium and Hard. The level you pick is remembered across all the SOLID and design pattern pages.