The SOLID principles are 30 years old but remain absolutely relevant. Revisited through the lens of modern architectures — microservices, functional programming, AI — they reveal their depth.
SOLID is an acronym popularised by Robert Martin grouping five object-oriented design principles. Often presented as rules to follow mechanically — that's a mistake. They're heuristics that guide design, not absolute laws. Understanding why they exist allows intelligent application.
Single Responsibility Principle — a class should have only one reason to change. Not "one method" or "one hundred lines maximum": if you modify a class for business reasons and technical reasons, it carries too many responsibilities. The most cited and most misapplied of the five.
Open/Closed Principle — open for extension, closed for modification. Adding behaviour should not require changing existing code, only extending it — via polymorphism, strategies, or plugins. This limits regression on already-tested code.
Liskov Substitution Principle — a subtype must be substitutable for its parent without altering the behaviour of the program. Any violation betrays a flawed inheritance hierarchy: if
Square extends Rectanglebreaks Rectangle's preconditions, the inheritance relationship is wrong.Interface Segregation Principle — prefer several specific interfaces over one general-purpose one. A class should not be forced to implement methods it does not need. The result: smaller, more readable contracts, easier to mock in tests.
Dependency Inversion Principle — depend on abstractions, never on concretions. The most transformative of all: it is at the heart of testability and hexagonal architecture. It allows replacing an SQL database with NoSQL, an external API with a mock, without touching business code. In a functional context, this principle maps directly to pure functions: no side effects, no hidden coupling.
SOLID under modern architectures
These five principles were formulated in a classical object-oriented context — Java, C++, early 2000s. Their relevance has not diminished, but how we read them has evolved.
In microservices, SRP shifts scale: it is no longer the class that must have a single responsibility, but the entire service. A microservice that handles both billing and user management violates SRP at the architectural level. The decomposition into bounded contexts from Domain-Driven Design is a direct application of this principle at scale.
In frontend development, OCP translates to composing components rather than modifying them. A well-designed React or Angular component is extended through its props or slots, not modified for each new use case. Effective design systems are built on this principle.
With generative AI, DIP becomes a critical safeguard. AI code assistants readily generate tightly coupled code — direct calls to concrete APIs, hard-coded instantiations, implicit dependencies. Reviewing AI-generated code through the lens of DIP immediately reveals fragility hotspots.
When not to apply SOLID
SOLID applies where complexity justifies it. On a utility script, a prototype, or a CRUD with no business logic, imposing five layers of abstraction creates more friction than it resolves. Pragmatism remains the engineer's first virtue: these principles are tools, not obligations. Applied mechanically, they produce exactly the kind of over-engineering they were meant to prevent.
→ See also: Clean Architecture · Hexagonal architecture