“Open/Closed” is the second principle proposed by SOLID. I wrote a post about Single Responsibility some days ago, and now it’s time of this. Let’s compile some definitions I got from several other papers first, and then I would like to go through some conclusions, thoughts or personal opinions at the end.
First of all, this is the acronym: OCP
Principle says: Software entities (classes, modules, functions, etc.) should be open for extension, but closed to modification. Actually, add classes or functions, but don’t change them. When requirements change, you extend the behavior of such modules by adding new code, not by changing old code that already works.
Open for extension: A common way to extend functionality is to create additional public methods. New or changed features would require the creation of a different class (inheritance is a good practice to apply this concept. “Abstraction is the Key.”)
Close for modification: Opposite of extension, the code should be locked down enough so that it isn’t necessary to be modified. “Write once, change never!”. Why? Changes introduce errors. As all rules, of course, we have an exception: errors corrections is the unique reason why a class could be modified (bugs!).
I read some advantages of obeying OCP:
- Less number of unit tests to refactor when adding additional functionality.
- Less research required to understand necessary changes. (Here the principle talks about code review. Good! since it’s not usual to talk about this at this level of definition.)
- Faster turnaround to programming changes.
- All of the benefits of SRP.
When reading this kind of principles, I like to distrust or not believe all at first impression at least. And I think we sometimes we can learn more from disadvantages than from advantages. At the end, nothing is law or global truth in terms of design (not only at software!). That’s why I find this definition interesting: “It should be clear that no signiﬁcant program can be 100% closed. The designer must choose the kinds of changes against which to close his design“.
From the same source I also read about “Data Driven Approach”. Along with Abstraction, saving behaviors in tables is other good practice to not modify your code when news features come. Adaptability is just a matter of a new configuration in the database. Personally, with this approach I see much clearer the concept of Open/Closed principle.
Searching for an example, I arrived to Strategy pattern, which contributes to the enforce of OCP:
Consider a car class. Two possible functionalities for car are brake and accelerate. In the strategy pattern, the behavior can be changed without breaking the classes that use it, and the classes can switch between behaviors by changing the specific implementation used without requiring any significant code changes. Behaviors can also be changed at run-time as well as at design-time. For instance, a car object’s brake behavior can be changed from
Brake()by changing the
brakeBehavior = new Brake();
The image illustrates the example better:
Time of conclusion
What it’s difficult to see when reading about OCP, it’s when it’s time to clean the old code. Since you are adding always new code when new features appear, “old” code won’t be modified and new methods and classes will be added systematically. The amount of framework code compared to the amount of business code is really small.
At this point, it’s when you really think about the importance of tests, speciality unit ones. That robustness is needed to ensure that, after cleaning code, nothing is broken using those apparently old methods and functions.
However, there is not clear evidence at what point we should do this. But I think that could a be a good practise to plan and schedule time to discard functionality that is not needed any more.