Private vs Protected - Visibility Good-Practice Concern [closed]

I've been searching and I know the theoretic difference.

  • public - Any class/function may access the method/property.
  • protected - Only this class and any subclasses may access the method/property.
  • private - Only this class may access the method/property. It won't even be inherited.

That's all fine and well, the question is, what's the practical difference between them? When would you use private and when would you use protected? Is there a standard or acceptable good practice over this one?

Up until now, to retain the concept of inheritance and polymorphism, I use public for anything that should be accessed from the outside (like constructors and main class functionality), and protected for internal methods (logic, helper methods etc). Am I on the right track?

(Note that this question is for me, but also for future reference as I haven't seen a question like this one SO).


Solution 1:

No, you're not on the right track. A good rule of thumb is: make everything as private as possible. This makes your class more encapsulated, and allows for changing the internals of the class without affecting the code using your class.

If you design your class to be inheritable, then carefully choose what may be overridden and accessible from subclasses, and make that protected (and final, talking of Java, if you want to make it accessible but not overridable). But be aware that, as soon as you accept to have subclasses of your class, and there is a protected field or method, this field or method is part of the public API of the class, and may not be changed later without breaking subclasses.

A class that is not intended to be inherited should be made final (in Java). You might relax some access rules (private to protected, final to non-final) for the sake of unit-testing, but then document it, and make it clear that although the method is protected, it's not supposed to be overridden.

Solution 2:

Let me preface this by saying I'm talking primarily about method access here, and to a slightly lesser extent, marking classes final, not member access.

The old wisdom

"mark it private unless you have a good reason not to"

made sense in days when it was written, before open source dominated the developer library space and VCS/dependency mgmt. became hyper collaborative thanks to Github, Maven, etc. Back then there was also money to be made by constraining the way(s) in which a library could be utilized. I spent probably the first 8 or 9 years of my career strictly adhering to this "best practice".

Today, I believe it to be bad advice. Sometimes there's a reasonable argument to mark a method private, or a class final but it's exceedingly rare, and even then it's probably not improving anything.

Have you ever:

  • Been disappointed, surprised or hurt by a library etc. that had a bug that could have been fixed with inheritance and few lines of code, but due to private / final methods and classes were forced to wait for an official patch that might never come? I have.
  • Wanted to use a library for a slightly different use case than was imagined by the authors but were unable to do so because of private / final methods and classes? I have.
  • Been disappointed, surprised or hurt by a library etc. that was overly permissive in it's extensibility? I have not.

These are the three biggest rationalizations I've heard for marking methods private by default:

Rationalization #1: It's unsafe and there's no reason to override a specific method

I can't count the number of times I've been wrong about whether or not there will ever be a need to override a specific method I've written. Having worked on several popular open source libs, I learned the hard way the true cost of marking things private. It often eliminates the only practical solution to unforseen problems or use cases. Conversely, I've never in 16+ years of professional development regretted marking a method protected instead of private for reasons related to API safety. When a developer chooses to extend a class and override a method, they are consciously saying "I know what I'm doing." and for the sake of productivity that should be enough. period. If it's dangerous, note it in the class/method Javadocs, don't just blindly slam the door shut.

Marking methods protected by default is a mitigation for one of the major issues in modern SW development: failure of imagination.

Rationalization #2: It keeps the public API / Javadocs clean

This one is more reasonable, and depending on the target audience it might even be the right thing to do, but it's worth considering what the cost of keeping the API "clean" actually is: extensibility. For the reasons mentioned above, it probably makes more sense to mark things protected by default just in case.

Rationalization #3: My software is commercial and I need to restrict it's use.

This is reasonable too, but as a consumer I'd go with the less restrictive competitor (assuming no significant quality differences exist) every time.

Never say never

I'm not saying never mark methods private. I'm saying the better rule of thumb is to "make methods protected unless there's a good reason not to".

This advice is best suited for those working on libraries or larger scale projects that have been broken into modules. For smaller or more monolithic projects it doesn't tend to matter as much since you control all the code anyway and it's easy to change the access level of your code if/when you need it. Even then though, I'd still give the same advice :-)