Skip to main content

Command Palette

Search for a command to run...

SOLID Principles Explained

Updated
•3 min read•View as Markdown
SOLID Principles Explained

The Rules That Make Design Patterns Actually Work

If Object-Oriented Design is the foundation,
then SOLID principles are the load-bearing pillars.

Design patterns assume your code follows SOLID.
Without SOLID, patterns feel forced, confusing, and over-engineered.

Let’s break SOLID down

What Is SOLID?

SOLID is an acronym for five design principles that helps us write:

  • Flexible code

  • Maintainable systems

  • Change-friendly designs

S → Single Responsibility
O → Open / Closed
L → Liskov Substitution
I → Interface Segregation
D → Dependency Inversion

Each principle exists to reduce pain when requirements change.

S — Single Responsibility Principle (SRP)

A class should have only one reason to change

Problem

One class:

  • Handles business logic

  • Saves to database

  • Sends emails

  • Logs activity

Result:
One change breaks everything.


Better Mental Model

One responsibility
→ One reason to change
→ One focused class

Intuition:

class InvoiceService {
    calculateTotal();
}

class InvoiceRepository {
    save();
}

SRP makes code:

  • Easier to test

  • Easier to change

  • Easier to understand


O — Open/Closed Principle (OCP)

Open for extension, closed for modification

Problem

if (type.equals("CARD")) {
    payByCard();
} else if (type.equals("UPI")) {
    payByUpi();
}

Every new feature → modify old code


Solution

New behavior
→ New class
→ No change to existing code

Intuition:

interface Payment {
    void pay();
}

New payment?

  • Add a new implementation.

  • Old code untouched.


L — Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types

Sounds scary
Actually very simple.


Classic Violation

If code expects a Bird that can fly,
and you pass an Ostrich — things break.


Mental Rule

If it looks like a duck,
it should behave like a duck.

In practice:

  • Don’t lie with inheritance

  • Don’t surprise the caller

LSP teaches you when NOT to use inheritance.


I — Interface Segregation Principle (ISP)

Clients should not be forced to depend on methods they don’t use


Problem

interface Worker {
    work();
    eat();
    sleep();
}

What about a robot?
It doesn’t eat or sleep.


Better Design

Small interfaces
→ Specific roles
→ Less forced implementation

Intuition:

interface Workable { void work(); }
interface Eatable { void eat(); }

ISP leads to:

  • Cleaner abstractions

  • Less coupling

  • Happier implementations


D — Dependency Inversion Principle (DIP)

Depend on abstractions, not concrete implementations

This is the backbone of testable and flexible systems.

Tight Coupling

High-level logic depends directly on low-level details.

Result:

  • Hard to test

  • Hard to change

  • Hard to mock


Inverted Dependency

High-level → Interface ← Low-level

Intuition:

class OrderService {
    private Payment payment;

    OrderService(Payment payment) {
        this.payment = payment;
    }
}

Now:

  • Behavior is swappable

  • Testing is easy

  • Code is future-proof


How SOLID Connects to Design Patterns

SOLID PrinciplePatterns That Use It
SRPAlmost all patterns
OCPStrategy, Decorator
LSPInheritance-based patterns
ISPAdapter, Facade
DIPFactory, Dependency Injection

Design patterns are practical applications of SOLID.


Summary

SRP → One reason to change
OCP → Extend, don’t modify
LSP → Don’t break expectations
ISP → Small, focused interfaces
DIP → Depend on abstractions

Together, SOLID principles:

  • Reduce coupling

  • Increase clarity

  • Make change safer


Final Thought

Bad code fails loudly.
Bad design fails slowly and expensively.

SOLID doesn’t make your code perfect —
it makes it resilient to change.

Once SOLID is clear, design patterns stop feeling magical
and start feeling obvious.