Sentimental Versioning
sentimentalversioning.org
sentimentalversioning.org
We necessarily include extremely detailed change documentation for a 1.x to 1.y release and our versioning system is described in great depth at https://www.sqlalchemy.org/download.html#versions . I didn't provide an easy word like "romantic" for this website to mock but we're doing essentially the same thing AFAICT.
When Jeremy says "This allows folks, immediately upon hearing about a new release, to get a rough sense of its scope.", that is exactly what we are doing as well when we are suddenly calling an upcoming release "2.0". The scope is dramatically broader than the scope in which we move from 1.x to 1.y. It's fun for semver purists to make clever (and definitely funny) websites mocking this need but that does not change that fact that semver does not work for every kind of project.
Instead, a more sane thing to do there is: patch is for bug fixes, like perhaps addinng a `cursor: pointer;` that you forgot to a button. Minor is for adding new features, and major is for heavily modifying or removing features.
I've yet to experience any serious issues updating SQLAlchemy versions and the guides for upgrading have been top notch.
Versioning is for machines and developers. Versioning is the way to communicate the scope of change. Tools rely on it. The ideal package manager should reject non-major releases that have breaking changes.
Softwares that don't respect Semver actually don't respect the developers that use them.
End users don't care about the version of your product (even if they are developers). Fast, what's your current Chrome or Firefox versions? (Hint: greater than 48)
I remember being pretty upset that they broke that with what surely must be only a bug fix release. Now I know better.
https://lkml.org/lkml/2019/3/3/236
I'd like to point out (yet again) that we don't do feature-based
releases, and that "5.0" doesn't mean anything more than that the
4.x numbers started getting big enough that I ran out of fingers
and toes.
LinuxWith as many as three major releases a year, its versioning system is a performance art piece exploring the endless turmoil and internal struggle of a project that is expected by the world to follow semantic versioning, but whose soul yearns to move fast and break things.
At least for the basics(immutable collections), it's stable enough
I'd love to know how semver, git-flow, and other zombie ideas get established, despite decades of effective battle proven lore. Uncle Bob's theory is that population grows faster than they can be taught (onboarded), so that cone of ignorance expands faster than adoption rate of best practices.
My favored scheme is roughly like so. Automatically assign a build number to every build for tracking purposes. Assign a semver number to every version you publish in order to give some concise signaling to operations folks and technical consumers about how the version behaves compared to the previous one(s). And, when applicable, assign a more creative version number for marketing purposes. I've always liked year-based numbering schemes for that purpose. It's immediately meaningful, and encourages staying up-to-date by giving a reminder that you're still on a version that came out 4 years ago.
Deming process people call this "one way flow" of information.
Paraphrasing, mostly to continue my rant:
Versions are just labels (tags, aliases) you share with clients, users. Semver is no worse than any other scheme. And fretting about semver gives scrum masters something to do.
Build numbers are used for internal processes. Like the "found", "fixed", "closed" fields that QA tools should have (but rarely do).
As you said, version is annointed AFTER an artifact is accepted, moments before release. Like an imprint. (For all workflows prior to "Test Into Prod", so ymmv.)
Then everyone can also precognitively divine a future version, so stuff like press releases can be front loaded. Genius!
Few things drive me more nucking futts than teams which predetermine version before attempting a build. Oops, build failed. Manually increment semver. Try again. Rinse, lather, repeat. Then ferret all wiki references to semver and update those JIRAs.
Trying to explain this to noobs is harder than advocating using knives for cutting to someone who's only ever seen spoons. People get it when they see it, but can't imagine it, so the push back is exhausting.
This probably also explains his success...
For those of us working on things not worthy of a mathematical constant, I prefer plain old major.minor. If it breaks something, increment major and reset minor to 0. Anything else doesn't really matter.
- Is the release stable? Alpha, beta, experimental new features?
- Does the release have known vulnerabilities? How insecure is it? (of course, this changes as time passes and might stop being tracked, so it's not easy to manage)
- Did a new release break back-compatibility? How much? Are we breaking everything, or just slightly changing the behavior of one function?
- Does the release include new important features or API changes?
- How often should I check for new releases, or how can I get notified if there are important unexpected changes?
To me, any non-toy software project needs to respond very clearly to all these questions. If it does, I don't care about semver or not semver. If it doesn't, I don't care about semver or not semver.
MAJOR versions can also be incremented when "substantial new functionality or improvements are introduced within the private code" which is really the cause for confusion and, in my opinion, should be removed from the SemVer standard. There's no semantic value to consumers when significant amounts of private code has changed except for the potentially heightened possibility of introducing bugs. Removing this would clear the confusion up altogether.
But the ComVer contention is that bugs don't deserve special treatment. I disagree. Changes to behavior that fix something but don't change anything else are changes I'm likely to want to deploy while maintaining a system. I might be using a legacy version where the main branch has progressed but I still want to deploy PATCH releases for bug fixes for an older version when they become available. I do not want to upgrade by a MINOR version if I can avoid it because it would add functionality or interfaces I don't need and which themselves could be problematic. I want to make as little change as necessary to maintain a otherwise stable system.
Minimizing the surface area of a release to only the necessary is an important principle to follow when publishing public APIs. Thinking about bug fixes as distinct from new features means you're considering every change in light of the potential impact to consumers. Even when know you don't have any actual dependent consumers, it's still a good habit of a disciplined engineer.
Without this you just leave the umbrella of versions to create a new package for your next era. This is fine except for corporate or big name projects that want the advantage of their package name for many years.
- https://man7.org/linux/man-pages/man7/deb-version.7.html - https://rpm-packaging-guide.github.io/#epoch
https://manpages.debian.org/buster/dpkg-dev/deb-version.7.en...
Or possibly this one: https://www.debian.org/doc/debian-policy/ch-controlfields.ht...
99% of people using SemVer actually only have two types of change:
1. "Updating will probably work, but you should test anyway in case we've introduced a regression or you depend on behaviour we've decided was a bug"
2. "Updating might not work, depending on which features you're using, but you should test anyway and you'll be forced to update eventually anyway"
Given users have to respond in the same way to both, why adopt a versioning system that claims 1.12 is greater than 1.2 ?
"This update fixes important bugs and will almost certain work if the previous version did"
bool operator<=(version lhs, version rhs) {
return (lhs.Major <= rhs.Major) || (lhs.Minor <= rhs.Minor) || (lhs.Patch <= rhs.Patch);
}
looks correct for anyone who have never wrote such comparison before, but of course it's wrong. The correct one is bool operator<=(version lhs, version rhs) {
return (lhs.Major < rhs.Major)
|| ((lhs.Major == rhs.Major) && ((lhs.Minor < rhs.Minor)
|| ((lhs.Minor == rhs.Minor) && (lhs.Patch <= rhs.Patch))));
}
[0] https://devblogs.microsoft.com/oldnewthing/20040213-00/?p=40... cat >test_ver.cpp << EOF
#include <cstdio>
struct version {
int Major;
int Minor;
int Patch;
version(int major, int minor, int patch)
: Major(major)
, Minor(minor)
, Patch(patch)
{ }
};
bool operator<=(version lhs, version rhs) {
return (lhs.Major < rhs.Major)
|| ((lhs.Major == rhs.Major) && ((lhs.Minor < rhs.Minor)
|| ((lhs.Minor == rhs.Minor) && (lhs.Patch <= rhs.Patch))));
}
int main(int argc, char **argv) {
version lhs(4, 3, 7);
version rhs(3, 3, 7);
printf("lhs <= rhs? %s\n", lhs <= rhs ? "true" : "false");
}
EOF
g++ test_ver.cpp -o test_ver && ./test_ver
prints lhs <= rhs? falseIt is equivalent to the following:
lhs.Major < rhs.Major
or (lhs.Major == rhs.Major and lhs.Minor < rhs.Minor)
or (lhs.Major == rhs.Major and lhs.Minor == rhs.Minor and lhs.Patch <= rhs.Patch)
Deduplicating (lhs.Major == rhs.Major) decreased readability enough to be confusing. bool operator<=(version lhs, version rhs) {
return std::tie(lhs.Major, lhs.Minor, lhs.Patch) <= std::tie(rhs.Major, rhs.Minor, rhs.Patch);
}
Wait, there is! And Python has something like this too, even more laconic: you don't need to write "std::tie", naked parentheses are enough.edit because I feel like I have to: this describes my experience, it may not be fact, your experience may differ, etc.
- the changes had to be small (and would be by nature of so close together) - we had to be very very careful about backwards incompat changes (either to the UI or the APIs).
Of course we're on the opposite end of that today, where two major browser engines are Chrome and WebKit(Safari), with Gecko often an afterthought.
Glad these alternative versioning schemes now have a name.
Patch - a build we do to be deployed to clients test environment that we don't control
Minor - a prod build for client
Major - reserved for when the client demands a complete redesign of the app
It works for us, for this project... And of course nobody else is depending on it
As long as it's not a library with no external things and not more than one thing depending on it you don't necessary need semver at all.
$ curl --head http://sentimentalversioning.org/
HTTP/1.1 200 OK
Server: GitHub.com
Date: Mon, 12 Oct 2020 05:28:30 GMT
[ ... ]
Last-Modified: Fri, 12 May 2017 07:22:37 GMTThis was discussed on 2014-07-31: https://news.ycombinator.com/item?id=8247877
This matches “[Node.js] version 0.12 having been in the works for over a year”, since 0.10 was released on 2013-03-11 (per https://nodejs.org/en/blog/release/v0.10.0/) and 0.12 was finally released on 2015-02-06 (per https://nodejs.org/en/blog/release/v0.12.0/).
It jumped from 0.12.7 to 4.0.0.
Sentimental Versioning:
You may see a download
Along with release notes
And somehow you know
You know even then
That somehow you'll update
Again and again.https://github.com/Microsoft/TypeScript/issues/14116#issueco...
Seems like quite a blase approach to the development of such a large project.
I don't think anyone is losing sleep that we're on Chrome 86.0.4240.75 and that communicates exactly the amount of information I need to know if that's older or newer than another version.
I agree it's not semantic versioning, per se, and maybe not nice to developers but it's at least communicating clearly IMO.
How is this communicating clearly or being helpful to me? Does anyone know offhand what major version of Chromium/Firefox they're using? If it's just an incremental counter, then why do we need .0.4103.116?
Hope more articles coming up on the site.
Add to it the dangers of names being taken directly from de clients, and enjoy the fun. Having clients name something “machine v2” was a nightmare.
On the plus side, it gave us a lot of jokes when a client named something “machine X” about how many iterations would it take to get it right.