I like semi-annual release cycles. 2020a, 2020b. 2021a, 2021b. Nice, simple. Dates, too.

It’s a bit slow if you are used to releasing every sprint, or commit, or something.

It’s a bit fast for large suites of software products.

But for a single product or system, I think it’s the way to go.

It allows for near-term future commitments without breaking current state. On the other hand, things you ask for are generally 6 months away. So “near-term” is a bit of a stretch.

It allows for more predictable long-range planning, especially if other systems share cadence / are in phase.

Porting future changes to current versions seems innocent enough. It can’t possibly be twice the work to add a feature to 2021a and then add it to 2020b. You’d only ever really need to go that far, unless you had a (paying?) customer with an even older version. Backports are never exactly free.

It’s easy to remember the scheme. You pretty much know which version you were running at any given time. 2020a would’ve come out early 2020, maybe January - March. 2020b would’ve been July - September.

And if you release 4x a year, you should abandon a b c d and go straight to enumerating the month: 2020.01, 2020.04, 2020.07, 2020.10 &c. This is, arguably, more admirable, but I do like the shorthand of 2020a and 2020b, because I think it’s more reliable that others will align with your cadence, not too fast (but maybe, for some, too slow).

I’m fine with feature flags to enable next- or last-generation features. I like lots of flags, with good metaflags, so to speak (like --best or --auto).

Short shoutout to versioning I hate: Windows (service packs, build numbers uselessly big), Emacs (again, too big), Chrome/Edge/Firefox (all too big), OpenSSL (too 1.0.2.å.®), TeX (converging to an irrational limit? really, Don?).

Versioning I like: youtube-dl, Matlab, FIFA/Madden, guitars, wine. All of these just go by year, or year-mm-dd. Maybe, ya know, we could appreciate this time thing a little more, just an epsilon here and there. Guitars often get down to month, but I don’t think ever down to the day.

Car models, I give honorable mention, but it’s always off by 1, when they come out.

I wish Apple would just call it the iPhone 2020. Just get on with it. iPhone 12?? Looks like a 5, but they’re coprime. Whatever.

And lastly, it should be consistent, no gaps. Just re-release last version and slap new labels on it. You can’t, you know, very well charge for that kind of thing, but I hate leaving gaps.

You should leave old versions up, too.

I think it’s fair to write a little bit of not-quite-DRM / disableware to demo basic functionality right out of the standard product installer, with full functionality behind a keyhole.

too slow

So what if 6 months is just not fast enough?

You can run a weekly build, and a daily build.

Like debian, consider one testing and the other unstable.

If that sounds bad, consider that’s basically what we deal with in real life, where versions could potentially bump on any given day, even for really old stuff that hardly gets updated.

It would mesh nicely with the more broad version specifiers, if you needed something like

dependencies: {
    "xlib" "2020a"
    "ylib" "2020-07"
    "zlib" "2020-04-01"
}

and it works out just like things do now, except it’s way easier to see if you have an outdated dependency. Contrast:

dependencies: {
    "xlib" "2020a"
    "ylib" "2014-03-02"
    "zlib" "2009-11"
}

Oh dear. But you wouldn’t notice that if it’s "zlib" "1.0.2" when current version is "3.4.9" or what have you.

Outdated dependencies always look the same

dependencies: {
    "xlib" "2.13.6"
    "ylib" "8.1"
    "zlib" "1.7.0"
}