2

I have spent a lot of time trying to understand the principle as it is stated. Read maybe several dozen articles "explaining" it, but it feels like everyone is just providing an example without actually specifying the ways that it works in our code in clear english language. The definition is understandable, what it actually means for our classes isn't.

I, maybe, gained a bit of understanding and I want to verify I am correct. Can it be rephrased like this?

Classes should be coded in such a way, that, given the initialization conditions of class instances do not change, any proposed behavioural extension cannot change the behaviour of old code.

Whether the proposed changes are achieved by inheritance or composition of differnt pointer of concrete type derived from an abstract interface we must change the type of the instance of the class we are modifying to a derived one, or pass a different interface implementation for any possible behavioural changes to take effect. Direct code fixes are not acceptable.

Is that it? Do I still not understand it?

jaco0646
  • 15,303
  • 7
  • 59
  • 83
Zeks
  • 2,265
  • 20
  • 32

3 Answers3

1

Honestly, I can't say whether your rephrasing is accurate, because it looks considerably more complicated than the actual OCP. I suspect your version is more restrictive than necessary. In my experience, most people who have not seen the original book seem to have an interpretation of the OCP that is more restrictive than it was intended to be.


The OCP was first defined by Bertrand Meyer in his famous book Object Oriented Software Construction. In the second edition of that book, the description extends from page 57 to 61. I will paraphrase it here.

  • Closed for modification simply means that your code is published to a customer (as an API, a service, a desktop application, whatever) and you've committed to maintaining backwards compatibility.

  • Open for extension means that it should be possible to expand the set of operations or add fields to the data structures of the code you've published.

Meyer states,

With traditional techniques, the two goals are incompatible. Either you keep a module open, [for modification] and others cannot use it yet; or you close it, and any change or extension can trigger a painful chain reaction of changes in many other modules, which relied on the original module directly or indirectly.

Meyer then notes two non-OO solutions: either edit the original code, which is risky, or copy and paste it into a new application, which is redundant and hard to maintain.

As we all know, the claim is that OOP solves the apparent OCP incompatibility through inheritance, i.e. extending code without modifying it. This solution is often oversimplified by saying things like "existing code cannot be edited" however, Meyer explicitly says otherwise.

jaco0646
  • 15,303
  • 7
  • 59
  • 83
1

Classes should be coded in such a way, that, given the initialization conditions of class instances do not change, any proposed behavioural extension cannot change the behaviour of old code.

I don't see a point in not allowing an instance of a specific type to change. I totally agree on not allowing the code of that class to be forced to change.

Whether the proposed changes are achieved by inheritance or composition of differnt pointer of concrete type derived from an abstract interface we must change the type of the instance of the class we are modifying to a derived one, or pass a different interface implementation for any possible behavioural changes to take effect. Direct code fixes are not acceptable.

I would agree on that. Although I have to admit, that is is hard to understand on that level of abstraction. I think it's worth trying to explain the OCP to your collaborators and make the term OCP part of you common language.

Jan Linxweiler
  • 382
  • 2
  • 9
-1

The main point of this principle is modularity and reusability. Think about a diesel engine. In a nutshell, a diesel engine is a black box that has various ports for connecting it to the car: fuel input, air input, foot pedal input, exhaust gas output, torque output. As such, it is a component that doesn't have necessarily be part of a car. You can put it in a ship, electrical generator, lawn mower, water pump, use it for spinning a ferris wheel or even as a starter for a bigger diesel engine. The engine doesn't care about what you use it for as long as you correctly connect inputs and outputs and operate it within the designed range of parameters.

In other words, you don't need to invent a separate engine from scratch if you are making a water pump or a car. This has lots of benefits - you can reduce the manufacturing and maintenance costs, make repairs simpler, recycle spare parts, train your service people to repair just one type of engine, use a single set of tools, standard fuel etc. etc. In a real-life project those things can get absolutely brutal if you don't manage them properly. I see many projects fail precisely because people do not realize how important this principle really is and how to apply it properly. Surprisingly, even senior developers and managers have just as much trouble with it.

The engine itself is not supposed to be serviced by a user. It is closed for modification as the engine internals are none of users' business. Opening it will break the seals and tolerances and void the warranty. And don't even think about modifying some of the engine internals. Do you want to risk the engine breaking down while you are going 200 km/h on a busy road because you replaced a piece of plastic with another that looks the same, but is not designed for the maximum operating temperature and melts? Bad idea, no manufacturer will let you get away with that and some even go as far to install special screws and other forms of tamper protection that will prevent unskilled people from opening it.

Still, the engine is open for extension. Extension is another word for customization. A user can customize the engine as long as he does it within the range of parameters and knobs that the manufacturer has provided and documented as supported. If you are using it in a generator, you might want to fix the throttle to 80% to maximize the torque. If you are going to use it in a racing yacht you might read the manual and adjust the compression and ignition parameters to boost the power since you don't care about fuel consumption. And by turning a single knob, the engine itself will respond by adjusting hundreds of internal little springs and gears - timing of valves, carburator pressure, turbocharger blade geometry etc. It will do this in a way that its operation will remain stable and predictable, and most importantly - it will work.

And you cannot really appreciate what it means that something works until it stops working and in a minute you have thousands of people calling in telling you that they need it NOW!!!1! and that the company is losing millions. Or worse.

But once you have your entire system built with well-designed components, life becomes much simpler and less stressful. For example, when you put diesel engine into a electrical generator, the generator itself becomes a reusable component. The principles of SOLID are not laws of nature, they are all about teaching people how to design good software in an imperfect world. Besides of reducing the costs and increasing the productivity and quality, you also gain something very important: the ability to replace, share and reuse parts of your work within the team and the community.

E_net4
  • 27,810
  • 13
  • 101
  • 139
jurez
  • 4,436
  • 2
  • 12
  • 20
  • Actually no. I have to completely disagree with provided example. Engine that can be configured to work in different modes is not an open/closed principle, it doesn't extend anything, just changes its state based on hardcoded preset parameters. It doesn't deal with manufacturer being able to plug a module that will make the engine swirl rhythmically on demand. – Zeks Oct 04 '22 at 00:44
  • In that case, you already know the answer to your own question. – jurez Oct 04 '22 at 00:45
  • No, I simply think that your provided example is horribly wrong for obvious reasons that pre-produced engine isn't in any way extended (duh). it doesn't mean my own answer is right. – Zeks Oct 04 '22 at 00:48
  • @Zeks "Extending" means "customization". I've updated the answer to make it more clear. – jurez Oct 04 '22 at 01:20