Pragmatism over Theory: Protected vs Private
Fabien Potencier
March 29, 2011
I often favor pragmatism over theory; probably because programming is how I earn a living but also because I don't have any computer science degree and what I know I've learned from my experience.
In the recent months, there have been a lot of discussions in the PHP community about the usage of private over protected visibility for methods and properties in Open-Source libraries.
To summarize my point of view:
"private" is for purists and "protected" is for pragmatic developers.
Coming from Perl, I've been a strong advocate of never using private for anything (as far as I remember, there is not a single use of private in symfony1; and until recently, the usage of private was explicitly disallowed in Symfony2 -- it was even part of the Symfony2 coding standards!).
So, why Symfony2 changed its mind? Yep, I've just wrote Symfony2, not I. As Symfony2 is a community driven project and because we have such a large number of contributors, I'm not the only one who take decisions. And if some people have strong arguments, I'm willing to change things even if I'm not a big fan of them.
Anyway, a couple of weeks ago, we have started to switch most protected properties and methods to private. And guess what, just two weeks after the change, I already have two great stories and lessons to share with you.
Besides obvious mistakes we have fixed right away, all the requests we had for reverting back to protected lead to better solutions so far.
First, someone complained about not being able to customize the Routing component. Here is the conversation we had on Twitter (translated from French):
@InformatHic: The closing of the Symfony2 API is a real ordeal. (cc @fabpot)
@fabpot: @InformatHic we can reopen the API if necessary. But give me examples first.
@InformatHic: Finally I cleaned up my code and I must say that it is much cleaner now. (cc @fabpot)
Having a few well defined extension points force the developer to extend your library the right way instead of hacking your code.
And now, for the second example. The Symfony2 Console component is used by many PHP libraries outside the Symfony world, like Behat. For Behat, Konstantin used to override some methods that I've switched from protected to private. At first, he was annoyed. But after some discussion with Bulat, they came up with a much better solution: they actually decoupled the code and added a new and clean way to solve the problem at hand and as a result, they made the component more beautiful and more customizable.
Closing the API allows design flaws to be found more easily and gives you the opportunity to evolve your code by creating well defined extension points.
So, even if I still believe that using private is not a hard rule you should blindly follow, I can see some pragmatic advantages. And it's not like we cannot change our mind if needed. Changing a private method to protected is simple and won't break any code. But before doing that, you need to understand what the developer is trying to achieve and if you cannot find a better way to resolve his problem without opening the API too much.
By the way, public methods does not define the public API. Sometimes, you
need to declare a method as public because you need to access it from another
class in your library; but that does not mean that you want your users to
actually call it directly. What do you do then? Symfony and Flow3 have decided
to mark the "real" public API with the @api tag. All classes, methods, and
properties tagged with @api are public in the sense that we guarantee their
stability over time: their name, signature, and behavior won't change for
any minor version of the library. That's a strong commitment; one that I like
much better than any strict enforcement done on the language level.




Discussion
I mean, classes should only call other classes API, and to avoid calling methods which are not meant to be public, a better solution can always be found... am I wrong ?
this is possible if the library is still changing, like Symfony, but as soon as the library is stable, I don't see how you could refactor it to make it more extensible without breaking things.
So yes for private first and change them to protected if needed, but if it requires refactoring and breaking the library, is it good?
Finally, I think privates force you to potentially break things in the future.
Would you mind giving us an example ?
"Finally, I think privates force you to potentially break things in the future."
That's quite the contrary actually. You cannot break things with private methods. And if needed, you can still change them to protected.
Again, it depends on concrete needs, but I prefer protected.
And if find an class having too many, then perhaps it's an indication that the class needs refactoring/splitting. This would also make methods more testable.
Keep 'em methotds private, do not let me break anything! Just bwcause one sunny morning I decide to be a smart a** and extend native Symfony Core (Look, Fabien haven't thought of that,he-he!), does not mean I am allowed to do this!
Save me my own time, spent on debugging my own stupidity, and just keep those methongs shut ;)
I'm interested in knowing if you followed any particular methodology when it came to privatising protected methods? Did you simply replace every protected with private and fix all the errors and refactor methods as appropriate or perhaps you had a more focused plan of attack?
Cases where you would use the friend relationship in c++ or the "internal" access modifier in c#
I sort of agree with you but I'd leave it at:
Many methods is a code smell.
For anyone who that is lost on. "ours go to eleven"
an improvement like the one requested here <http://bugs.php.net/bug.php?id=52297> would help, imho ;)
You can use interfaces to declare API, but not strange tags.
And fields should be declared 'protected' when class designed to be extended, and 'private' otherwise - all simple. Any other rules (like 'all fields must be private') looks non-logical as minimum.
Is it possible that the code was improved not because closing the API forced people to refactor, but just because of the simple fact that they were forced to refactor at all? A lot of companies (including all those that I have worked for) don't really approve of refactoring - they would rather produce crap code, but make more money. So if there is some horrible code that works despite it's horribleness, we just leave it. We refactor when there is a real need.
Why doesn't PHP have 'final' methods like Java?
Apparently I'm still sleeping.
Private methods are usually a sign that those methods don't belong in the current class, but in a separate class that provides services for the current one.