High-quality software designs are easier and safer to work with. Investing in quality demands discipline and skill. Good design principles are usually helpful. But, are they always applicable?
This post investigates the limits on the applicability of the “Open/Closed Principle” when we add new functionality to a software design whose source code is entirely under our control.
The Open/Closed Principle (OCP)
The “Open/Closed Principle” (OCP) was first advocated by Bertrand Meyer in the first edition (1988) of his book “Object Oriented Software Construction” and is considered by Bob Martin as “the most important principle of object-oriented design”.
OCP states that modules should be open for extension and closed for modification. New functionality should be implemented by adding new classes, attributes and methods, instead of changing the current ones.
The simplest way to apply OCP is to implement the new functionality on new derived (sub)classes that inherit the original class implementation. Another way is to mediate client access to the original class with an abstract interface, so new functionality can be implemented on new classes that are accessed through the same interface. Both ways create new classes and leave the original implementation untouched.
Modular and Expressive Abstractions
High-quality software designs are made of modular and expressive abstractions.
Modularity is a design quality at syntactical level. A design’s abstraction is a module if its internal implementation and external context are coupled only through the specification of its responsibilities.
Modular designs enable its abstractions to be locally implemented and globally reusable. Modularity facilitates human minds to engineer highly complex and adaptable systems.
Expressiveness is a design quality at semantic level. A design’s abstraction is expressive if its specification represents a domain concept.
Expressive designs can easily articulate abstractions to clearly express the relevant concepts, problems and solutions. Expressiveness facilitates understanding and communication that enable human minds to engineer relevant and valid solutions.
Identifying, representing and separating relevant concerns is the fundamental principle for our design process.
Concerns bridge syntax and semantics to define abstractions and assign responsibilities that compose and decompose modular and expressive designs.
When OCP should be Deliberately Broken
When our domain model, system requirements or design objectives change radically, new concerns unfold and emerge as relevant.
The new concepts, problems and solutions can only be expressed after the respective concerns are also represented and separated in the design; otherwise, we would introduce duplication and break modularity.
The emerging concerns must be distilled from all the modules where they were mixed with other concerns. That is when we deliberately break the OCP, opening and changing previously existing classes in order to represent and separate the new concerns.
New relevant concerns can emerge from either small or big changes. Fowler’s Video Store didactic program provides us with a good example. Creating an HTML version of the customer’s statement makes its format a relevant concern. The
statement method must be opened and factored to avoid duplication. After format is separated from content, the OCP again must be observed when creating new versions for other formats.
Separation of concerns not only guides the deliberate breaking of the OCP but also fundamentally underlies the “Single Responsibility Principle“.
Special thanks to Kent Beck for the enlightening inspiration!
Picture from WikiMedia Commons.