DEV Community

Cover image for SOLID principles explained: the foundation of an object-oriented design interview
Gowtham Potureddi
Gowtham Potureddi

Posted on

SOLID principles explained: the foundation of an object-oriented design interview

SOLID principles explained: the foundation of an object-oriented design interview

Every object-oriented design interview is really a test of whether your classes will survive change, and the SOLID principles are the five-letter vocabulary for talking about that. They are not trivia to recite — they are the reasons behind the decisions a good design makes: why pricing lives in its own class, why you code against an interface instead of a concrete type, why a new feature should be a new class rather than an edit to an old one. An interviewer who asks "why did you structure it that way?" is asking you to answer in SOLID, whether or not they name it.

This guide explains the five principles the way they actually matter in an OOD interview — each with a short before-and-after that shows the smell and the fix — and then shows how they surface as the reasoning inside a low-level design round, from the parking lot to the rate limiter. The goal is not to memorise five definitions; it is to recognise which principle a design decision is really about, so that when the interviewer pushes on a seam you can name the principle, explain the trade-off, and adjust the design out loud.

Title card for an object-oriented design interview guide to the SOLID principles, showing the five letters S O L I D each paired with its principle — single responsibility, open/closed, Liskov substitution, interface segregation and dependency inversion — and a before-and-after sketch of a tangled class refactored into clean, decoupled classes, on a dark citrus-and-lavender background.

Why SOLID comes up in object-oriented design interviews

SOLID shows up two ways: as a direct question ("what does the D in SOLID stand for, and when have you used it?") and, more often, as the hidden grading rubric behind every design decision you make. When you put pricing behind an interface in a parking-lot design, you are applying the open/closed and dependency-inversion principles; the interviewer may never say the words, but that is what they are rewarding. The principles are a favourite because they separate a candidate who memorised definitions from one who can feel a design going wrong and name why.

The interviewer rarely accepts a definition on its own. "You told me your Report class formats the data, writes it to a PDF, and emails it. Which SOLID principle does that violate, what breaks when the business later wants CSV instead of PDF, and how would you restructure it?" That question — spotting the single-responsibility smell and fixing it without breaking callers — is the one a memorised acronym can never survive, and the one these principles are really testing.

The rounds on Zynter are modelled on how the loop runs, not scraped from any candidate's recall. What matters for prep is the shape: you make a design decision, and the interviewer asks you to justify it — and the cleanest justification is almost always one of these five principles.

What the interviewer is really testing

A SOLID answer is read on the same four dimensions as any design round. Problem solving — can you spot which principle a messy design violates and propose a fix that does not create a new mess? Communication — can you state each principle in one plain sentence, with an example, rather than quoting a textbook? Technical execution — when you refactor, does the result actually decouple the classes, or just move the tangle? Time management — do you apply the principles where they earn their keep, rather than over-engineering a three-class problem into fifteen? Reading this guide teaches the principles; it does not teach you to apply them while someone changes the requirement mid-answer.

The five SOLID principles at a glance

SOLID is an acronym for five principles of class design, popularised by Robert C. Martin. Each targets a specific way that code becomes rigid or fragile as it grows.

Letter Principle In one sentence
S Single Responsibility A class should have one reason to change — one job.
O Open/Closed Open for extension, closed for modification — add behaviour by adding code, not editing existing code.
L Liskov Substitution A subtype must be usable anywhere its base type is, without surprising the caller.
I Interface Segregation Many small, specific interfaces beat one fat interface nobody fully implements.
D Dependency Inversion Depend on abstractions, not concretions — high-level code shouldn't hard-wire low-level details.

A diagram of the five SOLID principles, each shown as a letter card with its name and a tiny icon: single responsibility as one class with one job, open/closed as a class extended by a new subclass rather than edited, Liskov substitution as a subtype slotting cleanly into a base-type socket, interface segregation as one fat interface split into several small ones, and dependency inversion as a high-level module pointing at an abstraction instead of a concrete class.

S — Single Responsibility Principle

A class should have one reason to change. When a class does several unrelated things, a change to one of them risks breaking the others, and the class becomes a magnet for edits. The classic smell is a class whose name contains "and," or one that mixes business logic with formatting and I/O.

// Smell: three reasons to change — computation, formatting, delivery.
class Report {
    String compute() { /* business logic */ }
    String toPdf()   { /* formatting   */ }
    void   email()   { /* I/O          */ }
}

// Fix: one responsibility per class; each changes for its own reason.
class Report        { String compute() { ... } }
class PdfFormatter  { byte[] format(Report r) { ... } }
class EmailSender   { void send(byte[] doc) { ... } }
Enter fullscreen mode Exit fullscreen mode

Now "the business wants CSV, not PDF" touches a new CsvFormatter and nothing else — and that is also the open/closed principle starting to pay off.

O — Open/Closed Principle

Software should be open for extension but closed for modification: you should be able to add new behaviour without editing code that already works and is already tested. The smell is a growing if/switch on a type — every new case forces you back into the same method.

// Smell: every new shape edits this method.
double area(Shape s) {
    if (s.type == CIRCLE) return Math.PI * s.r * s.r;
    if (s.type == SQUARE) return s.side * s.side;
    // ...adding a triangle means editing here again
}

// Fix: each shape owns its area; a new shape is a new class, no edits.
interface Shape { double area(); }
class Circle implements Shape { public double area() { return Math.PI * r * r; } }
class Square implements Shape { public double area() { return side * side; } }
Enter fullscreen mode Exit fullscreen mode

This is exactly why pricing in a parking lot lives behind a PricingStrategy interface — a new rate is a new class, not an edit to the ticket.

L — Liskov Substitution Principle

A subtype must be substitutable for its base type without breaking the caller's expectations. The smell is a subclass that overrides a method to throw, do nothing, or change the contract — forcing callers to check "which subclass is this really?"

// Smell: Penguin is-a Bird, but can't fly — callers of fly() break.
class Bird { void fly() { ... } }
class Penguin extends Bird { void fly() { throw new UnsupportedOperationException(); } }

// Fix: model the capability, not a false hierarchy.
interface Bird { }
interface FlyingBird extends Bird { void fly(); }
class Sparrow implements FlyingBird { public void fly() { ... } }
class Penguin implements Bird { /* no fly() to break */ }
Enter fullscreen mode Exit fullscreen mode

The lesson for an interview: inheritance is for "behaves-as," not just "is-a-kind-of." If a subclass can't honour the base contract, the hierarchy is wrong.

I — Interface Segregation Principle

No client should be forced to depend on methods it does not use. The smell is a fat interface that different implementers only partly fill, leaving stubbed or exception-throwing methods.

// Smell: a robot worker is forced to implement eat() and sleep().
interface Worker { void work(); void eat(); void sleep(); }

// Fix: split by what clients actually need.
interface Workable { void work(); }
interface Feedable { void eat(); }
class Human implements Workable, Feedable { ... }
class Robot implements Workable { ... }   // no eat()/sleep() to stub
Enter fullscreen mode Exit fullscreen mode

Small, role-specific interfaces keep implementers honest and callers decoupled — and they set up the dependency-inversion principle.

D — Dependency Inversion Principle

High-level modules should not depend on low-level modules; both should depend on abstractions. In practice: code against an interface and inject the concrete implementation, rather than new-ing it inside your class. The smell is a high-level class that constructs its own dependency, welding itself to one implementation.

// Smell: OrderService is welded to MySQL — can't swap or test it.
class OrderService {
    private MySqlDatabase db = new MySqlDatabase();   // hard-wired
}

// Fix: depend on an abstraction, inject the concrete type.
interface OrderRepository { void save(Order o); }
class OrderService {
    private final OrderRepository repo;               // an abstraction
    OrderService(OrderRepository repo) { this.repo = repo; }
}
Enter fullscreen mode Exit fullscreen mode

Now OrderService works with MySQL, Postgres, or an in-memory fake for tests, and none of that is its concern. Dependency inversion is what makes code testable and swappable, and it is the principle interviewers probe most for senior roles.

A before-and-after diagram of the dependency inversion principle, showing on one side a high-level OrderService class with a hard-wired arrow pointing directly at a concrete MySqlDatabase class, and on the other side both the OrderService and the MySqlDatabase pointing at an OrderRepository interface in the middle, with the concrete database injected at construction so it can be swapped for a fake in tests.

How SOLID shows up inside a low-level design round

In a real LLD round you rarely get asked "name the five principles." Instead, SOLID is the language you use to justify the model and to answer the follow-ups. A few recurring moments:

  • "Where does pricing / tax / discount logic go?" → Behind an interface, chosen at runtime (open/closed + dependency inversion). A new rule is a new class.
  • "Add a new vehicle type / payment method / notification channel." → A new subclass or implementation, touching nothing that already works (open/closed). If it forces edits across many classes, a boundary is wrong.
  • "This class is doing a lot — is that a problem?" → Name the single-responsibility smell and split it by reason-to-change.
  • "How would you test this?" → Dependency inversion is the answer: because the class depends on an interface, you inject a fake.

Say it plainly: SOLID isn't a checklist I run at the end — it's the reason behind each boundary I draw, and it's what lets me absorb the requirement you add halfway through without rewriting what already works. That framing is what reads as a designer rather than a memoriser.

A diagram mapping SOLID principles onto moments in a low-level design round, showing pricing logic placed behind an interface (open/closed plus dependency inversion), a new vehicle type added as a subclass that touches nothing else (open/closed), an overloaded class split by reason-to-change (single responsibility), and a class tested by injecting a fake implementation (dependency inversion), each labelled with the interviewer question it answers.

Low-Level Design
LLD · OOD foundations
Apply SOLID in a live design round out loud

Practise on Zynter →

How to talk about SOLID in an interview

The probes rhyme across all five letters. Master these and you can defend a design decision in any OOD round.

  • "Which principle does this class violate?" → Usually single responsibility (it has more than one reason to change) or open/closed (a growing switch on type); name it and show the split. (problem solving)
  • "Add this new case without breaking anything — how?" → Open/closed via a new class behind an existing interface; no edits to tested code. (technical execution)
  • "Is this a valid use of inheritance?" → Only if the subtype honours the base contract everywhere (Liskov); if it throws or no-ops a base method, prefer composition or a smaller interface. (communication)
  • "How would you make this testable?" → Dependency inversion: depend on an interface and inject the concrete type, so a fake slots in for tests. (technical execution)
  • "Aren't you over-engineering?" → Apply the principles where change is likely, not everywhere; a three-class problem doesn't need fifteen. Knowing when not to is part of the signal. (time management)

Each maps to a debrief dimension. Reading them teaches the answers; it does not teach you to deliver them while someone adds a requirement that stresses your boundaries — that only comes from saying them out loud.

How to prepare: a short plan

You do not need to memorise definitions. You need to recognise the smell each principle addresses and the fix, fast enough to apply them live.

  • Day 1: For each letter, learn the one-sentence statement, the smell it targets, and a before-and-after you can write from memory (the Report split, the shape switch, the penguin, the fat Worker, the hard-wired database).
  • Day 2: Practise spotting violations in a messy class and refactoring out loud — and practise saying when a principle does not apply, so you don't over-engineer.
  • Day 3: Do a full LLD problem (parking lot, rate limiter) and narrate every boundary in SOLID terms, timed, with someone adding a requirement that forces you to lean on open/closed and dependency inversion.

This guide feeds the broader low-level design interview track — SOLID is the reasoning underneath every design problem there, so getting it reflexive pays off across all of them.

Low-Level Design
LLD · Core skills
Refactor a violation live and defend the fix out loud

Practise on Zynter →

Frequently asked questions

What are the SOLID principles?

SOLID is an acronym for five object-oriented design principles that keep classes flexible as code grows: Single Responsibility (a class should have one reason to change), Open/Closed (open for extension, closed for modification), Liskov Substitution (a subtype must be usable anywhere its base type is), Interface Segregation (prefer many small, specific interfaces over one fat one), and Dependency Inversion (depend on abstractions, not concrete classes). Together they target the specific ways code becomes rigid, fragile or hard to test. In an interview they matter less as definitions to recite and more as the reasoning you use to justify why your classes are structured the way they are.

What is the Single Responsibility Principle with an example?

It says a class should have only one reason to change — one job. The classic violation is a Report class that computes its data, formats it as a PDF, and emails it: three unrelated responsibilities, so a change to the formatting can break the delivery, and the class attracts edits from every direction. The fix is to split it into a Report that computes, a PdfFormatter that formats, and an EmailSender that delivers. Now each class changes only for its own reason, and supporting CSV output means adding a CsvFormatter rather than editing the report. The practical test is whether you can describe the class's job without using the word "and."

What is the difference between the Open/Closed and Dependency Inversion principles?

They are related but answer different questions. Open/Closed is about adding behaviour: you should be able to extend a system by adding new classes rather than editing existing, tested ones — typically by having new types implement an existing interface, so a growing if/switch on type disappears. Dependency Inversion is about direction of dependencies: high-level code should depend on an abstraction (an interface) rather than a concrete low-level class, and the concrete implementation is injected in. In practice they work together — coding against an interface (dependency inversion) is often what makes a design open to extension (open/closed) — but one is about what you depend on, and the other is about how you grow the system.

What is a Liskov Substitution Principle violation?

It is when a subclass cannot stand in for its base class without breaking the caller's expectations. The textbook example is a Penguin extending a Bird that has a fly() method: a penguin can't fly, so the subclass either throws an exception or does nothing, and any code calling fly() on a Bird reference breaks when handed a penguin. Another common one is a Square subclassing a Rectangle whose width and height can be set independently. The fix is to model capabilities honestly — for example a separate FlyingBird interface — so that inheritance expresses "behaves as," not merely "is a kind of." The giveaway is a subclass that overrides a method to throw or no-op.

How do SOLID principles help in a low-level design interview?

They give you the vocabulary to justify every boundary you draw, which is exactly what the follow-ups probe. When the interviewer asks where pricing logic should live, "behind an interface, so a new rate is a new class" is open/closed and dependency inversion. When they add a new vehicle type or payment method, "a new implementation that touches nothing already tested" is open/closed. When a class is doing too much, naming the single-responsibility smell and splitting it shows design maturity. And when they ask how you'd test a class, dependency inversion is the answer. Using SOLID as the reason behind your decisions — not a checklist recited at the end — is what distinguishes a designer from someone who memorised an acronym.

How do I practise applying SOLID out loud?

Reading the principles is not the same as spotting a violation and refactoring it while an interviewer changes the requirement. On Zynter, the low-level design track runs live voice rounds modelled on how real OOD loops run — you write your classes in the editor and a voice interviewer follows up one question at a time ("which principle does this class violate?", "add CSV output without breaking PDF", "how would you test this?"), then gives you a debrief on problem solving, communication, technical execution and time management. The score is a practice signal, not a hiring decision.

Practise it on Zynter

You can recite all five letters. The round is won on spotting the violation and fixing it out loud.

Pick a low-level design round, write your classes in the editor, and defend them out loud to a voice interviewer that keeps asking "which SOLID principle does that violate?" and "add this new case without editing what already works" — then read the debrief. Zynter.ai is on-demand mock interviews modelled on real company loops, with 150+ rounds across 20 companies including the low-level design track (Sep 2026).

Practise a low-level design round →
Browse all interview tracks

Top comments (0)