A Perfect Storm

We’re nearing the end of the year and when I look back at 2020, aside from all the turmoil in the world, more than anything I feel very, very tired.

It largely feels like I have been running from one open-source crisis to another since May/June. Crisises which were outside my control, but had to be tended to anyway.

No matter that a Composer plugin I’m a co-maintainer of was prepared for Composer 2.0 well in advance. When Composer 2.0 was released into the world this October and prevailing CI systems updated quickly, there were still lots and lots of projects which hadn’t updated to the new version we released in June, resulting in support requests and emergency update rounds for various projects.

Along the same lines, while the latest PHPUnit was prepared for Xdebug 3, a lot of real-world projects are not using the latest version of PHPUnit. Again, when the prevailing CI systems were updated to use Xdebug 3 quickly after the release, emergency fixes were needed to prevent projects from being completely blocked by CI code coverage runs failing.

And when Travis finally broke down, and even though they are still not owning up to it, stopped supporting open source, again, there was a scramble to move all CI builds for all open source projects to other CI platforms, which again took huge amounts of time, under pressure, as progress in projects was blocked while the CI wasn’t running.

And let’s not talk about PHP 8.0…

Or actually, maybe we should.

From an open-source maintainer point of view, PHP 8.0 is, not to put too fine a point to it, a nightmare. Don’t get me wrong; I love all the new features and I compliment and thank everyone who has contributed. I can’t wait to start using the nullsafe object operator or union types once projects I work on drop support for PHP < 8, but that will be another few years at the very least.

In the meantime, I had to prepare projects, or help prepare projects for the fall-out. And fall-out there is.

Combine the engine exception changes with union types, which now allowed for adding lots of new type declarations to PHP internal functions, and you get a release that throws fatal errors on code that worked perfectly fine without even a notice or a warning in previous PHP versions.

Top that up with changes in return types for some pretty commonly used functions and you get code that may end up doing the complete opposite of the originally intended behaviour, again without any warning or notice in previous PHP versions.

And while static analysis tools can guestimate where there may be problems in your code, as these changes are all related to the run-time value and type of variables, the only sure-fire way to detect these fatal errors and behavioural changes is to run the tests on PHP 8…

This brings its own problems as lots of open source projects which – for their own reasons – support a wider range of PHP versions than just the latest and greatest, were still using PHPUnit 5/6/7 to run their tests on PHP 7.4 due to the addition of the void return type to fixture methods in PHPUnit 8.

So, instead of being able to focus on fixing their PHP 8 problems, these projects now first have to find a way to get their tests running on PHPUnit 4 to 9.3+ and have to pay the technical debt they had built up from not doing so earlier.

A small project like PHPUnit Polyfills, going from first public mention to over 50.000 downloads in just eight short weeks, testifies to the amount of projects which are scrambling to make their test suites PHPUnit cross-version compatible.

And that’s for the projects which have tests.

The unfortunate reality is that a significantly large number of projects do not have unit tests or when they do have tests, those only cover a small portion of their codebase.

So, again, instead of being able to focus on fixing their PHP 8 problems, these projects now first have to raise their code coverage by writing additional tests.

And let’s not forget the difference between testing the happy path versus the unhappy path. A significantly large number of tests in projects only test the happy path, while the problems created by PHP 8.0 lie mostly in the unhappy path.

So, again, instead of being able to focus on fixing their PHP 8 problems, projects now have to write even more tests to make sure the unhappy path in their code is sufficiently covered.

Are you feeling the pain yet?

And don’t even get me started on named parameters in function calls. A change that was voted in late July, suddenly makes parameter names in function declarations part of the public API.

This means that every single function declaration in the public API of an open-source project has to be reviewed for those parameter names being suitable for public use, as as soon as PHP 8 came out, changing any of them will now be a breaking change.

Now doing this for your own small, 5.000 lines of code, pet project may be a one-day job, but having to do this for a 500.000 line codebase in one of the most extended pieces of software in the PHP world, where nearly everything is public API, in just four months… well, you get my drift.

Of course, you may say: “but a project can indicate it is not compatible (yet) with PHP 8 in the version constraints in their composer.json“. You are wrong. As that presumes that the software will be installed via Composer, which for projects with a large non-technical userbase is rarely the case.

Open source projects, which basically are expected to be cross-version compatible by the release date of a new PHP version, now have to break with the past and actively declare themselves incompatible or “alpha-compatible” with the latest version of PHP for the time being.

And that is presuming those projects even keep track of changes in PHP ahead of a release and don’t just look at the changelog or migration guide for the first time once the release has come out.

With all that going on, the barrier for updating legacy code to use a more modern PHP version has gone up exponentially and for some, may even have become insurmountable.

I believe PHP is doing itself a huge disservice by not making these changes opt-in. It feels like it’s lost touch with a significant part of its user-base and that the impact of these changes has been grossly underestimated.

Yes, these changes are all nice and dandy when you work in a closed-source environment, where everything is under your control, you only have to deal with one PHP version at a time and get paid to write tests for the code you write.

However, for the majority of unpaid, overworked open source maintainers, working on software that is extended in ways they never imagined when the project started, these changes are a huge additional burden to carry, especially with the added time-pressure of having to be ready in time for the release of PHP 8.

I have seen beautifully coded projects, which are largely unused and some of the ugliest code I’ve ever seen is in projects used by millions.

Historically PHP has always been a very forgiving language. Now, that “contract” with the dev users has been broken.

Why force a “one way” of coding upon everyone? Why, when things are a significant break with the past, not make things optional?

I’d be the first to take that option. But the whole thing about it being an option is that it puts the power in the hands of your users, which is where it belongs.

While I laud the progressiveness of the changes in PHP 8.0, the reality is that 40.0% of all PHP servers still run PHP 5, 53% of that PHP 5.6, which means 47% still run on PHP < 5.6. *

There is just a hell of a lot of legacy code out there.

It’s all nice and dandy to believe that everyone has always named parameters in a sensible and descriptive manner and that everyone uses strict type checking and strict_mode already. It’s a wonderful illusion to believe that everyone manages their dependencies with Composer using strict version constraints. The reality is very different and I live in that reality.

So I join Derick in asking: please, please have some more emphpathy.

Let’s try and be kinder to each other. Take a moment to gauge the workload a proposed change will cause for maintainers of open source projects. Not just for your own small pet-project, but for the big, huge projects which run the internet.

Consider whether it is realistic to expect them to push EVERYTHING ELSE to the side and get every contributor they can scramble together to focus 100% on fixing the fall-out caused by your change, knowing that even then, chances are they would still not be ready in time for the release of PHP 8.0. If that’s the case, then maybe, just maybe, your change should be an option and not be forced upon the world.

I wish you all time to reflect and hope that 2021 will bring some light to the world again.

An Ode to PHP’s Unsung Heros

I love the PHP community and I love all the people who, each in their own way, help bring people together, help us to connect, to learn from each other, to get better. Whether it is Cal, Emir, Mark, Michelangelo, Michelle, Stefan, Theo or any of the countless other people out there. I love how we all come together to make PHP and the community around it better.

With so many good people out there, I have to admit, it scares me that some of the most used projects in the PHP sphere are largely maintained by one person.

When I say “PHPUnit“, you say Sebastian Bergmann, when I say “Xdebug“, you say Derick Rethans, when I say “PHP_CodeSniffer“, you say Greg Sherwood, PHPDocumentor, Mike van Riel, Composer, Jordi Boggiano etc.

Of course, they do have help, sometimes even co-maintainers, but when I look at the contributors pages of each of these projects, I truly do get scared.

These projects often have hundreds of contributors with maybe one or two commits and then the main maintainer with the bulk of the commits and the bulk of lines of code contributions. Often the distance between the main maintainer and the next co-maintainer or contributor is a factor 10 or even 100.

Of course, looking at the contributors page is arbitrary. At the end of the day, the quality of contributions is/should be more important than the quantity and the contributors page also doesn’t show who has been most active recently, but it still gives quite a good indication of how many, or rather, how few, people actively contribute to a project.

It is easy to speculate why these projects have few active contributors: they “just” work. But for these projects to “just work”, a lot of work has been done and still continues to be done. And is mostly done quietly by these awesome maintainers, without complaint and often without getting nearly enough credits or praise to keep them motivated.

These are semi-“invisible” projects. You set them up once & they do their job, helping you do your job, every single day.

Unless you have an error or the build is breaking, you don’t even notice they are there, other than in the peace of mind it gives you knowing that these tools are running the background.

Each of these projects is a de-facto industry standard. There are alternatives out there, but generally speaking, these projects have hardly any direct competition in their field as they are good, have earned a reputation, and – as mentioned before – “just work”.

And while it’s bad enough that it’s a relatively thankless job for the maintainers, what scares me is this: what will happen if one of them steps down ? Or changes job and won’t get much time from their new employer to continue working on the project ? Or just loses interest ? Or – while we don’t like to think about this -: what will happen if one of them would die ?

We sometimes talk about the “bus factor“, i.e. if a bus crashes with a certain group of people what would the impact be ? Can a project survive even after the bus crash ? Each of these projects has a bus factor of one. If one particular person would die or withdraw from the project, the project would effectively be dead.

Our dependency as an industry on a few key projects with only one primary maintainer is enormous. Can we honestly afford to allow this situation to continue ?

Of course, the old adage “when one door closes, a window opens” holds true. If one of these projects would “die”, other projects would rise up in their wake. And other projects do rise up now and again anyway, completely naturally, like how Composer effectively replaced PEAR. The difference between this happening naturally and happening suddenly and unexpectedly, is the havoc which we’ll see in the interim before the next project has gained enough momentum to be said to be the rightful successor.

We’ve all seen the drama that happened when left-pad, one of the NPM-hosted projects which was a dependency for thousands of projects, got withdrawn.

Essentially, if there is only one person with admin rights on the repository, there is only one person with the keys to the castle.

Yes, someone could fork the project, but the project “move” can not be registered in Packagist, dependent projects can not easily be informed about the new “official” fork and quite soon there will be a hundred unofficial forks, each slightly differently and nobody knows which one to use anymore.

Still, unless someone actively withdraws a project and/or disables the account under which the project repo is hosted, a project should still be around for a while. But it will slowly disintegrate. A new PHP version will come out and suddenly something doesn’t work anymore, a new PHP feature is not supported while it should be, etc.

And just imagine the sheer amount of effort which would be needed to re-code all unit tests to use an alternative to PHPUnit…. yes, take a moment to let that sink in.

We are talking centuries of dev-hours. CENTURIES.

No matter how awesome we may be as a community, we also have a responsibility.

A responsibility to our fellow developers as well as a responsibility to the projects we maintain. And being dependent on so many one-maintainer projects is irresponsible. So let’s show the world how awesome we are and give these maintainers the support they deserve.

We all use these projects, we all use PHP. All these projects – with the exception of Xdebug – are written in PHP.

My challenge to you for the new year is to have a look at the (dev-)dependencies you use in nearly all projects, have a look at their repositories, have a look at their open issues, open PRs and to ask yourself what you can do to mitigate the risks of using these one-maintainer projects.

It may not be “sexy” to contribute to these kind of projects. They are not the latest “hip” thing, nor the newest bleeding edge technology, but that shouldn’t matter.

By contributing to any of these projects – or any of the other typical dependencies I haven’t mentioned -, you end up making the whole of the PHP sphere better as every other project using these projects will also get the benefit of your work.

And risk mitigation can take many forms, whether it is:

  • validating open issues (arbitrage)
  • reviewing & testing open PRs
  • writing, improving or translating documentation
  • claiming an issue and creating a PR to fix it
  • or donating to the project

And, please, consider the same if you are the sole or main maintainer of a package which could be classed as risky from this point of view. Consider what you can do to on-board more contributors.

Consider adding “good-first-bug” or “up-for-grabs” tags and using them actively to signal easy-pick issues for new contributors to get started. Make sure there is a useful Contributing.md file. Be welcoming to new contributors, even if their ideas do not (currently) fit your project and be willing to spend time on reviewing pull requests, even when it would be quicker to fix something yourself.

Now, I realize on-boarding new contributors onto a project is not a small thing. For some maintainers, it may take a while before they are mentally ready to share their baby with co-maintainers. For others, it will be more of a challenge on how to educate new co-maintainers on the philosophy behind the project and to stay true to it.

So let’s be patient and kind towards each other while we each figure out our new roles.

Of course, the projects I have mentioned here are just examples. There are plenty of other projects out there of which the same can be said. Be it certain Symfony components, Flysystem, Guzzle, Twig or Swiftmailer.

I challenge you to look at the contributor stability of your dependencies and think about what you can contribute to improve the long-term sustainability of these projects.

Let’s show them as much love as we show our beloved elephpants.

Let’s all, in our own way, try to show how great a community we are, by behaving like one and supporting the people and projects who need and deserve it.

I salute you and wish you all a happy & productive 2018.

Juliette

 

Links:

Don’t know where to start contributing ?

 

With gracious thanks to Norbert de Langen, Andreas Heigl and Michelangelo van Dam for reviewing the article before publication.