SOLID is five design guidelines for object-oriented code: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. Robert C. Martin described the underlying ideas in the early 2000s, and the acronym stuck because each letter names a specific way software rots as it grows. None of the five is a law. They are heuristics for keeping change cheap, and every one of them has a point past which following it adds more ceremony than value.
What changed in 2026
- AI coding assistants generate SOLID-flavored scaffolding by default. Ask an assistant for a service class in 2026 and it often produces an interface, a single implementation, and a dependency-injection wrapper, even for code that will only ever have one implementation. Review generated abstractions before keeping them.
- Dependency-injection libraries are common outside enterprise Java now. InversifyJS and tsyringe made constructor injection a normal pattern in Node.js backends too.
- Static analysis catches coupling violations in CI. Complexity and coupling linters, which flag classes with too many reasons to change, are now a standard pre-merge check on many teams.
- Functional composition is a live alternative in parts of the JavaScript ecosystem. Codebases built around pure functions and composition get some of the same benefits without classes at all.
SOLID at a glance
| Principle |
One-line rule |
What it prevents |
| Single Responsibility |
A class should have one reason to change |
Unrelated changes forcing edits to the same file |
| Open/Closed |
Extend behavior without editing existing code |
Regressions in code that already worked |
| Liskov Substitution |
A subclass must work anywhere its parent does |
Surprising behavior when swapping implementations |
| Interface Segregation |
Do not force a class to implement methods it does not need |
Bloated interfaces with fake or empty methods |
| Dependency Inversion |
Depend on abstractions, not concrete classes |
Code that cannot be tested or swapped without a rewrite |
Single responsibility and open/closed
Single Responsibility means a class or module should have exactly one reason to change. A class that formats a report and also saves it to disk has two reasons to change. Splitting them means a storage change never risks breaking formatting. Full walkthrough: the single responsibility principle explained.
Open/Closed asks you to extend behavior with new code rather than editing code that already works. Adding a new payment method should not require editing the checkout function's if/else chain; adding a new class that implements the existing payment interface is safer, because nothing that already passed tests gets touched.
Liskov substitution and interface segregation
Liskov Substitution says a subclass must be usable anywhere its parent is expected, without surprising the caller. The classic violation is a Square that extends Rectangle but forces width and height to change together, breaking any code that sets them independently.
Interface Segregation says a class should not be forced to implement methods it does not need. A ten-method interface where every implementer fakes six of them is a sign the interface should be split into smaller, role-specific ones. This is closely tied to how interfaces and abstract classes divide responsibility; see interface vs abstract class in 2026 for the mechanics.
Dependency inversion: the one with the biggest payoff
Dependency Inversion says high-level code should depend on an abstraction, not a concrete low-level class. The concrete class then depends on the abstraction instead of the other way around, which is what makes unit testing without a live database or network call possible.
// Before: OrderService depends on a concrete class
class OrderService {
private db = new PostgresOrderStore();
}
// After: OrderService depends on an abstraction
interface OrderStore { save(order: Order): Promise<void>; }
class OrderService {
constructor(private store: OrderStore) {}
}
Full treatment, including when this is worth the extra indirection, in dependency inversion explained in 2026.
When to apply SOLID and when to skip it
A growing codebase with multiple contributors and a long expected lifespan benefits most, especially from Single Responsibility and Dependency Inversion. A script or prototype with one clear owner usually does not; premature interfaces add indirection with no payoff. Applying all five principles to a small internal tool tends to create more files to navigate than the problem justifies. Name that tradeoff honestly before reaching for an abstraction.
FAQ
Do I need to use all five principles in every project?
No. Treat them as a checklist to consult when a class feels hard to change safely, not as a mandatory pass over every file you write.
Is SOLID only for object-oriented languages?
Mostly, but the underlying ideas, single responsibility and depending on abstractions, apply to functional code too, just without the interface and inheritance vocabulary.
What is the most commonly violated SOLID principle?
Single Responsibility, by a wide margin. Classes and functions accumulate unrelated responsibilities gradually, one small addition at a time, until nobody notices the class does five unrelated things.
Does SOLID guarantee good software design?
No. It reduces certain categories of pain, rigidity, fragility, and tight coupling, but says nothing about naming, algorithm choice, or whether the feature was worth building.
Where to go next