This article will present the Open Close Principle (OCP). Along with the introduction of this topic, examples from MechLynx project will be used (https://github.com/CharlieGearsTech/MechLynx)
SOLID principles were introduced by Robert C. Martin around 2000. These principles are “guidelines”, they are not rules due that the application of these principles for certain software systems will not be feasible or recommended in some cases. The goal of these principles is to create reusable software modules that are able to tolerate changes over time and are easy to understand.
The principal value of Software Systems is their ability to change during their lifetime, therefore they should be open to changes. Bad designs does not allow to make changes easily, a system is called bad design regarding OCP if these changes are:
- Difficult to implement, the system is defined as rigid
- Easy to make the system collapse, then the system is defined as fragil.
- Required to propagate changes to another SW component, and those SW components need to be deployed along the change even when they are not related with this change, then the system is defined as immobile.
To avoid these bad designs, developers should thrive to not modify old code as much as possible when changes are being added.
Bertrand Meyer coined a OCP as follow:
“Software entities should be open for extension, but closed for modification”
Software entities definition can be classes, modules, namespaces, function ect.
As a matter of example, MechLyxn SW systems were requested to support operations written as infix notation. The structure is simple as follow:
After a few successful releases, the client wants to add a new requirement to support RPN (Reverse Polish Notation). Following the current design of MechLynx, these changes can be added to the logic of Infix Syntax Analyzer and create a Syntax Analyzer component:
The compile function() is a multilevel function which wraps up several instructions (loading workspace, lexical analysis result collection, check if syntax analysis is feasible, ect.), adding RPN support to this code, will make modification throughout all these responsibilities, even sometimes there will be a risk to omit areas of change, producing insidious bugs.
Modifications will cause features that were running correctly, might miswork, unit tests might need to change and regression tests might urge to execute again. Therefore, more effort and risk are present due a change that from the client perspective, was an “addition” to something that already was working.
MechLynx, then, is a rigid system, due it is resistive to changes. By definition, MechLynx is not delivering the principal value of Software: Systems shall be open to changes.
One possible solution to comply with OCP, is to create an abstract class SyntaxAnalyzer. RPN Syntax Analyzer and Infix Syntax Analyzer are concrete classes and derive from Syntax Analyzer:
With this approach, Infix Syntax Analyzer remains relatively unaffected (it was changed to derive from SyntaxAnalyzer only). The creation of an Abstract class Syntax Analyzer permits the addition of new features as RPN Notation support without affecting old code Infix Syntax Analyzer, fully complying with OCP. Additionally, this structure permits the addition of more notations with the same result: Addition without affecting old code.
In class level perspective, this implementation complies with the Single Responsibility Principle, since RPN Syntax Analyzer serves only one actor RPN Notation Expert, and Infix Syntax Analyzer serves another actor Infix Notation Expert.