First of all, thanks Alessandro for bringing this up.
I have given a lot of thought on this topic, which, as most of you will know, has been recurring pretty much since PHP7 was released.
I never actually sat down and write these thoughts of mine, though, so I better do it now, finally.
While I agree that something *must* be done to ease the process of keeping PSRs up to date, I think the suggested approach is too simplistic and would introduce more problems than it solves.
There are multiple facets to this issue, here are some we need to solve to fully address it:
- The common Git workflow of opening a PR doesn't really fit a project that is meant be immutable once released, bar minor erratas that can't effectively harm users.
- The specification documents are separate from the actual code, if any; I think this is exactly why simply opening a PR, voting it, and merging may seem easy, but it's actually not. If we update the interfaces and release a new version of the Composer package, we also need to update the specs, and vice-versa. While updating the package is a simple as bumping a tag, updating the specification documents has no actual release process instead, because a new PSR is supposed to be created instead. We can't simply make the old specification documents disappear by merging a PR. Also, superseded major versions should still be accessible for future reference.
- All specs are all in the same repository, so their lifecycle cannot be managed independently.
- The namespace of the code we produce (Psr\Foo\Bar and Fig\Bar\Baz) is fragmented, ambiguous and wouldn't accommodate multiple major version of the same PSR living in the same codebase. This makes effectively impossible to provide soft migration paths from one version to another, which would probably end up in a Python 3 scenario, where not enough people will migrate to the new ones to simply declare the old one DEAD, thus incurring in the risk of very long and painful transition timeframes where multiple incompatible standards are used in the wild.
Now, at the cost of sounding preposterous, I will propose the following:
I think we need to completely overhaul our naming conventions, the PSR release process (just the release, not the production workflow!), and how we use VCS to manage the documents and sources we produce. This involves a lot of changes and the willingness to turn page quite drastically.
Here comes some craziness, but bear with me.
We could overhaul the naming scheme by introducing the concept of Revisions:
Standard name: PSR-$n - $topic [ - Revision $major.$minor.$patch]
Package name: fig/psr-$n-$topic[-rev-$major]:$major.$minor.$path
Namespace: Fig\Psr$n[\Rev$major]\
Example 1:
PSR-7 - HTTP Messages - Revision 1.0.0
Package name: fig/psr-7-http-messages:1.0.0
Namespace: Fig\Psr7\
Example 2:
PSR-7 -
HTTP Messages - Revision 2.0.0
Package name: fig/psr-7-http-messages-rev-2:2.0.0
Namespace: Fig\Psr7\Rev2\
Example 3:
PSR-7 - HTTP Messages - Revision 2.0.1
Package name: fig/psr-7-http-messages-rev-2:2.0.1
Namespace: Fig\Psr7\Rev2\
Note that:
- The Revision number matches the Semver package version, but it's doesn't map exactly to the same concept. The most relevant part is obviously the major number because minor and patch should not break compatibility, thus releasing a new Revision will not be required.
- If the Revision is omitted, it means it's 1.x, thus referring just to "PSR-7" implies version 1.x.
- The $n is still determined at PSR entrance, but it is *never* changed unless the PSR purpose changes substantially, enough to grant a scenario where two standards may coexist and both be current (e.g. "PSR-6 - Caching Interface" and "PSR-16 - Simple Cache").
- Deprecated minor and patch versions are not accessible other than via Composer.
- The Composer package should contain both the specification documents AND the sources, if any.
- For simplicity, $topic refers to both a text representation and a slugified one.
In hindsight, I think the IETF naming convention has *heavy* negative trade-offs. Some will argue that it's a good naming scheme, but I think we can agree that trying to remember what RFC is about what is a waste of neurons. We have had it easy because we only had to deprecate one standard, PSR-2, but, believe it or not, I have seen people still getting confused about this, because someone would refer to a spec as "the autoloader PSR", to only later mention the actual version, leading to undesirable "gotchas".
Considering that if we had to keep the pace with the engine development cycle, in the worst case we would need to release a new version every two years, simply using natural numbers to identify standards would quickly become a mess. Also, we can't make it match with Semver major versions, and this should be enough to prove it ineffective as a versioning scheme.
The main reason for introducing a separate concept from the Composer version is because Composer doesn't allow for multiple versions of the same package to coexist.
That said, using the major Semver number in the namespace would allow very straight forward migration paths, avoiding the Python scenario: we could produce backwards compatible adapters for newer Revisions, that could coexist with previous ones, actively encouraging adoption of the new and deprecation of the old.
Separating it from the PSR number allows unambiguous and clear naming, ensuring that a specification will successfully endure the test of time without causing headaches, contrary to things like RFC2616.
Omitting the Revision for V1 allows for a cleaner transition from the current status quo, and avoids unnecessary verbosity for standards that would hardly be ever updated because of inherent characteristics.
Bundling documents *with* the sources I think just makes sense, I can't imagine why they should continue to be separated. If someone wants to implement a spec, they will just have to require the package and open the included markdown in the vendor dir, which they will be *sure* it matches the interfaces they are trying to implement.
On a side note, I would also take the chance to rename the topic of some of the current PSRs, because sometimes we have a pleonastic "Interfaces" in the name that just drives me crazy, but hey, that's just me.
So how do we release this stuff?
Simple enough: different repos for each PSR, for each Revision. A new Revision is a fork of the previous one. If a PR is opened to a current PSR but it requires a new Revision, it should be straightforward to retarget it to a new fork, once the due voting process is done. The WG members will be maintainers of all the repos of a PSR. This should also make it *much easier* the governance of the access and the contribution process, which I reckon it hasn't always been exactly seamless with the current flow (e.g. sometimes PRs have been hanging for a lot of time because the Editor or anyone in the WG was not notified, or they needed approval from the secretaries, etc).
We could also talk about a Revision Approval voting protocol, which could maybe be a shorter version of the corresponding PSR Readiness and Acceptance, or maybe just use those instead, but I'll leave this particular issue open because I think is not that crucial right now.
This is all I got for now, I realise that there may be unclear details, but at least we started a discussion on this problem.
I know for a fact that some people won't approve any of this, so I'll now let you throw figurative milk shakes at me.
Cheers,
Stefano