SemVer has failed us
11–20 of 52 posts
Re: SemVer has failed us
#12The first notion is needed for keeping our code stable but keeping up with bufixes and security patches. The second one is needed to deal with design issues: will this change require a lot of reworking? Will it change the underlying model or abstraction in the library?
Both of these are important. But because Semver requires bumping for any breaking changes—even if they are semantically minor—it can only address the first, low-level notion of versioning, not the second.
A possible solution? We can have two minor version numbers:
4.1.0.2
Patches and backwards compatible changes work as always. But if you are making a breaking change, you have two options. If it's not too big, just increment the first one: 4.2.0.0
But if you're really changing things up and creating a new generation of your library, go for 5.0.0.0
Of course, the difference between the two major numbers is not well-specified. But that's fine! From the more technical, low-level perspective, it's no different from normal Semver: any change in the major version (either of the two numbers) can be breaking. It just also lets library authors send an additional signal to developers about the scope of the change.For example, this scheme gives more information on how "stable" a library is. If the second major number is high, it means there are a lot of minor breaking changes; it would take a bit of active maintenance to keep up, but as long as the first major number is not changing, these steps won't be radical.
Personally, this approach makes a lot of sense to me. It's also more or less what Haskell packages use according to the "package versioning policy", and it seems to work pretty well. (There are some other pervasive issues with Haskell version numbers, but not related to how they treat major versions.)
Re: SemVer has failed us
#13For smaller projects and libraries, it works very poorly, because these are usually "itch-scratching" efforts that don't necessarily have a clear endpoint or goal. For these kinds of packages, I wish people would just use a commit number. I really hate having to agonize over SemVer for a 500 LOC miniproject.
That kind of project, incidentally, is the most likely to be in "0.X.X" limbo forever. See for example the Clojure ecosystem where 80% of packages are this way.
Re: SemVer has failed us
#14Completely agree. For a long time, I've thought that humans shouldn't be in charge of version numbers at all. The main problem is that a human isn't reliable at determining "is this change breaking?". Unfortunately our software isn't well-specified enough to allow the computer to determine version numbers automatically yet. To make this a reality, you'd need Haskell-level type safety, along with specifying other cons…
> Unfortunately our software isn't well-specified enough to allow the computer to determine version numbers automatically yet. To make this a reality, you'd need Haskell-level type safety, along with specifying other constraints, like "this fn is O(log(n)) or better". Isn't this going to be impossible for the same reason the Halting Problem is unsolvable?
Re: SemVer has failed us
#15Completely agree. For a long time, I've thought that humans shouldn't be in charge of version numbers at all. The main problem is that a human isn't reliable at determining "is this change breaking?". Unfortunately our software isn't well-specified enough to allow the computer to determine version numbers automatically yet. To make this a reality, you'd need Haskell-level type safety, along with specifying other cons…
> Unfortunately our software isn't well-specified enough to allow the computer to determine version numbers automatically yet. To make this a reality, you'd need Haskell-level type safety, along with specifying other constraints, like "this fn is O(log(n)) or better". Isn't this going to be impossible for the same reason the Halting Problem is unsolvable?
Is it possible to specify the complexity of every arbitrary function? Probably not. Is it possible (and useful!) to specify the complexity of most functions you use on a daily basis? Absolutely.
A stronger critique I heard once is that 'computer generated complexity analysis has too much noise in it', where you ask what is the complexity of this fn, and rather than giving you O(n^2), it gives you back O(n^2 * m * q * log(r) * s^4), but it turns out 's' is "always" a small number, and m & q are constants. You can improve (but not completely eliminate) this by doing empirical testing, i.e. "the statistical sample of 1000 test runs varying the input does appear to fit an O(n^2) curve".
Re: SemVer has failed us
#16Completely agree. For a long time, I've thought that humans shouldn't be in charge of version numbers at all. The main problem is that a human isn't reliable at determining "is this change breaking?". Unfortunately our software isn't well-specified enough to allow the computer to determine version numbers automatically yet. To make this a reality, you'd need Haskell-level type safety, along with specifying other cons…
These minor version bumps scare library developers, especially people that produce libraries that depend on libraries that depend on... and so on. So packages fail to build too often because of constraints. So the irony of this thorough process for package building is that humans have mucked it up and made it break builds. In almost every case in which semantic versions blocked some update from occurring and caused my work to stop, it was because I needed to bump the constraints on some third-party package. It's a boring process that I've only become too accustomed to:
1. try to build with updated libA 1.1.0-foobar
2. libB depended on libA 3. download source for libB
4. update constraint and repackage libB locally
5. rebuild main application
This happens just about every time there's a new version of any major piece of Haskell software.
If we really want to move into The Future, we need to start versioning individual modules or functions, instead of whole suites of software. But the cognitive burden of doing this is very high, and the software to do it hasn't been written yet.
[1] The Haskell community doesn't technically use semver, but rather a related policy called the package versioning policy. That's a nitpick though, and doesn't affect my argument.
Re: SemVer has failed us
#17Earlier quoted context omitted.
> Unfortunately our software isn't well-specified enough to allow the computer to determine version numbers automatically yet. To make this a reality, you'd need Haskell-level type safety, along with specifying other constraints, like "this fn is O(log(n)) or better". Isn't this going to be impossible for the same reason the Halting Problem is unsolvable?
The halting problem is unsolvable in the general case, but there are lots of specific, practical cases where you can answer "yes, this program terminates". Is it possible to specify the complexity of every arbitrary function? Probably not. Is it possible (and useful!) to specify the complexity of most functions you use on a daily basis? Absolutely. A stronger critique I heard once is that 'computer generated complexi…
Re: SemVer has failed us
#18In general, it's always better to have a computer enforced standard over a human enforced one. Semantic versioning can just become human readable sugar over a set of contractual expectations.
Re: SemVer has failed us
#19SemVer is working fine, you just need to face up to the real impact of a change on clients, not what you wish was the impact of the change. If a change breaks clients who rely on buggy behavior, you need to bump a version, not a patch number.
Re: SemVer has failed us
#20We've used SemVer for Julia for a while now and it seems fine. However, versioning and compatibility are still hard problems and a perennial, unavoidable pain. The way I like to think of it is this: - patch: forwards and backwards compatible – only bug fixes, no new features, no changing existing features. - minor: backwards compatible – new features allowed, but old code should keep working. - major: all bets are of…
So what should upstream do? After all, the premise must be that the upstream does not control or even know about all the clients! The entire point is to separate the concerns, so how could upstream know if a bug fix is a breaking change if it passes the internal regression tests?
Of course they can't know without asking downstream, and hence the use of release candidates.