Wow, the author is really over-the-top in his passion for PHP, and I say that as someone who has fond childhood memories of bodging together stuff with the language. (Security? What’s that?) Their post gets really oblivious toward the end:
Last but not least, other languages lack advanced technology.
“Advanced technology” includes abstract syntax trees, refactoring tools, and linters.
EDIT: They’re the author of said refactoring tool, so they might be the teensiest bit biased.
All of the technical reasons cited here (AST, parser, linter, and other language tools written in the same language) can be said about Python, JavaScript, Rust and C++.
Java is still the de facto king of backwards compatibility that actually has the years to show for it. Just based on the title, that ‘title’ would go to Java in my opinion.
I would argue that it is at most as bad as with any other language, but arguably better as the ecosystem is significantly more stable than any other. (What is in the same ballpark in size are JS, and Python, neither is famous for their stability).
But of course third-party libs may decide to break their public APIs at any point, that’s irrelevant to language choice, besides “culture” — and Java’s is definitely not “going fast and breaking stuff”.
Sadly, starting with Java 9, while the core language is backwards compatible, the library situation is a nightmare. And when you’re doing an upgrade, you don’t care if it’s the core language or the library that’s changed, either way, it’s work to upgrade and ensure you don’t have regressions.
Lots of things have changed the package that they live in. In principle, this sounds like it’s not a very difficult change to accomodate, just find and replace, but it wreaks havoc when you have libraries that have to run on multiple JVM versions.
If you’re unlucky enough to be using Spring, it’s even worse. That framework has no concept of backwards compatibility, and is like a virus that spreads throughout your entire codebase.
I can’t share your experience at all. Even large jumps pre-8 to post-11 (though after like 11 they are basically trivial) are reasonably easy, and the few libraries that made use of JVM internals that got increasingly locked down (to prevent further breaking changes in the future) have largely been updated to a post-module version, so very often it’s just bumping the version numbers.
I don’t understand some of what you’re describing.
And when you’re doing an upgrade, you don’t care if it’s the core language or the library that’s changed, either way, it’s work to upgrade and ensure you don’t have regressions.
Are you saying that other languages can somehow prevent the problem of third-party libraries breaking backwards compatibility? Because, if you aren’t saying that, then the core language being stable is going to make the situation objectively better to deal with than if you have to worry about breaking changes in libraries and in the core language…
Lots of things have changed the package that they live in. In principle, this sounds like it’s not a very difficult change to accomodate, just find and replace, but it wreaks havoc when you have libraries that have to run on multiple JVM versions.
Yes, it can be tricky to write code to target multiple versions of Java at the same time, but in my experience, it’s about 100 times less tricky to do this with Java than almost any other language. JavaScript might be the only one that’s even better about running old code on newer runtimes without much problem. Are there others you consider better than Java at this? Specifically for running the SAME code on multiple versions of the language? I remember back in the day when I worked on a lot of C++, it was a nightmare to figure out what features I could use from C++11 to allow the project to build on various versions of GCC that shipped with different Linux distros (Ugh, RedHat’s ancient versions!).
Are you saying that other languages can somehow prevent the problem of third-party libraries breaking backwards compatibility? Because, if you aren’t saying that, then the core language being stable is going to make the situation objectively better to deal with than if you have to worry about breaking changes in libraries and in the core language…
I think that depending on the community, some languages have less BC issues because of libraries than others. Case in point for me was Clojure: both the core language and community have a stance of avoiding breaking compatibility, even if the language itself doesn’t offer any special mechanism for that. Quite the opposite actually, since the language is really dynamic and you can even access private functions without much difficulty.
Are you saying that other languages can somehow prevent the problem of third-party libraries breaking backwards compatibility?
Of course they can’t, and that’s not my point.
My point is that communities develop norms, and those norms include more or less careful treatment of backwards compatibility in libraries. My sense is that Haskell and JavaScript are probably the worst. Java is actually mixed, as there are a lot of libraries that do great work. Some even have a single version that runs on Java 5 through Java 21. But at my day job, we’re using Spring, and the situation is bad.
Though with regard to languages, I will say dynamic class-loading can make the situation worse. I’ve dealt with issues where the order of requests to a web server determined which version of a service provider was loaded. So 9 times out of 10, the code ran on the newer version of Java, but failed 1 time in 10.
Because, if you aren’t saying that, then the core language being stable is going to make the situation objectively better to deal with than if you have to worry about breaking changes in libraries and in the core language…
It sounds like your argument is “having two problems is worse than having one”. But two little problems are better than one big problem.
I greatly appreciate the backwards compatibility of the Java language. But I would be happier with a slightly less backwards compatible core language, if I could trade it for an ecosystem that’s much better at backwards compatibility.
My point is that communities develop norms, and those norms include more or less careful treatment of backwards compatibility in libraries. My sense is that Haskell and JavaScript are probably the worst. Java is actually mixed, as there are a lot of libraries that do great work. Some even have a single version that runs on Java 5 through Java 21. But at my day job, we’re using Spring, and the situation is bad.
Right. I understand and agree about ecosystem “culture”. But, at the end of the day, someone said Java was good with backwards compatibility because it makes it easy to write code that will continue to work “forever”.
I guess maybe your point is that the language prioritizing backwards compatibility is only necessary, but not sufficient, for developers actually getting to experience the benefit of the backwards compatibility. Would you say that’s a decent interpretation/restating? I do agree with that. And if the language itself doesn’t care about backwards compatibility, then it’s impossible for the ecosystem to have stability.
Though with regard to languages, I will say dynamic class-loading can make the situation worse. I’ve dealt with issues where the order of requests to a web server determined which version of a service provider was loaded. So 9 times out of 10, the code ran on the newer version of Java, but failed 1 time in 10.
Definitely true! Luckily, I only remember one time where I had a nightmare of a time figuring out some class or service loading bug.
It sounds like your argument is “having two problems is worse than having one”. But two little problems are better than one big problem.
Yeah, that’s exactly what I was saying. But there’s no reason to think the “one problem” (community doesn’t value backwards compat.) would be bigger or smaller for either case. So, it’s like comparing x to x + 1.
I greatly appreciate the backwards compatibility of the Java language. But I would be happier with a slightly less backwards compatible core language, if I could trade it for an ecosystem that’s much better at backwards compatibility.
I really feel like this is mostly just Spring. I hate Spring, too, so I have been fortunate enough to not have to use it in several years now. But, as for the Java libraries I am using, I honestly couldn’t tell you about their JVM version compatibility over time. But, just judging by API stability, it seems that most “general purpose” or “utility” style libraries stay pretty backward compatible (thinking of the Apache and Guava libs, etc). It’s mostly the frameworky ones (like Spring, Spark, etc) that like to rewrite big chunks of their APIs all the time.
Can you give an example of what you’re referring to?
I’m semi-active on the PHP internals mailing list (i.e. the list where development of php itself is discussed) and BC breaks are a near constant discussion point with any proposed change, so I’m kind of curious what breaking change you’re referring to here?
Well, since I’m not the person you originally asked, I obviously can’t speculate on which breaking changes they’ve actually bumped into. But, I’ve works on several long-lived PHP projects going all the way back to version 5.3 and all the way up to 8.1 or 8.2 (I don’t quite remember which), and I’ve definitely had to fix broken code from minor version bumps. Luckily, we do have those migration lists, so I learned pretty early on to read them carefully and grep through any code base to fix things on the list before even running unit tests.
But, I’m not sure what the point is. The person said that PHP introduces breaking changes in minor version bumps, and that it frustrates them. Maybe they’re misguided for being frustrated by that, but it’s objectively true.
Personally, I’m perfectly fine with breaking bug fixes in minor versions. It’s not like you’re going to accidentally or unknowingly version bump the programming language of your projects. On the other hand, many of these changes are NOT bug fixes, but just general “improvements”, like the range() changes or the “static properties in traits” change in the 8.3 list. I can see how this would be frustrating for someone who wants the bug fix changes, but doesn’t want to pay the extra “tax” of dealing with the non-essential breaking changes.
But, again, I personally don’t care. I treat PHP minor versions as a big deal. PHP 8.2 is not the same language as PHP 8.1, which is fine. But, if you care about backwards compatibility and painless upgrades, Java is pretty much the king.
It’s mostly the ripple effects into libraries and “big” frameworks. For instance, I remember a few years ago a client was on still on PHP 5.3 (I think) and his hosting provider was about to shut down this version, so he had to get his site working on newer versions. This site was built on an in-house CMS of questionable code quality, using CakePHP.
The problem I ran into was that I had to step-by-step upgrade CakePHP through some major versions because the older versions wouldn’t run in the newer PHP due to BC breakage. Eventually, I completely hit a wall when I got to one major version where I discovered in the changelog that they completely rewrote their ORM. Because of the shitty code quality of the CMS (with no tests), I had to admit defeat. The client ended up having to commission the building of a new site.
Java and Go are really great in this regard.
Every other language, including Python (which makes breaking changes from 3.12.3 -> 3.12.4!) is horrible on that front.
For me the biggest reason for betting on an “old” established technology like PHP for long-term business is the Lindy effect. Old technologies or ideas that are still relevant today are more likely to still be relevant in, say, 20 years, than recently developed things.
PHP got released 29 years ago, the same year as Ruby and JavaSciprt (a fact that never fails to blow my mind). But it seems unfair to compare PHP to the other two, as PHP was designed to build websites on its own. Ruby on Rails was released 20 years, and Node.js 15 years ago.
From a business perspective, betting on Ruby on Rails or Node.js —or, better yet, vanilla JS— seems almost as safe as betting on PHP TBH. Just try to avoid tying your business too tightly to frameworks or libraries that are still too young, especially if they are designed to make it hard to be replaced —yes, VC-funded JS frameworks like Next.js, i’m talking about you.
Huh, didn’t know those languages were all the same age! My other favorite “surprisingly old” language is Python, which dates back to 1991. (Though I’m sure it’s changed plenty since then!)
I’m curious about the first versions of all those languages.
The unique thing about JavaScript is that it’s changed substantially over its lifetime without breaking backwards compatibility. For JS, the first release didn’t have try…catch, and only much latter did it get classes, a reasonable Map<K, V> type, and it feels like we’re still waiting on a reasonable Iterable/Interator to land in the standard library.
On the other hand, I don’t think there’s another language out there with better support for using today’s code with yesterday’s runtime. I’m not aware of any tooling to run Python 3.11 on Python 2.3, but you can sure find plenty of production strength tools to run JavaScript 2024 all the way back on Internet Explorer 5 (ES3), although over the past few years the need for that is drying up.
As a person who had endless thousands of hours of fun and joy building stuff with PHP back in the day, it saddens me a little bit to read stuff like this.
The reasons PHP was awesome are almost the opposite of what the author goes on about. Please stop this framework non sense. All languages mentioned have orders of magnitude more merits than the frameworks listed in the article.
I don’t see the point trying to make a value accessment by evaluating things like: which year was it released or which programming language was it written in. Surely, it depends on how it has been maintained since launch and how it written.
Laravel and modern symphony are the anthetisis of what PHP used to be. By the time you’re ready with their boilerplate code, you could have written an old school PHP script and copy it to your PHP enabled web server.
In 2016, a company contacted me to help upgrade their internal CRM. They used Angular 1 and wanted to go to Angular 2. It would require a complete rewrite.
Another path was to migrate to React, the “Facebook framework”.
In 2018, Vue became the new competition. Another rewrite would be required to attract more developers.
Next, Alpine… there are dozens of new tutorials on YouTube on the brand new JS framework. They have 90 % feature overlap, just slightly different syntax sugar.
2016 sounds recent to middle aged people like me, but it was 8 years ago. Contrary to this narrative, React is over ten years old (only two years younger than Laravel, which the author praises), and shows no signs of being displaced. It has less buzz than Vue or Alpine, but more users, and that doesn’t seem likely to change (my company started using React in 2016, and I don’t think anyone has seriously suggested migrating away from it).
I do get the impression React has more internal breaking changes than would be ideal, but you’re not going to be forced to abandon it.
However, there is a tool you can run to convert your PHP 5.2 project to PHP 8.4. In the case of vanilla PHP, this can be done in a single day, fully automated.
This is not even much of a problem doing it by hand. The real issue is upgrading frameworks, and it’s the frameworks that this post is praising, not vanilla PHP. Often, frameworks come with some form of upgrade tool, but those never work 100% in my experience.
Wow, the author is really over-the-top in his passion for PHP, and I say that as someone who has fond childhood memories of bodging together stuff with the language. (Security? What’s that?) Their post gets really oblivious toward the end:
“Advanced technology” includes abstract syntax trees, refactoring tools, and linters.
EDIT: They’re the author of said refactoring tool, so they might be the teensiest bit biased.
All of the technical reasons cited here (AST, parser, linter, and other language tools written in the same language) can be said about Python, JavaScript, Rust and C++.
PHP makes breaking changes between minor versions (when activating all errors), which is certainly great to keep developers working, but a major PITA.
After 10 years of PHP, I value the Go 1.0 compatibility promise very much…
Java is still the de facto king of backwards compatibility that actually has the years to show for it. Just based on the title, that ‘title’ would go to Java in my opinion.
Until you try out the nightmare that is upgrading the maven, ant or gradle dependencies of an old project, then sure.
I would argue that it is at most as bad as with any other language, but arguably better as the ecosystem is significantly more stable than any other. (What is in the same ballpark in size are JS, and Python, neither is famous for their stability).
But of course third-party libs may decide to break their public APIs at any point, that’s irrelevant to language choice, besides “culture” — and Java’s is definitely not “going fast and breaking stuff”.
Sadly, starting with Java 9, while the core language is backwards compatible, the library situation is a nightmare. And when you’re doing an upgrade, you don’t care if it’s the core language or the library that’s changed, either way, it’s work to upgrade and ensure you don’t have regressions.
Lots of things have changed the package that they live in. In principle, this sounds like it’s not a very difficult change to accomodate, just find and replace, but it wreaks havoc when you have libraries that have to run on multiple JVM versions.
If you’re unlucky enough to be using Spring, it’s even worse. That framework has no concept of backwards compatibility, and is like a virus that spreads throughout your entire codebase.
I can’t share your experience at all. Even large jumps pre-8 to post-11 (though after like 11 they are basically trivial) are reasonably easy, and the few libraries that made use of JVM internals that got increasingly locked down (to prevent further breaking changes in the future) have largely been updated to a post-module version, so very often it’s just bumping the version numbers.
I don’t understand some of what you’re describing.
Are you saying that other languages can somehow prevent the problem of third-party libraries breaking backwards compatibility? Because, if you aren’t saying that, then the core language being stable is going to make the situation objectively better to deal with than if you have to worry about breaking changes in libraries and in the core language…
Yes, it can be tricky to write code to target multiple versions of Java at the same time, but in my experience, it’s about 100 times less tricky to do this with Java than almost any other language. JavaScript might be the only one that’s even better about running old code on newer runtimes without much problem. Are there others you consider better than Java at this? Specifically for running the SAME code on multiple versions of the language? I remember back in the day when I worked on a lot of C++, it was a nightmare to figure out what features I could use from C++11 to allow the project to build on various versions of GCC that shipped with different Linux distros (Ugh, RedHat’s ancient versions!).
I think that depending on the community, some languages have less BC issues because of libraries than others. Case in point for me was Clojure: both the core language and community have a stance of avoiding breaking compatibility, even if the language itself doesn’t offer any special mechanism for that. Quite the opposite actually, since the language is really dynamic and you can even access private functions without much difficulty.
Of course they can’t, and that’s not my point.
My point is that communities develop norms, and those norms include more or less careful treatment of backwards compatibility in libraries. My sense is that Haskell and JavaScript are probably the worst. Java is actually mixed, as there are a lot of libraries that do great work. Some even have a single version that runs on Java 5 through Java 21. But at my day job, we’re using Spring, and the situation is bad.
Though with regard to languages, I will say dynamic class-loading can make the situation worse. I’ve dealt with issues where the order of requests to a web server determined which version of a service provider was loaded. So 9 times out of 10, the code ran on the newer version of Java, but failed 1 time in 10.
It sounds like your argument is “having two problems is worse than having one”. But two little problems are better than one big problem.
I greatly appreciate the backwards compatibility of the Java language. But I would be happier with a slightly less backwards compatible core language, if I could trade it for an ecosystem that’s much better at backwards compatibility.
Right. I understand and agree about ecosystem “culture”. But, at the end of the day, someone said Java was good with backwards compatibility because it makes it easy to write code that will continue to work “forever”.
I guess maybe your point is that the language prioritizing backwards compatibility is only necessary, but not sufficient, for developers actually getting to experience the benefit of the backwards compatibility. Would you say that’s a decent interpretation/restating? I do agree with that. And if the language itself doesn’t care about backwards compatibility, then it’s impossible for the ecosystem to have stability.
Definitely true! Luckily, I only remember one time where I had a nightmare of a time figuring out some class or service loading bug.
Yeah, that’s exactly what I was saying. But there’s no reason to think the “one problem” (community doesn’t value backwards compat.) would be bigger or smaller for either case. So, it’s like comparing x to x + 1.
I really feel like this is mostly just Spring. I hate Spring, too, so I have been fortunate enough to not have to use it in several years now. But, as for the Java libraries I am using, I honestly couldn’t tell you about their JVM version compatibility over time. But, just judging by API stability, it seems that most “general purpose” or “utility” style libraries stay pretty backward compatible (thinking of the Apache and Guava libs, etc). It’s mostly the frameworky ones (like Spring, Spark, etc) that like to rewrite big chunks of their APIs all the time.
Happy to agree with your last paragraph. It’s very close to what I think.
Hey, have you heard of Perl?
[Comment removed by author]
Can you give an example of what you’re referring to?
I’m semi-active on the PHP internals mailing list (i.e. the list where development of php itself is discussed) and BC breaks are a near constant discussion point with any proposed change, so I’m kind of curious what breaking change you’re referring to here?
PHP maintains change logs for every minor version. Here’s the most recent list for migrating from version 8.2 to 8.3 (a minor version bump): https://www.php.net/manual/en/migration83.incompatible.php
Yes, I’m aware of the migration lists. I was asking to try and get an example of a real world issue that’s likely to affect users.
In that migration list specifically, the vast majority of the “breaks” are fixing inconsistencies.
Yes they are technically a BC break. But part of the discussion on each RFC for PHP is the expected real-world impact if there is a BC break.
Well, since I’m not the person you originally asked, I obviously can’t speculate on which breaking changes they’ve actually bumped into. But, I’ve works on several long-lived PHP projects going all the way back to version 5.3 and all the way up to 8.1 or 8.2 (I don’t quite remember which), and I’ve definitely had to fix broken code from minor version bumps. Luckily, we do have those migration lists, so I learned pretty early on to read them carefully and grep through any code base to fix things on the list before even running unit tests.
But, I’m not sure what the point is. The person said that PHP introduces breaking changes in minor version bumps, and that it frustrates them. Maybe they’re misguided for being frustrated by that, but it’s objectively true.
Personally, I’m perfectly fine with breaking bug fixes in minor versions. It’s not like you’re going to accidentally or unknowingly version bump the programming language of your projects. On the other hand, many of these changes are NOT bug fixes, but just general “improvements”, like the
range()changes or the “static properties in traits” change in the 8.3 list. I can see how this would be frustrating for someone who wants the bug fix changes, but doesn’t want to pay the extra “tax” of dealing with the non-essential breaking changes.But, again, I personally don’t care. I treat PHP minor versions as a big deal. PHP 8.2 is not the same language as PHP 8.1, which is fine. But, if you care about backwards compatibility and painless upgrades, Java is pretty much the king.
It’s mostly the ripple effects into libraries and “big” frameworks. For instance, I remember a few years ago a client was on still on PHP 5.3 (I think) and his hosting provider was about to shut down this version, so he had to get his site working on newer versions. This site was built on an in-house CMS of questionable code quality, using CakePHP.
The problem I ran into was that I had to step-by-step upgrade CakePHP through some major versions because the older versions wouldn’t run in the newer PHP due to BC breakage. Eventually, I completely hit a wall when I got to one major version where I discovered in the changelog that they completely rewrote their ORM. Because of the shitty code quality of the CMS (with no tests), I had to admit defeat. The client ended up having to commission the building of a new site.
Java and Go are really great in this regard. Every other language, including Python (which makes breaking changes from 3.12.3 -> 3.12.4!) is horrible on that front.
For me the biggest reason for betting on an “old” established technology like PHP for long-term business is the Lindy effect. Old technologies or ideas that are still relevant today are more likely to still be relevant in, say, 20 years, than recently developed things.
PHP got released 29 years ago, the same year as Ruby and JavaSciprt (a fact that never fails to blow my mind). But it seems unfair to compare PHP to the other two, as PHP was designed to build websites on its own. Ruby on Rails was released 20 years, and Node.js 15 years ago.
From a business perspective, betting on Ruby on Rails or Node.js —or, better yet, vanilla JS— seems almost as safe as betting on PHP TBH. Just try to avoid tying your business too tightly to frameworks or libraries that are still too young, especially if they are designed to make it hard to be replaced —yes, VC-funded JS frameworks like Next.js, i’m talking about you.
Huh, didn’t know those languages were all the same age! My other favorite “surprisingly old” language is Python, which dates back to 1991. (Though I’m sure it’s changed plenty since then!)
I’m curious about the first versions of all those languages.
The unique thing about JavaScript is that it’s changed substantially over its lifetime without breaking backwards compatibility. For JS, the first release didn’t have try…catch, and only much latter did it get classes, a reasonable Map<K, V> type, and it feels like we’re still waiting on a reasonable Iterable/Interator to land in the standard library.
On the other hand, I don’t think there’s another language out there with better support for using today’s code with yesterday’s runtime. I’m not aware of any tooling to run Python 3.11 on Python 2.3, but you can sure find plenty of production strength tools to run JavaScript 2024 all the way back on Internet Explorer 5 (ES3), although over the past few years the need for that is drying up.
JS has Symbol.iterator() and Symbol.asyncIterator()?
As a person who had endless thousands of hours of fun and joy building stuff with PHP back in the day, it saddens me a little bit to read stuff like this.
The reasons PHP was awesome are almost the opposite of what the author goes on about. Please stop this framework non sense. All languages mentioned have orders of magnitude more merits than the frameworks listed in the article.
I don’t see the point trying to make a value accessment by evaluating things like: which year was it released or which programming language was it written in. Surely, it depends on how it has been maintained since launch and how it written.
Laravel and modern symphony are the anthetisis of what PHP used to be. By the time you’re ready with their boilerplate code, you could have written an old school PHP script and copy it to your PHP enabled web server.
2016 sounds recent to middle aged people like me, but it was 8 years ago. Contrary to this narrative, React is over ten years old (only two years younger than Laravel, which the author praises), and shows no signs of being displaced. It has less buzz than Vue or Alpine, but more users, and that doesn’t seem likely to change (my company started using React in 2016, and I don’t think anyone has seriously suggested migrating away from it).
I do get the impression React has more internal breaking changes than would be ideal, but you’re not going to be forced to abandon it.
The sad part of this post is that the author is probably writing in good faith, but really is ignorant of the state of affairs outside PHP.
This is not even much of a problem doing it by hand. The real issue is upgrading frameworks, and it’s the frameworks that this post is praising, not vanilla PHP. Often, frameworks come with some form of upgrade tool, but those never work 100% in my experience.