Let's talk about your privates

Warning: This blogpost has been posted over two years ago. That is a long time in development-world! The story here may not be relevant, complete or secure. Code might not be complete or obsoleted, and even my current vision might have (completely) changed on the subject. So please do read further, but use it with caution.
Posted on 07 Nov 2021
Tagged with: [ php

In the software development world, there are a lot of debates going on: tabs vs. spaces, vim vs. emacs, Linux vs. mac, and so on. In most, if not all, these debates, there is no clear winner: both sides are equally right (or wrong), and most likely, there is no majority on one side. I, however, am part of a debate on the “losing” side in such that I’m part of the minority. And even though strong opinions are weakly held, after I guess since the launch of PHP 5, my opinion still holds, and I’m talking about your privates…

Here is the whole debate:

<?php

class Foo {
    /** protected or private? */
    string $bar;
}

Should this $bar property be protected or private? I think the correct answer would be “it depends”, but my answer would be “protected by default,” while the majority of users would opt for “private by default.” I think this is the wrong way of looking at the issue. So let’s explain why I think why this is.

Visibility

To decide what the best visibility is, we need to know the difference between protected and private. In a nutshell: Protected means that the property (or method) cannot be accessed from code OUTSIDE the existing class. However, classes that EXTEND the given class CAN access the property or method. Private means that even classes that extend this class cannot access the property. It’s private to this specific class alone.

Why private?

So why is the majority of users using private? More than often, it’s because “it is the way.” There is no actual reasoning behind it when you ask the question. Still, it most likely boils down to maintainability for those who have a reason: it’s much easier to refactor a class that you are 100% confident is not referenced outside the class. And this is true! It makes a lot of sense: if you write a library and open-source it, there is no real way of knowing who is using your code, and changing a method or property can break a lot of code from your users. There is merit in making everything private because it allows a lot of flexibility for you and your class.

Why protected?

One simple reason: You should not decide for me how I use your library or code. That’s it.

A library can be built for many use-cases, but it’s a 100% certainty that you as a developer do not know ALL the use-cases your library may be used or abused for. Some of these use-cases could be plain stupid, and some of these use-cases are entirely valid. The point is: by making your properties and methods private, you just decided for ALL YOUR USERS that your library is not to be used in a way that you didn’t think of beforehand.

Sure, you can create an issue or PR to change private into protected as soon as you find a use case. But let me know how that works in practice. The times this is done in those libraries are rare, and of course, you can fork the lib, but now you have to take responsibility for ALL library code, including security issues and whatnot. And maintain more code is precisely what we want in life.

What about composition over inheritance?

Well, I agree. Composition should be used over inheritance. But it’s OVER inheritance, not INSTEAD OF inheritance. There are many use-cases where inheritance is valid, even the only option.

How about the practical side of things?

I’ve been bitten by final/private many, many times over. By small libs and by large frameworks and libraries. I’ve been bitten by protected, well.. never. I do not know of any other person who is bitten by my love for protected visibility. Often I have a library that does exactly what I want until it doesn’t. And very often, it’s a straightforward fix to make sure it does work: if only I could extend this class and override this method :( Instead, now I have to copy/paste an entire class, update a single method, often even a single line and maintain this piece of code into eternity.

But my users are complaining about breaks!

Here is the thing: IF you are doing a BC break, any BC break, you should use semver and upgrade your major release number. But protected does something else intentionally: it moves the responsibility of USAGE from the library writer to the library user. Protected says: “Hey if you need to do something I didn’t foresee, here is the tooling. But know that you are on your own!”. And I kind of like this attitude: it allows users who do not want this responsibility to use your library the way they always have done. Nothing is changing or is more dangerous now that we use protected. We just more your code more open. And it will enable those power users can change the 1% of your library without rewriting the other 99%. I think this is a clear win, but somehow, we are indoctrinated that we should care for our users like children who cannot take care of themselves. We need to educate people on why things are dangerous, instead of saying: this is dangerous, and I will take it away from you so you can’t hurt yourself.

Eating your own dogfood

If you look at some of my open-source libraries, you might see that I’m using privates as well. Why is this? The first time I use protected, within 5 minutes, there will be a pull request or an issue opened about changing it to private. And now we are in a debate with people that I don’t feel like I need to have over and over again. It gets too tiresome. There are too many battles I (want to) fight, and this is one too many.