Do private members/methods inherently violate the open-closed principle


Doesnt private members and methods inherently violate the open-closed principle?
Given that private, protected and public modifiers are supported.

I came across this many times in codebases where developers use private modifiers for members and methods for whatever reason which in turn requires me to copy entire blocks of code to be able to extend it.
I feel like many people just use private out of habit because its use cases are very nieche in my opinion and almost all the time protected does the job as well.

Best Answer

Thought experiment: imagine a component designed to be OCP-compliant, with certain extension points and public members, so it can be reused in a black-box fashion in several use cases. Imagine also the component has some or several private members.

Now, imagine the private members were all made public - then the same component would still be as reusable as before. So this makes it clear private members - at least technically - don't contribute to the OCP.

That still does not mean they violate the OCP. Nevertheless you are right - in real-world components, sometimes developers miss occasions for opening a possible extension point to the client by keeping something private, which should be made public. Usually, this involves more than just exchanging the keyword private by public, but sometimes this is all what appears to be needed.

However, one should not jump to the conclusion that it is better to make every member public in a reusable component "just in case". The OCP is usually only one of many goals you have to aim for when designing reusable components. Other typical goals are

  • to keep the component maintainable and evolvable,

  • to keep the number of breaking changes low when creating a new version

  • to keep the API of a component as simple as possible, so another dev has only to learn and understand the 5 public methods to use it and can ignore the 95 private methods which they don't care for.

And that's why private members are required - to keep the the impact of changes low, and the whole component comprehensible for a client. That's especially important when you don't know all the clients who are potentially reusing your component - by making a method or field private, you signal to them

  • you don't have to know what this method does when you just want to use this component

  • this part of the code might become subject to change at a later point in time

  • don't fiddle around with this member from the outside, you may accidentally break some invariant.

Hence, the design of reusable, long-living components is often a trade-off. If one

  • is 100% sure a component's source code will never-ever become subject to change, not even for a bug fix, and

  • does not care whether a component is used by clients in an anticipated "correct" way, or if clients may shoot themselves in the foot

then one may use only public members. But as soon as you want to provide updates and new releases, you have to find a balance between private and public members.