Which SOLID principle has genuine architectural consequences, and which one most often produces harm?
Show the full answer Hide the answer
What is being tested
Whether you can separate the architecturally load-bearing part of a well-known acronym from the coding guidance around it.
Why dependency inversion is the architectural one
High-level policy should not depend on low-level detail; both depend on an abstraction. In practice the
domain defines the interface it needs — OrderRepository — and the infrastructure implements it. The
dependency arrow points inward, toward the stable thing.
That single rule is what makes hexagonal and clean architecture work, what makes a database replaceable without touching business logic, and what makes the domain testable in milliseconds without infrastructure. It is the difference between a system whose core survives a framework change and one that must be rewritten alongside it.
Why open/closed most often harms
Read literally — "open for extension, closed for modification" — it encourages extension points before the variation exists. The result is abstract factories and strategy interfaces with exactly one implementation, added for a second case that never arrives.
That is premature abstraction with an acronym behind it. It costs indirection now, in exchange for an option that is usually never exercised, and it makes the code harder to read for everybody in the meantime.
The healthier position: write the direct code, and refactor to an abstraction when the second and third variations actually appear. That refactor is mechanical and safe; un-abstracting a speculative design is neither.
The other three, briefly
Single responsibility is useful when stated as "one reason to change", which is really about change correlation — the same test that identifies a good service boundary. It is harmful when misread as "do one thing", which justifies splitting into pieces that must always change together.
Interface segregation matters at service boundaries: a consumer should not be coupled to what it does not use. This is the same instinct as consumer-driven contracts declaring only the fields actually consumed.
Liskov substitution is largely subsumed by preferring composition over inheritance, which most modern codebases already do.
The honest summary
The architectural content is: point dependencies at stable abstractions, and put boundaries where change correlates. The rest is craft, and reciting the acronym in design review generates ceremony rather than better structure.