Hacker News new | ask | show | jobs
by gourlaysama 4339 days ago
I am not sure I agree with all of OP's argument, and I don't really care for the whole "version numbers as a marketing message" thing, but for me SemVer fails miserably when it comes to binary compatibility versus source compatibility (and don't even start on semantic compatibility...).

In languages where that difference matters, let's say Java/Scala [1], there are way too many possibilities:

- bug fix: forward and backward binary compatible; basically a drop-in replacement. Package managers are supposed to resolve conflicts between those automatically,

- new feature, but backward binary compatible; just some new code alongside the old. Package managers should also be able to resolve a conflict between dependencies that depend on different versions of those.

- bug fix: forward and backward source compatible; here we have a problem: we can guarantee developers that they won't have to edit a single line of code to migrate, but we can't allow (binary) package managers to do anything. They have to rebuild their library, which means bumping their own version number. And does that means that their new version becomes binary-incompatible with the previous one, or just their dependencies?... who knows? Maybe it depends on if the consumer of that library calls into the conflicting dependency directly or only uses it indirectly? Maybe not? Can we tell?

- new feature, backward source compatibility, but no binary compatibility; same as above: package managers cannot do anything, and conflicting transitive dependencies on the new and the old may or may not be solved by recompiling one's library. The only safe bet is to wait for the dependencies to upgrade.

- all bets are off (possibly split in minor and major): here at least we know there is nothing to be hoped. But in practice after upgrading to the new API, you are faced with the same questions concerning that thing's dependencies...

And if every dependency manager within the same packaging eco-system doesn't enforce a single global versioning scheme, how can they handle any dependency version conflict anyway? They could if packages could auto-describe their semantic versioning, so basically they can't, so they don't, and we're back to source dependencies, with recompile and bump in version number for every dependency change (ok, sometimes they do try and we get JAR hell...). And since a single versioning scheme isn't enforced, people use hundreds of different ones (or just none), and the maintainer of a library has to make all of those decisions, recursively (except that below 1 level of dependency, he/she might not be able to do anything as long as even a single dependency keeps an old conflicting dependency around, but they still have to check, in case they are lucky and can do something), taking into account the different versioning semantics of each dependency. That's madness.

So in the end, if we get a conflict between dependencies far down in the dependency tree, it becomes something pretty ugly:

- if guaranteed binary compatibility, everything is fine,

- otherwise:

0) look at that dependency's official versioning scheme, usually find nothing (except for big famous libraries)

1) pick the highest common-one, try to recompile your library

2) if it works, try the tests (your library's tests, not your dependencies' tests, mind you. Even though those should probably be run, considering they directly depend on it, and use (and hopefully test) more stuff from that library)

3a) it it works, ship it and pray.

3b) it will probably fail somewhere since the dependencies in between have not be recompiled; then you can only wait for them to upgrade.

I know in the end this doesn't work so bad (well, everything is relative...), but it still makes me sad that upgrading dependencies is still human-based trial and error.

Oh. I guess this is a rant.

[1] that's just what I am the most familiar with, but you could say the same with C packages in a distro's package repo, for example.