Continuing with the SOLID principles, today we will come to these two principles. To understand my point of view, you can read the Single Responsibility Principle.
📌 What Is the Open/Closed Principle?
The Open/Closed Principle, introduced by Bertrand Meyer in Object-Oriented Software Construction (1988), is defined as follows:
“A software artifact should be open for extension but closed for modification.”
This means a software component should allow new features to be added without modifying existing code.
❓ What Does That Actually Mean in Software?
Most developers understand and apply this principle at the level of a single class or service. That’s not necessarily wrong — but that’s not true OCP either.
To properly implement OCP, you must consider it at the architectural level, across your entire project, not just individual modules. This principle helps preserve the long-term structure of your system.
🧪 Let’s Imagine an Experiment
Imagine you’re showing a page of business reports to users. Now, the user wants to export the report in a nicely formatted Word or PDF file.
Of course, we need to write new code — but here’s the real question:
How much of the existing code do we need to modify?
A well-designed software architecture aims to minimize code changes — ideally, none.
However, we know that in about 80% of cases, OCP can be satisfied this way. But we must also respect the Single Responsibility Principle (SRP) when designing.
⚙️ Separation of Concerns: Logic vs. Presentation
After implementing the reporting system, you realize it has two main parts:
Calculation
Presentation (output)
Any future changes — like adding a new export format — should be made only in the Presentation part. Thanks to this separation, we are confident that changes in one responsibility do not affect the other.
🔄 Direction of Dependency and OCP
Let’s say it again:
If Component A needs to be protected from changes in Component B, then B should depend on A, not the other way around.
In our example, we want to protect the Controller from changes in the Presenter. Therefore, the Presenter should depend on the Controller — but the Controller must not know about the Presenter.
🎯 Why the Interactor Is an OCP Champion
The Interactor is in the best position regarding OCP. Why?
It is not affected by changes in the Controller, Presenter, or even Database.
It holds the core business logic and policies, and it’s not concerned with the implementation details of other components.
If you’re still unclear, go back and look at the previous image again.
We designed our system top-down and when we needed to add a new export format, we first respected SRP, and then applied OCP.
🧩 Real-World Conflict: When OCP Is Broken
Let’s be careful:
Even though we can add new capabilities to the Interactor, if that involves changing its interface, then the Controller must change too.
👉 That would violate OCP.
However, if we only add code to the Controller, and the Interactor remains untouched, then we’ve fully respected OCP.
✅ Final Conclusion
We can conclude:
Designing the system from large to small helps protect lower-level components from unnecessary changes.
And in approximately 80% of use cases (this is an intuitive figure), OCP can be achieved.
Whenever you manage to fully respect OCP, you’ve likely designed an ideal system.
_Author: Hossein Molaei
Translation from Persian to English by artificial intelligence
ref: Clean Architecture (Robert C Martin)_
I love c# 🥰