SOLID Principles#
flowchart LR
S([S - Single Responsibility])
O([O - Open / Closed])
L([L - Liskov Substitution])
I([I - Interface Segregation])
D([D - Dependency Inversion])
S --> O --> L --> I --> D
classDef p fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
class S,O,L,I,D p;
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class S,O,L,I,D service;
Five principles for object-oriented design. Follow them and your classes stay small, intent-revealing, and easy to change.
classDiagram
direction LR
class SRP {
+Single Responsibility
+A class has ONE reason to change
+Split classes by axis of change
}
class OCP {
+Open / Closed
+Open for extension
+Closed for modification
+Use interfaces + polymorphism
}
class LSP {
+Liskov Substitution
+Subtypes must be usable wherever
+base type is expected
+preserve contracts
}
class ISP {
+Interface Segregation
+Clients shouldn't depend on
+methods they don't use
+Many small interfaces - one fat one
}
class DIP {
+Dependency Inversion
+Depend on abstractions
+not concretions
+High-level modules don't import
+low-level details
}
SRP --> OCP
OCP --> LSP
LSP --> ISP
ISP --> DIP
Each principle in one sentence#
| Principle | Tells you to... | Smell when violated |
|---|---|---|
| S ingle Responsibility | give each class one reason to change | "And"-named classes; methods touch unrelated state |
| O pen / Closed | extend behaviour by adding new types, not editing old ones | sprawling if (type == ...) chains |
| L iskov Substitution | make subclasses substitutable for their base type | if (instanceof Square) workarounds; thrown UnsupportedOperationException |
| I nterface Segregation | split fat interfaces so clients only see what they use | classes implementing 20 methods to satisfy 1 caller |
| D ependency Inversion | depend on abstractions, inject concretions from outside | new HttpClient() inside a domain class |
Worked example: OCP#
Before (violates OCP - every new shape needs an edit to area()):
class AreaCalculator {
double area(Shape s) {
if (s instanceof Circle) return Math.PI * ((Circle)s).r * ((Circle)s).r;
if (s instanceof Rectangle) return ((Rectangle)s).w * ((Rectangle)s).h;
throw new IllegalArgumentException();
}
}
After (open for extension - add a new shape, no edits to existing code):
interface Shape { double area(); }
class Circle implements Shape { public double area() { return Math.PI * r * r; } }
class Rectangle implements Shape { public double area() { return w * h; } }
class AreaCalculator {
double area(Shape s) { return s.area(); }
}
How SOLID shows up in this site#
Most of the LLD-flavoured designs (Parking Lot, Elevator, Vending Machine, ATM, Chess, Logger) rely on: - SRP to split state / pricing / dispatch into separate classes. - OCP + LSP to add new vehicle types / piece types / payment methods without editing the core. - DIP to inject payment gateways, storage backends, time sources.
Glossary & fundamentals#
Concepts referenced in this design. Each row links to its canonical page; the tag column shows whether it is a high-level (HLD) or low-level (LLD) concept.
| Tag | Concept | What it is | Page |
|---|---|---|---|
LLD |
OOP pillars | encapsulation, abstraction, inheritance, polymorphism | oop-pillars |
LLD |
SOLID principles | SRP / OCP / LSP / ISP / DIP | solid-principles |
LLD |
Error handling | exceptions vs Result, error boundaries | error-handling |
Quick reference#
Why it matters#
SOLID is the canonical sanity check for OO designs. It doesn't guarantee good design - but its violations are reliable red flags.
Per-principle gotchas#
- SRP: "responsibility" = axis of change. A
Userclass that handles persistence and password hashing has two axes of change (DB schema vs auth policy). - OCP: hardest to apply preemptively. Apply it when you've actually seen the second variation, not the first.
- LSP: contracts cover pre/post-conditions, invariants, and exceptions - not just method signatures. The classic counterexample: a
SquareextendingRectanglebreaks the post-condition "setWidth doesn't change height". - ISP: in Go-style languages, interfaces are implicit and small by convention. In Java/C#, do it explicitly.
- DIP: pair with DI. Dependencies passed in via constructor / setters / framework - never
newinside business logic.
SOLID vs other acronyms#
| Acronym | Stands for | Focus |
|---|---|---|
| SOLID | five OO principles | class-level design |
| DRY | Don't Repeat Yourself | duplication |
| KISS | Keep It Simple, Stupid | over-engineering |
| YAGNI | You Aren't Gonna Need It | speculative features |
| CUPID | Composable, Unix-philosophy, Predictable, Idiomatic, Domain-based | systems-oriented alternative to SOLID |
Refs#
- Robert C. Martin: "Clean Architecture" (2017) - full SOLID treatment.
- Uncle Bob's original 2002 papers on each principle.
- Dan North: "CUPID - for joyful coding" (2022) - alternative framing.
FAQ#
What does SOLID stand for?#
Single responsibility, Open-closed, Liskov substitution, Interface segregation, and Dependency inversion. Five OO design principles popularised by Robert C. Martin.
What is the single responsibility principle in plain English?#
A class should have one reason to change. If two different stakeholders would request changes to the same class, split it along that seam.
What is the open-closed principle?#
A module should be open for extension but closed for modification. You add new behaviour by introducing a new type, not by editing existing code.
What is Liskov substitution principle?#
Subtypes must be usable wherever the base type is expected without surprising callers. Violations show up as code that needs to know the concrete subclass.
Are SOLID principles still relevant?#
Yes. They are guidelines, not laws, and they map well onto modern dependency injection, hexagonal architecture, and even functional design with interface-shaped types.
Related Topics#
- Dependency Injection: DIP is one of the five SOLID principles and drives DI container design
- Clean Architecture: SOLID principles are the structural rules that make clean architecture layers stable
- Composition over Inheritance: OCP and LSP directly motivate favouring composition over inheritance hierarchies
Further reading#
Curated, high-credibility sources for going deeper on this topic.