Open-Closed Principle

A class or module should be open for extension and closed for modification.
This principle was introduced by Bertrand Meyer. According to him class or module should be open for extension and closed for modification. In other words, you should be able to change the behavior of the class or module without changing the existing code.
What the heck?🙄 Is it really possible?🤔 This was the first word that came out of my mouth when I read it for the first time. Actually we do it oftentimes; let's decode it with an example.
Let’s consider a typical example of a terms and conditions screen. The user will be presented with terms and conditions, he has two buttons to accept and deny it. We have to save the user’s selection inside the local storage.
Below is the crude way to implement the functionality. It does not follow any of the good coding practices also violates the open-closed principle.
A manager comes to us and says the client has a lot of problems with this application, so he has hired a consultant. They have a new idea, the client wants to provide two versions of this software. In the free version, data will be stored locally on the device and in the paid version it will be stored remotely on the server.
Now we have to tell our manager that, we will be able to add the functionality for the store it on the remote server but we have to deploy both functionalities together. As per the current design, there is no way to separate the functionality. This called immobility.
When we add the functionality for storing data on a remote server the UI and business logic will get recompiled, this is rigidity.
Also, we have to add a check whether the account is paid or free and accordingly execute the code for saving the data. There will be several such conditions throughout the codebase making the code fragile.
How to apply the Open-Closed principle?
Let’s modify this code to avoid these bad symptoms and achieve the objective of paid and free accounts. Let's segregate the class into two modules, first will be responsible for UI related stuff and second will deal with data storage options.
We will continue using activity for UI related stuff. We have also created a presenter that will segregate the business logic from our UI.
These two classes will be part of our UI module. In the same module, we will be defining the TermsAndConditionsRepository interface which has a method for updating terms and conditions preference. TermsAndConditionsPresenter will always depend on this abstract interface instead of the actual implementation.
Now in the second module, we will be having an implementation of the above interface that will store the data in local storage. I am calling it as TermsAndConditionsLocalRepository.
After refactoring this code now we have to make changes to store data on a remote server. Now we will create a new class in another module called TermsAndConditionsRemoteRepository, which will extend the TermsAndConditionsRepository and deal with communication with the server. I am using the Retrofit library for this purpose.
As we have added the TermsAndConditionsRemoteRepository the code inside TermsAndConditionsPresenter and TermsAndConditionsActivity will not be recompiled so we get rid of rigidity.
There are no if-else conditions as we have separate versions of the application as requested by the client. This will get rid of fragility.
We will compose the application either with local storage or remote server. This will get rid of immobility.
Where to apply this principle?
This principle will help us to protect against the changes. That does not mean we have to apply it to each and every class. Practically it is almost impossible to do it considering the time and effort it will take.
Instead, we should identify the points where an application is prone to changes. Apply this principle only at those points. There are two ways to identify these changes, one is from your previous experience another is from the user’s feedback. By following the Agile methods we will be able to get continuous feedback from the user and with it, we will be able to apply this wherever needed. This is an ongoing process and will evolve with time.