3 ms·
The problem with rolling releases is that there’s no way to say “I’m using the API as it was at version 3”. The last few years I’ve been increasingly thinking a
by josephg 5y ago
The problem with rolling releases is that there’s no way to say “I’m using the API as it was at version 3”. The last few years I’ve been increasingly thinking about software versions where the major version is part of the dependency name. So product Foo@1.2.3 is really “Foo1” at version 2.3. Foo1 is what you’re depending on, and so long as the semver guarantee holds, you should be able to incorporate rolling releases of Foo1’s versions. But because Foo2 (Foo@2.0.0) has a different API, it’s a different dependency and should be treated as if it were separate object in the dependency tree. And generally Foo1 and Foo2 should be able to sit, live and work side-by-side.
The fact that Foo1 and Foo2 are both called "Foo" is an artefact of how humans write software, but its meaningless to the computer. Foo2 usually has all the features of Foo1, but because the API is programmatically incompatible, when it comes to the dependency tree, they should be totally separate items.
You see forms of this all over the place. Eg, HTTP APIs are usually /api/v1/ not /api/v1.2/. Debian's apt repository has packages for 'llvm-10', 'llvm-11', 'llvm-12', and so on. I used to think this was silly; but now I think it might be the only way to do that in a coherent way.
- hadlock 5y agoThis is just called semver or semantic versioning. https://semver.org https://semver.org
- josephg 5y agoThe semver spec implies this, but doesn't say it outright. And that leads to lots of overcomplicated tooling! I'm going to try being even more clear: "Package Foo v1.2.3" should usually be spelled "Package Foo1, v2.3" For example, the migration from react 17.x.x to react 18.x.x is actually a change from depending on package react17 to depending on react18. React17 and react18 are two different packages which have been designed by the same team, and happen to have similar APIs in order to make migration easier. If I designed npm today I'd make "react16", "react17" and "react18" all be essentially different packages (under a namespace). They should probably only share their lists of authorized authors. You can see this confusion all over the place. For example, when setting up peerDependencies in a nodejs project, there are suggestions[1] to use a version like `"chai": ">= 1.5.2 < 2"`. This is because chai v1 and chai v2 are essentially different packages. You want to say "chai v1 should be a peer dependency". But its unintentionally awkward to say that clearly. And with the current nomenclature, there's no way to express a dependency on both chai1 and chai2 - despite them being different, incompatible packages. Even though nodejs is obsessed about semver, it still makes a mess of things by pretending as if major versions and minor versions are similar. They are not. [1] Last couple paragraphs of https://nodejs.org/es/blog/npm/peer-dependencies/ https://nodejs.org/es/blog/npm/peer-dependencies/
- jacobmischka 5y agoWeird that nodejs.org doesn't say so, but that's usually written `"^1.5.2"` and is by far the most common way dependencies are specified in my experience. Cargo even makes the ^ implicit, and you can just write "1.5.2".
- nyanpasu64 5y agoCargo and Poetry treat different major versions of software as effectively different packages by default. However I've seen pushback against upper version bounds (which putting different major versions under different names is an extension of): https://iscinumpy.dev/post/bound-version-constraints/ https://iscinumpy.dev/post/bound-version-constraints/. I'm not sure how to feel myself.
- josephg 5y agoInteresting. But python's package system makes this actively hard to do. From that article: > For example, let’s say you support click^7. Click 8 comes out, and someone writes a library requiring click^8. Now your library can’t be installed at the same time as that other library, your requirements do not overlap. What I'm arguing for is that click^7 and click^8 should be seen as different packages that (like any other packages with different names) can be installed side-by-side without issue. It sounds weird, but it makes this problem goes away entirely. Nodejs and (I think) cargo both support this. I've never run into errors like this in rust or node. Another advantage of this approach: Integration tests in all previous versions of a package should pass on the current version of that package. I'd love to see test runners which actually enforce this - which should be pretty easy to do in a language like rust where integration tests are clearly separated. Sometimes (rarely) it makes sense to allow an integration test for react16 v1.0 to fail on react16 v2.0, but that implies a violation of semver compatibility. So it should be the exception. Not the default.