10 ms·
Pragmatic Versioning – An Alternative to Semver
- mock-possum 3y agoOur ad hoc system on the last big product I worked on was roughly: A.B.C A is a big major release, a significant step forward in terms of how you interact with the product - the difference between 1.b.c and 2.b.c should be fairly apparent. B is for Breaking changes within a release - if it used to work one way in a.1.c, you shouldn’t rely on it working the same way in a.2.c C is for non-breaking new features and bug fixes - if you’ve been using a.b.1, it should be totally safe to switch to a.b.2 Not sure if that was the best approach, but it’s sort of what we settled on organically and nobody complained so It helped that our users were mostly our client’s counterpart developers, so they were pretty looped into our release cycle anyway.
- catlover76 3y agoI am surprised more software libraries don't simply use date versioning. What is the reason?
- deathanatos 3y agoIt doesn't convey useful information like Semver versioning does. (Now, why things that don't do Semver don't just do DateVer in lieu of that… IDK, really. Marketing likes to take advantage of it? …& then you get stuff like the OP here.)
- catdog 3y agoAt lot of projects honestly should just do something simple like date versioning, approximate pi, just increment a single number, ... Especially those which currently use the major.minor.patch format but don't care at all about what it usually means, that in itself can be fine but using such a version scheme is then annoyingly misleading.
- nonameiguess 3y agoYou've made it pretty hard for anything downstream to declare a dependency on a version range. They can depend on a date range, but it's not clear what basis there is for picking any particular upper bound other than "last known working version."
- mostlylurks 3y agoWith semantic versioning, it's easy to go back and provide a security update (for instance) for an earlier version of a library (which matters if the newer version is API compatible or has different dependencies or a different license or has stopped supporting the platform the user is on). If you try to do the same with date versioning, your versioning suddenly because very misleading and confusing.
- yencabulator 3y agoThe "sane" way of combining those is that the date takes the role of the major version, and this mostly applies to big projects that are pretty much guaranteed to have at least one breaking change in their twice a year release. Then you can say 2023-06-01.2 for a maintenance release on top of 2023-06-01.
- golergka 3y agoBecause software versioning is non-linear. A security patch to a previous LTS version can be newer than a new version of the software.
- travisjungroth 3y agoDates are one dimensional, monotonic, totally non-strictly ordered. There’s no room for branching. Branching is necessary anytime you want to have multiple “latest”s. This is usually major releases with ongoing bugfixes and security updates but minimal breaking changes. What I’ve never seen, but seems useful, is to throw the date on the version number as the third or last number. The nice thing is you get the ordering back. Something like 4.3.20231204
- erik_seaberg 3y agoAs I recall, Maven tooling lets you say 4.3-SNAPSHOT and creates 4.3-2023.12.04-23.27. When you release 4.3 it will be considered newer than all the snapshot versions (and other qualified versions like 4.3-beta).
- travisjungroth 3y agoNice. That makes me realize I’ve seen it as part of nightly builds. Seems like it should just be standard though.
- t_tsonev 3y agoThat's a pre-release and is covered by Semver.
- mickael-kerjean 3y agoThat's exactly what I do on my OSS work [1]: MAJOR.date. it works great for my use case (not a lib) but I don't count how many discussions I've had with people telling me: "do you know semver? You should use it" [1]: https://demo.filestash.app/about https://demo.filestash.app/about
- nablaone 3y agoWe use YEAR.SPRINT.PATCH scheme, for example 23.10.1. But this is an internal SaaS version.
- seveibar 3y agoAn early draft of an alternate system to semantic versioning (semver) that I think is more useful in practice for both package maintainers (who don't want to evaluate every change for meaning, and want to be able to maintain large releases) and package contributors (who want to know what the maintenance period is) Pragmatic versioning reflects more closely what many mature projects do in practice. Feedback welcome!
- bensecure 3y agoIt basically just says that version numbers are meaningless and purely marketing. "Pragmatic" yes, but in need of standardization, no. The project comes across almost as a satire, so its odd for you to treat it as serious here.
- dbingham 3y agoHonestly, this is all too often how versions actually get used - that's what makes it feel like satire. But there's nothing wrong with admitting that the ideal of Semantic misses the mark, looking at real world usage, and saying "Okay, maybe we should formalize that in some way." I can see that being useful, especially if people are able to say "We use PragVersion rather than Semantic" to communicate the reality, rather than saying "We use Semantic" when they are, in fact, using Prag.
- m4dc4pXXX 3y agoNeeds examples.
- simonw 3y ago> In Semantic Versioning, there is no way to release or communicate a LTS/"long term support" version of a package. In Pragmatic Versioning, this is solved with a BIGRELEASE version, which has meaning that can be controlled by the package author. That doesn't make sense to me. With semantic versioning the way you communicate a LTS version of a package is you declare that in your documentation. Django (which doesn't fully use SemVer, but is still a good example here) does that on this page: https://www.djangoproject.com/download/#supported-versions https://www.djangoproject.com/download/#supported-versions "In Pragmatic Versioning, this is solved with a BIGRELEASE version, which has meaning that can be controlled by the package author" - that doesn't appear to address the need for LTS communication at all. It feels like the situation is exactly the same as SemVer: if you want to do LTS you have to represent that outside of the version number.
- natbennett 3y ago“There’s no way to…” is maybe imprecise phrasing but this is a real problem. Marketing departments really want to use that first number for Big Important Releases and only Big Important Releases. I have seen products get their version incremented from 2.x.x 3.0.0 to indicate that an entirely different product (that could be deployed alongside the first but was otherwise unrelated) was being launched.
- mlhpdx 3y agoThat doesn't sound like an issue with semver (or pragmatic). There is no versioning convention that will prevent people from being people. A rigid, automated (magical) versioning _system_ might do that, but not a convention/standard. I find semver extremely helpful, both as an author and consumer. It may make me think a little for some packages about where I want to pin things, but at least it makes the mechanics of pinning them sensible. Edit: packets -> packages
- natbennett 3y agoServer is very helpful in many contexts, especially libraries and packages, and that don’t have associated commercial support obligation. It has real drawbacks for on-premise software with commercial support obligations, and shouldn’t be used automatically just because it works well for libraries.
- simonw 3y ago"Democracy is the worst form of government, except all those other forms that have been tried from time to time." - attributed (but likely not accurately) to Winston Churchill Looks to me like Semantic Versioning is the worst form of versioning except for everything else we've tried.
- marcosdumay 3y agoHum, no. Semver has lots of problems and many other standards work better. The ones that look like this one on the article tend to fare the best for libraries.
- simonw 3y agoWhich standards work better?
- marcosdumay 3y agoAnything that has a human-decided number overruling all the others and no indefinite timespan when no rules apply. Personally, I do like the Haskell standard a lot. People tend to not use the extra number a lot, but just because it exists the other ones are much cleaner. Or you could use the one on the article.
- vacuity 3y agoPerhaps, but a lot of people misuse it. It's easy to accidentally get breaking changes when some part of the chain is misused.
- natbennett 3y agoThis is great. Especially for products that need long term support, which is basically not compatible with semantic versioning. (Since LTS versions occasionally must have security fixes that are also breaking changes backported.)
- baq 3y agoVersions are a communication tool. There is no best tool for all jobs. Write down your communication objectives and pick a versioning scheme which fulfills them. Want to communicate api compatibility? Use server. Want to communicate a new version worth at least checking out? Bump that major version.
- herpdyderp 3y agoThis sounds similar to how TypeScript versions are named and it is a huge pain to me. Can I upgrade from 5.2.2 to 5.3.2 without everything breaking? Who knows. I thought I could, but I was wrong. Semver (when followed correctly, of course) would've conveyed this information instantly. I don't care about the branding, I just want my code to work. (Disclaimer: I am obviously not in marketing.)
- bombcar 3y agoTo be fair, Semver also falls apart relatively regularly, where a major version upgrade is easy and fine, but a minor upgrade trips you up. Even if an API stays exactly the same, something about what it returns could subtly change, so there's really no replacement for extensive testing.
- herpdyderp 3y ago> Even if an API stays exactly the same, something about what it returns could subtly change This means the API did in fact change. But you're right of course, sometimes we pick the wrong number to bump (major vs minor vs patch).
- madeofpalk 3y agoIt depends what you consider your "API" to be. One developer's bug is another's contract. For Typescript in particular, which is nothing _but_ a type system, every change is going to be a breaking change.
- bombcar 3y agoExactly - if your API makes a mistake somewhere, someone is depending on that mistake. So even if the API says “returns the number of chickens” and now correctly returns 5 when there are 5 instead of saying 4; that may break something.
- zzo38computer 3y ago> One developer's bug is another's contract. That is why you have major.minor.patch semantic versions. The documented and official contract is according to equal to major versions, and greater or equal to minor versions (and possibly the patch number as well); if you depend on a specific bug or internal function then you should use the exact full version number only, in order to avoid such a problem. A bug would be one example, but another example might be the sqlite3_test_control function in SQLite.
- remram 3y agoWhy not encode further information into the number, if that's what you want? 1004.0.0 to 1005.0.0 is an api-major business-minor version bump (incompatible API). Semver-compatible. 1004.0.0 to 2000.0.0 is an api-major business-major version bump. There, the first number has changed, if that's important to you. Semver-compatible. 1004.0.0 to 1004.1.0 can be the "INCREMENT" thing they also mention. As a bonus, your version number is soon going to be much higher than competitors. That's sure to impress clients. You can refer to the 9000-line easy enough.
- cush 3y agoNeeds more bitmasking
- remram 3y agoOnly if a machine wants to read the business number, which it doesn't.
- colejohnson66 3y agoWhy not just have a four part version number? * 1.4.0.0 to 1.5.0.0 * 1.4.0.0 to 2.0.0.0 * 1.4.0.0 to 1.4.1.0
- remram 3y agoNot semver-compatible.
- yencabulator 3y agoNeither are breaking changes in a minor-according-to-semver bump.
- remram 3y agoMy point is that you don't have to do that. You still do a major version bump for breaking changes, you just have another number before that, for your business communication concerns.
- yetanother12345 3y agoI've always been a bit baffled by these types of discussions. Doesn't any of you have multiple versioning systems, say "internal" and "external" at the minimum? One project I'm on has an internal version number of around 28-dot-something-something. This is the number for techies, and it conveys some information that end users are fully ignorant of. End users see "Edition 2" in stead (soon to become 3)
- nerdponx 3y agoSemVer is intended primarily for libraries; techies are the end users.
- jmbwell 3y agoSeems like where semver focuses slightly more on the state and process of development, this thing focuses slightly more on marketing. For instance, semver increments field values when the state of the API or level of compatibility with previous versions changes, or maybe just when something about the build has changed. This thing appears to aim to express changes in features and functionality. Less about the mechanics of software assembly and more about reasons the vendor would want users to update. It describes issues with semver similarly in terms of marketing, which might explain what seems to be some cognitive disconnect among the different ways people seem to be interpreting both systems. Semver speaks developer language, while this thing seems to speak product manager language. Not sure how it’s differentiated pragmatically, except perhaps for the practical purposes of a specific role in a vendor’s organization.
- drewcoo 3y agoYes, and maybe that means marketing shouldn't be using dev version numbers. Marketing-Driven Development? Yuck.
- riquito 3y agoIt's the old way of versioning things, somewhat formalized. With semver you live in this world where you are promised the versions to follow semantics, but human nature creeps in and we introduce breaking changes (like bugs!) without setting the version correctly. With pragmatic versioning you give expectations but also convey that to upgrade you need to test that your software still works.
- chrisweekly 3y agoI liked the ideas behind another semver alternative called "imver" or "Immutable Versioning" (https://github.com/imver/imver/blob/master/imver.md https://github.com/imver/imver/blob/master/imver.md) that never quite caught on. It's basically just a timestamp. It requires full backwards compatibility of public APIs and behaviors (side effects) for the lifetime of the package. Read about it on an interesting 2019 blog post about monorepos and versioning: https://hub.packtpub.com/why-dont-you-have-a-monorepo https://hub.packtpub.com/why-dont-you-have-a-monorepo
- yencabulator 3y agoThat just pushed the "major" into the package name. You've released package foo version iv2019.01.01 and now need to make an incompatible change. You mark foo as deprecated and release foo2 version iv2023.12.06. That is not an improvement.
- tipiirai 3y agoI love this! Looks like this would solve a common problem where product managers and marketers are running this "pragmatic" versioning scheme (release, major, minor), and developers are running some other "internal" versioning scheme that is closer to semver (major, minor, patch). Wouldn't Pragmatic Versioning work for both?
- ghshephard 3y agoA lot of the communications regarding End of Life for Support is done very effectively here: https://endoflife.date/ https://endoflife.date/
- mattxxx 3y agoI think "BIGRELEASE" is not accurate representation of how semver is used. I always understood it as something that introduces a non-backwards compatible change in the API. This is so that you can specify ranges of api versions that your program could be built with. For reference, here's where I took my understanding: https://semver.org/ https://semver.org/
- zzo38computer 3y agoI think that "major.minor" is a useful feature of semantic versioning, that you can specify breaking changes vs non-breaking changes. "Announcement" version numbers may also be useful, although perhaps not as much, it seems to me. However, one thing I think would be useful is numbering of versions of "configuration-safe" upgrades.
- seveibar 3y agoIn my original commit I wrote "BIGRELEASE.MAJOR.MINOR" but I realized in practice many packages start to bundle multiple changes into their MAJOR and sometimes even MINOR releases. To me this started to really confuse SemVer, ANNOUNCE/INCREMENT is comparatively a bit cleaner/more like what they were doing in practice (see the NextJS example)
- kijin 3y agoWhatever you call it, there needs to be some distinction between breaking changes and other changes. It doesn't need to be as prominent as the marketing-oriented big release, but it needs to be in there somewhere. Modern software projects have too many dependencies, and too much noise coming from each dependency. Your project is likely just one of hundreds of libraries that got pulled into my dependency graph for some reason. I want to know if, and only if, there's a change that I need to be aware of. As for that shiny new feature that you're really proud of, I shouldn't even notice it unless it breaks an existing API.
- gorgoiler 3y agoI like this rationale. Acknowledging that the first number is very much the product brand is wise. Release numbers can be quite emotional things. Version numbers are indeed for communicating with your users, and in particular where that communication is a one way broadcast. In my career I’ve found that, when version broadcasting is used inside a team, it’s a sign of dysfunctional communication. Even at FAANG scale I encourage groups of people to colocate their code and collaborate on trunk in preference to putting up hard boundaries between projects — namely having to cross repositories and integrate with each others versioned releases. There’s no point hampering yourself with the one-way broadcast mode of communication unless you absolutely have to. When you have multiple teams one-way broadcasting at each other then, well, maybe it’s time we sat down for a chat instead?
- deleted 3y ago[deleted]
- avodonosov 3y agoThe biggest issue with semver is that it encourages compatibility breakages under the false promise that increased major version number saves the users from the dependency hell. https://github.com/semver/semver/issues/771 https://github.com/semver/semver/issues/771 SemVer is a product of Ruby community. In 2000s Ruby library authors were breaking compatibility left and right, neglecting elementary compatibility practices. If you were working on an application, every time when you update dependencies, the application would break. So (in 2011 ?) they came out with this "manifesto" (Why such a big name? This scheme of versioning was well established in linkers and sonames of Unix-like systems for decades - it goes back to at least 1987 paper "Shared Libraries in SunOS"). It's a good thing SemVer acknowledged finally that compatibility is a serious matter. Only that it's better to discourage compatibility breakages. An in cases when it's really needed (I agree such cases exists), there are things to take care of in addition to simply increasing major version num.
- lloeki 3y agoFrom your issue link: > Then commons-logging changes its API incompatibly and is released as commons-logging 2.0.1. Authentication adopts commons-logging 2.0.1 while other libraries still depend on 1.1.1 > Now my-application is broken, because the dependency tree includes two versions of commons-logging which share packages, class / functions names, and thus can not be loaded simultaneously. I absolutely don't see how this is a problem with semver, it is not the responsibility of semver to tell a language how packages should be isolated and loaded. That is a problem of a) the language and b) dependency resolution in the package manager. > SemVer is a product of Ruby community. Bundler, by design, does not allow the above, instead having a flat, consistent vision of dependencies. NPM though, allows that, allowing nested dependencies, by virtue of the ES6 module system importing to a variable in a lexical scope. Go also allows that, by virtue of its imports being scoped to a package (or file, I can't recall). Ruby has side-effectful load/require decoupled from the open class system - which is what bundler is designed around -, but can do that kind of isolation too! In fact, I've done it: https://github.com/lloeki/pak https://github.com/lloeki/pak Unless packages leak to globals each version is oblivious to the one next to it. Unless package dependents communicate with one another using objects from the packages they can happily live in their own little isolated world. Now if they do, then it's like hitting a HTTP /api/v1 with an HTTP /api/v2 client and somehow wishing things will work. Either the package (which should not leak globals / disallow cross-version communication) or the language (which should not allow leaking globals / detect incompatible communication). None of this is the responsibility of semver. In fact, semver would help the language provide tooling to detect that kind of "hey this instance is from foo-1.0 but you're trying to consume it in foo-2.0".
- Pxtl 3y agoMy approach to semver: Breaking.Planned.Hotfix.Publish Breaking is for breaking changes. Planned is for planned changes. HotFix is for emergency unplanned changes. Publish is internal, in the event getting the release out the door took multiple kicks at the build server and you still want to give those distinct builds their own tags. There's a lot of tools that are very opinionated that anything that hits public must have a distinct ID, and sometimes stuff happens and the pipeline doesn't go right on the first try.
- hasoleju 3y agoI experience the problem Pragmatic Versioning is trying to solve. For a commercial software product there are often two root causes to change the "major" number in a software product version. 1. There was a breaking change to the API. 2. The company wants to signal great new features. With pure Semantic Versioning the second reason can not be used alone. And breaking changes in the API are actually not good news for the users. I think semantic versioning is adopted broadly because great new features often also introduce breaking API changes. So that conflict does not need to be resolved. Pragmatic versioning helps solving this conflict by splitting um the "major" version number into two new ones for breaking changes and great new features. The main advantage Semantic Versioning has is that it is the default. So seeing a version tag with three numbers means Semantic Versioning today.
- pyrolistical 3y agoNo need for marketing version and dev version to be the same. Just have a mapping
- liampulles 3y agoI've seen and used marketing-led versioning for internal systems a few times. The major version is used purely for promoting team progress (e.g. Product 2.0). The purist in me balks, but the pragmatic cynic is happy to have a tool in the belt.
- yencabulator 3y agoEver since Windows 95, I've had the rule that marketing does marketing and products need internal names & versioning to avoid trouble with marketing making last minute changes.
- k__ 3y agoSimilar goal, different approach: https://gitlab.com/staltz/comver/-/blob/master/README.md https://gitlab.com/staltz/comver/-/blob/master/README.md
- spoiler 3y agoThe way I understood both makes it seem the goals are different, as PragVer is more marketing oriented. The ANNOUNCE is also a bit different than MINOR because it can also include breaking changes, as opposed to just feature additions
- noirscape 3y agoThe problem is that semver is versioning meant to make sense to package managers and downstream dependency resolution, but not to actual endusers of software. Great for libraries, less great for say, a text editor. Most people are nowadays used to versioning that's something like BIG.SMALL.IRRELEVANT, where those words basically indicate how much has been changed in a release. To the layman, "version 3 has released" usually is accompanied by the question of "and what's the new stuff that made them make a version 3". BIG doesn't necessarily have to be the first number; OS X for example does all major changes on the second number, so when that goes up, new features are expected, while the last number is reserved for bugfixes. In semver, this question is very boring - you have to bump MAJOR every time the public API changes, so most MAJOR changes don't mean much. To try and solve this, most projects have decided to just forgoing MINOR and PATCH entirely (or going for YEAR.MONTH versioning, and trying to keep breaking changes to the next year) or excessively holding back new features to then merge them all at once. This tends to result in semver software feeling... rather stagnant (or on the other side, impossible to say anything about due to constant major changes) and is why for non-libraries, I don't think semver is all that useful. Pragmatic versioning seems like a closer way for how end-user software should be versioned. There's also the fun situation going on with cargo where almost every package is still at 0.x because rust programmers love semantic versioning but want the escape hatch to do major breakage without bumping MAJOR. Which isn't necessarily indicative of the actual state of the project (most 0.x rust projects are afaict actually well maintained and ready for production use), but it does show how semver can really mess with expectations.
- rswail 3y agoSemver and this are orthogonal. Semantic versioning is about the semantics of an interface (rest or otherwise). This is about the version of the underlying implementation. “LTS” of a semver api is driven by backwards compatibility, so it’s the second section (1.2 vs 1.3). Declare the “not before” and “not after” of the semver and you have effectively defined lifetime.
- rswail 3y agoFor my rest apis I define a fixed endpoint /versions that returns an array of json objects that looks like: { “version”: “1.2.3”, “href”: “https://host/1.2.3”, “not_before”: “2000-01–01T00:00Z” “not_after”: “2025-01-01T00:00Z” } The array lists the available versions of the api and the endpoint to use. Not before/after can be null to indicate infinite past or future. The contract for /versions is that the client must check it once every 24 hours for changes. Allows deprecation of previous versions by changing a not after of null to a timestamp etc
- 2d8a875f-39a2-4 3y agoI think that how people feel about versioning tends to correlate with their attitude towards making breaking changes to their interfaces. Some people DGAF and want to move fast and break things. They want a versioning scheme that prevents pesky end users from complaining about stuff that is now broken. Some people will go to unreasonable lengths to avoid incompatible changes. They want a versioning scheme that makes it hard for the first group of people to break stuff. These two groups will never agree on a versioning scheme.