News for hackers. Stuff that matters.
Re:A strong commitment to backwards compatibility means keep... by WhyNotHugo on Tuesday June 15, 2021 @05:54AM (#27513095)
The reality is that you have to be sensible and balanced.

You can't keep BROKEN functions "because people rely on them", but you can't suddenly make a minor release (e.g.: from 2.3.4 to 2.3.5) completely changing the semantic of a feature you expose.

You need to:

- Avoid changing APIs just for the sake of change.

- Announce breaking changes.

- Document how users are intended to migrate from your old API to the new one.

Very large projects like Django do things like:

- v2.0: Adds a new API, but keeps the old one

- v3.0: Removes the old API.

This gives consumers of the API plenty of time and margin to experiment with both and move on.

If a single release changes too many things, it's very hard for a developer to upgrade, since they have a completely broken codebase, and need to fix multiple breakage at once.

Re:A strong commitment to backwards compatibility means keep... by okamiueru on Tuesday June 15, 2021 @07:54AM (#27513957)
Most of what you touch on is covered by semantic versioning. (https://semver.org), and IMO should be mandatory reading by anyone in software development.

It sort of looks like you are sort of aware of it, but maybe not entirely. What you called a minor version is typically called a "patch" version. So it goes. MAJOR.MINOR.PATCH

Major version bump can change anything. Minor versions are generally safe to upgrade, but will change the api in a backwards compatible way. Patch version updates make no change to the api.

One of the worst things to deal with is libraries for which maintainers have broken the semver contract.

Re:A strong commitment to backwards compatibility means keep... by ahartmetz on Tuesday June 15, 2021 @08:23AM (#27514221)
Qt is exemplary in that. There are ironclad rules that only MINOR adds new features and only MAJOR breaks API. And PATCH is strictly for bugfixes.

Binary compatibility is guaranteed as well so that an application compiled against 5.0.0 will dynamically link against 5.15.2 and run fine unless it relied on clear bugs.

There are exceptions for things like input method plugins, for which one needs to explicitly opt in to using internal API with build sysem flags. Without the opt-in, the corresponding private headers are not accessible.

Re:A strong commitment to backwards compatibility means keep... by humanrebar on Tuesday June 15, 2021 @09:38AM (#27515336)
The biggest problem I have with semver is that we don't have good enough tooling to reject minor or patch version bumps when major version bumps are actually warranted. I'm not sure it's possible to have that thorough of analysis in general.

Semver is handy for understanding what the maintainer meant to do. I guess in a lot of circumstances that's not nothing.

Re:A strong commitment to backwards compatibility means keep... by account42 on Tuesday June 15, 2021 @09:47AM (#27515473)
> The biggest problem I have with semver is that we don't have good enough tooling to reject minor or patch version bumps when major version bumps are actually warranted. I'm not sure it's possible to have that thorough of analysis in general.

The biggest problem with automated tooling is that there is a nontrivial subjective component to this. If you look at things strictly, any bug fix that changes externally observable behavior can be a breaking change - but bumping the major version for every release defeats the purpose of SemVer.

Re:A strong commitment to backwards compatibility means keep... by okamiueru on Tuesday June 15, 2021 @02:41PM (#27519692)
If the change actually breaks existing use, then bumping the major version of every such release is *exactly* the purpose of SemVer.

One important note that is often overlooked, as it isn't part of the short SemVer summary, is that major version 0 is special. The rules for minor and patch versions do not apply, and anything can change at any time.

In other words, a project and library can explore its API freely and make as many wild changes as it pleases. Once it matures, it can be made 1.0.0, and the whole point of doing so is to communicate that the rules of major, minor and patch version bumps can be expected to be followed.

Re:A strong commitment to backwards compatibility means keep... by maweki on Tuesday June 15, 2021 @09:11AM (#27514854)
You have to define the notion of "backwards compatible" though, as this is the core of semver. To be strict, a bugfix is not backwards compatible. You explicitly change the behaviour of a function or interface.

There's an interesting paper on checked semantic versioning [1] and you will get a new MAJOR version if you don't explicitly add the NOCOMPARE-pragma to a bugfix, as the prover (obviously) can not show the original function and the bugfixed function to be equal (usually they are not for some input).

Backwards compatibility is hugely in the eye of the beholder (Hyrum's Law). So this is not a cut-and-dry issue.

[1] https://drops.dagstuhl.de/opus/volltexte/2018/8456/

Re:A strong commitment to backwards compatibility means keep... by okamiueru on Tuesday June 15, 2021 @03:11PM (#27520092)
I think the underlying assumption here is that this is versioning for humans (and package managers). It isn't 100% ironclad and fool proof. It really only tries to make the job better/easier for those who rely on other libraries by baking in an educated answer to the following question:

> If I upgrade the library from X.Y.Z to A.B.C, what can I expect to have changed, and to what extent do I need to do anything after I make the upgrade to make my code work the same?

I don't find it interesting that, technically, any observed change to the library can potentially break code. If I use reflection to branch on number of methods available, a bump in minor version can introduce a method to the API, and thus break my code. Making an observation of this is one thing, naming it after one self is a tad on the egotistical side.

Other than that, I agree completely that the difficult part is defining what "backwards compatible" really means. However, to be clear, changing behavior is not the same as being backwards incompatible. I expect bugfixes to make my code function more correct and more reliably. I can reasonably expect minor versions to add functions or features that don't get in the way, and I can expect nothing from major version upgrades, so those will always need to be done with some extra care.

Re:A strong commitment to backwards compatibility means keep... by cecilpl2 on Tuesday June 15, 2021 @10:06AM (#27515712)
https://medium.com/@xzyfer/why-node-sass-broke-your-code-and...

What do you think of this example, where a library made a breaking, non-backwards compatible change, causing user code to throw fatal errors.

They defended their point that this is only a minor version increment since the working user code was actually erroneously working and should have been throwing fatal errors the whole time.

Re:A strong commitment to backwards compatibility means keep... by okamiueru on Tuesday June 15, 2021 @02:37PM (#27519625)
Versioning is always a little bit tricky. First of all, it depends what you are versioning. If it is an API (be that web-api or programmatic API through a public interface), then semantic versioning is exceedingly useful, and how to go about it is less ambiguous.

To address the issue you linked to, it really doesn't matter if it is a bug-fix or not. Semver 2.0 describes PATCH in the summary as

> PATCH version when you make backwards compatible bug fixes.

And the words backwards compatible are key. If it isn't, it doesn't matter that it fixes a bug or adds a breaking feature. If the code will break for your users unless they change their code, then you cannot fix it by bumping the PATCH version.

Now, semantic versioning isn't the end all be all. There are other versioning schemas that suit some developments. But, if there is a pretense of actually following semantic versioning, then the argument presented in defense really isn't relevant. Bumping the major version isn't something holy and beyond reproach. Just use it for what it is intended. Package systems very often rely on semver being followed. Does the new version break existing use? Then bump the major version. That's the responsible thing to do, and it should only be met with understanding.

To quote SemVer 2.0:

> 6. Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible bug fixes are introduced. A bug fix is defined as an internal change that fixes incorrect behavior.

Re:A strong commitment to backwards compatibility means keep... by WhyNotHugo on Tuesday June 15, 2021 @10:31AM (#27516055)
If it broke the exposed API, it should not be a minor.

It doesn't matter if it's "by design" or not, people still rely on it and semver is how you communicate the breakage to them.

Re:A strong commitment to backwards compatibility means keep... by joshuamorton on Tuesday June 15, 2021 @12:12PM (#27517531)
Per hyrums law, this would mean that essentially all changes should result in a major version bump, which defeats the purpose.
Re:A strong commitment to backwards compatibility means keep... by okamiueru on Tuesday June 15, 2021 @03:23PM (#27520233)
It also makes "Hyrum's Law" pretty useless, doesn't it? Who names something like that after themselves? Well, I know at least one such case.
Re:A strong commitment to backwards compatibility means keep... by joshuamorton on Tuesday June 15, 2021 @04:35PM (#27521150)
> It also makes "Hyrum's Law" pretty useless, doesn't it?

Not really. Hyrum's law is descriptive of reality and borne out of experience trying to update/change things. The point of it is to remind you that even when you think you aren't breaking things, you probably are breaking someone's workflow, and that your API surface is much larger than you think it is (performance, threading, ordering characteristics, etc. are all things that your dependencies will routinely rely on).

> Who names something like that after themselves? Well, I know at least one such case.

He didn't. Titus Winters probably deserves credit for the name. Hyrum deserves credit for the observation.

Re:A strong commitment to backwards compatibility means keep... by okamiueru on Tuesday June 15, 2021 @06:32PM (#27522439)
He sure makes no small attempt at marketing the term, and himself https://www.hyrumslaw.com/

In any case, my point is that it this observation has no relevance on the applicability of semantic versioning. One is a practical approach at making the best out of versioning. The other is a rather simple observation that given sufficient enough users of an API, all parts of the API will be depended on by someone.

To go and suggest that the logical extreme of a though experiment that, any change (bug fix or what have you) on an API, and given wide enough usage, will change/break something for someone, should somehow conclude in a defeatist mentality of "what's the point, everything becomes a major version", is... in my honest opinion, as uninteresting of an observation as they come. I'm sure it has more interesting applications elsewhere.

But then again, maybe I don't get what is supposed to be profound, or applicable, and I'm all ears.

Re:A strong commitment to backwards compatibility means keep... by joshuamorton on Tuesday June 15, 2021 @07:52PM (#27523129)
> One is a practical approach at making the best out of versioning.

I think the observation is that this is sort of going to inevitably fail, and people will get mad at you anyway (perhaps more mad than if you didn't have any semver promise to begin with).

Right, like say you maintain a library and refactor something in a patch version bump. It affects something that isn't a documented aspect of your api, but is nonetheless something I depend on. I complain to you that you broke me with a patch upgrade. Well who is right? You did break me. Should I continue to trust you? Should I pin to a patch version (this makes semver useless)? Should you take more care to not break observable behaviors? How can you even know which behaviors are depended on, many will be unknown unknowns!

The ultimate conclusion from this approach is that for a widely enough used api, you will always break someone, so you need to ship a migration story instead of a change, or you need a way to assert that your change won't break any of your users, which short of being able to run all of your dependencies tests isn't possible. This can be achieved in a corporate world, but not in the OSS world. And so yes, one of the fundamental truths of software engineering is that semver is fundamentally broken. It may be the best thing we've got, but it's absolutely not a magic pixie dust. You will still break your dependencies, and your dependencies will still break you, and you should prepare for that, semver or not.

> He sure makes no small attempt at marketing the term, and himself https://www.hyrumslaw.com/

Yes, and? It seems odd to drag someone for marketing themselves, on of all places, hacker news.

Re:A strong commitment to backwards compatibility means keep... by okamiueru on Wednesday June 16, 2021 @08:58PM (#27535188)
I think I'm just missing what the point of the sentiment is. You brought it up in reply to the failure to adhere to the semver contract.

> Per hyrums law, this would mean that essentially all changes should result in a major version bump, which defeats the purpose.

So, what is the point you want to bring across?

> I think the observation is that this is sort of going to inevitably fail, and people will get mad at you anyway (perhaps more mad than if you didn't have any semver promise to begin with).

Yes, and? It has absolutely zero impact on the applicability of semantic versioning, its purpose, and its utility. Nor do I find this observation particularly novel, or surprising. Are you suggesting to do away with semver, because a patch update given a theoretical "enough usage", will break for someone? We already have that granularity, just lock the version you use to the exact patch, and you're good. That way, you treat any change as a potential braking change, and the end result of this defeatist attitude is covered.

> The ultimate conclusion from this approach is that for a widely enough used api, you will always break someone, so you need to ship a migration story instead of a change, or you need a way to assert that your change won't break any of your users, which short of being able to run all of your dependencies tests isn't possible. This can be achieved in a corporate world, but not in the OSS world. And so yes, one of the fundamental truths of software engineering is that semver is fundamentally broken. It may be the best thing we've got, but it's absolutely not a magic pixie dust. You will still break your dependencies, and your dependencies will still break you, and you should prepare for that, semver or not.

And again, this is just beating the same dead horse. What's the actual point in relation to semantic versioning? Semantic versioning is not "fundamentally broken", that conclusion is ridiculous. Semantic versioning an engineering best practices. These things, and "logical thought experiments" rarely agree with each other. Suggesting this is therefore fundamentally broken, with not a single clue given as to how to improve it, is what I'm referring to as a defeatist attitude. A "best effort" must improved with a "better effort". So far, I've just seen "meeh, what's the point".

> Yes, and? It seems odd to drag someone for marketing themselves, on of all places, hacker news.

I'm not dragging them for marketing themselves. I'm annoyed about the triviality of the "observation" being referred to as a named law, in a contrived attempt at credence. It doesn't help to then see this used as attempting to make a point it has no grounds for. Not every xkcd observation needs to be coined by someone and called a "law".

Re:A strong commitment to backwards compatibility means keep... by beckingz on Tuesday June 15, 2021 @10:47AM (#27516292)
What if it counts as a bug fix?
Re:A strong commitment to backwards compatibility means keep... by squeaky-clean on Tuesday June 15, 2021 @11:23AM (#27516814)
I ran into this recently, I'm sure many others did too (I'm not the issue poster).

https://github.com/eventlet/eventlet/issues/702

https://github.com/benoitc/gunicorn/pull/2581

While the bug does seem pretty critical for websocket users, the patch-version-change ended up breaking any application that uses gunicorn with eventlet (even if you don't use websockets).

It feels slightly like my fault, because eventlet has been at v0.x.x for 9 years now. I used to be a bit hesitant about using anything that couldn't declare a version 1.0.0. I guess I've learned my lesson and just won't use any v0 library except in hobby projects now.

Re:A strong commitment to backwards compatibility means keep... by dagw on Tuesday June 15, 2021 @11:05AM (#27516536)
It really depends on the bug? If it is a bug that causes your program to crash or return obviously invalid output then it's probably OK to fix it. But if the 'bug' does something useful that just happens to be undocumented or contradicts the documentation, then you need to be a lot more careful about 'fixing' it. Especially if it's clear that lots of people are relying on that bug as a feature.
Re:A strong commitment to backwards compatibility means keep... by TheCoelacanth on Wednesday June 16, 2021 @11:47PM (#27535969)
Only "Announce breaking changes." is covered by semver.

A library that makes a breaking change every week could be following semver if it bumps the major version every time, but they are not taking backwards compatibility seriously.

Re:A strong commitment to backwards compatibility means keep... by account42 on Tuesday June 15, 2021 @09:44AM (#27515439)
I think GPs main point is not covered by semver at all - namely to not break anything out of the blue but have a transition period where API consumers can upgrade at their own leisure.
Re:A strong commitment to backwards compatibility means keep... by okamiueru on Tuesday June 15, 2021 @02:19PM (#27519389)
I do not know what GP is short for, apologies if I'm missing your point in my reply.

One, if not the most important part of semver is communicating the nature of the changes, and in particular, how that change affects the use.

I once used a library/tool that would detect vulnerabilities. The maintainers thought it would be a good idea to turn it in to a paid service, and a minor version upgrade caused it to fail silently due to lack of a token. When I noticed it by coincidence, I raised the issue of it not being communicated properly, and they said they had made every effort at raising awareness about the change through blog posts, twitter, etc. However, few people really subscribe or follow this kind of feeds. The change that came as an increment in minor version had IMO broken semantic versioning. If it instead had been followed, it would have communicated exactly that some care when upgrading was necessary, and allowed the API consumers to upgrade at their own leisure.

Re:A strong commitment to backwards compatibility means keep... by account42 on Wednesday June 16, 2021 @04:05AM (#27526088)
> One, if not the most important part of semver is communicating the nature of the changes, and in particular, how that change affects the use.

Yes, SemVer communicates breaking changes, but only after they have happened. The point is that you should have a migration path ready long before the old API is no longer available.

Re:A strong commitment to backwards compatibility means keep... by okamiueru on Wednesday June 16, 2021 @06:56AM (#27527051)
What do you mean by "after they have happened"?

The changes to an updated library don't affect you until you have upgraded to that version. The whole point of semantic versioning is to allow you or package managers you use to limit which libraries to update. So, semver is to let you know of braking changes exactly before they would happen, because until you actually upgrade the library, the change hasn't happened. Surely this makes sense? Maybe we are talking past each other.

Re:A strong commitment to backwards compatibility means keep... by dgb23 on Tuesday June 15, 2021 @07:26AM (#27513720)
Depends on what you mean with "BROKEN". Breaking changes actually break other people's code, tutorials, documentation, tooling and developer knowledge often for very questionable gains.

There are many projects that are relied on by thousands, but they keep pushing breaking changes on a regular basis without providing tangible improvements. This is especially true for tooling, frameworks etc. for web development.

Re:A strong commitment to backwards compatibility means keep... by dTal on Wednesday June 16, 2021 @05:54AM (#27526699)
Hypothesis: this is especially true for corporate-sponsored open source where the devs also sell consulting services - i.e. "freemium" - because their incentive structure does not encourage making things easy to use without their services.
Re:A strong commitment to backwards compatibility means keep... by MaxBarraclough on Tuesday June 15, 2021 @06:48AM (#27513425)
> This gives consumers of the API plenty of time and margin to experiment with both and move on.

It's not a silver bullet though, as we saw with the move to Python3. It annoyed people with large Python2 codebases, giving them the choice between:

• Laboriously reworking their code to transition it to Python3 (a language with only limited advantages over Python2)

• Using an unsupported language for a significant codebase

Re:A strong commitment to backwards compatibility means keep... by WhyNotHugo on Tuesday June 15, 2021 @07:05AM (#27513570)
Python 2-3 is a great COUNTER example of what I'm saying.

There was no intermediate release that could run both python2 and python3 code.

It introduced new features AND removed the old ones all at once.

Re:A strong commitment to backwards compatibility means keep... by MaxBarraclough on Tuesday June 15, 2021 @08:07AM (#27514074)
> There was no intermediate release that could run both python2 and python3 code.

Right, but would that have helped? Transitioning a large codebase from Python2 to Python3 is a significant undertaking, there's no way around it.

As I understand it there are dedicated tools to help migrate Python code, but it's still no small thing if you're dealing with a large codebase. Perhaps it would have been helpful to have an interpreter that supported the union of both languages, but I don't see that this would have changed things from significantly costly down to no big deal. It would make the process more incremental, but it would still represent significant work. There are legitimate reasons people don't want to have to modify large stable codebases.

(To be clear, I haven't had to do this personally, but that seems to be the sentiment of people who have.)

C++, on the other hand, goes to considerable lengths to preserve backward compatibility, at the cost of accumulating complexity.

Re:A strong commitment to backwards compatibility means keep... by kevincox on Tuesday June 15, 2021 @09:21AM (#27515018)
It would have helped immensely.

The main issues with the upgrade is that:

1. Libraries needed to maintain both versions (or code compatible with both.

2. Projects couldn't upgrade until their dependencies did.

If Python 3 could run old code (for example you needed to write `import py3` at the top of a file to switch) then all projects could have updated their code in parallel, there would be no (or minimal) work to maintain support for old versions and everyone can update to py3 the day it came out. The workflow then looks like this:

1. Everyone updates to Py2.9 which supports the old features and the new features.

2. Everyone migrates their code to use the new features and remove deprecated features independently.

3. Py3 comes out and drops support for the old stuff.

1 is not trivial, but it is equivalent to any other time that you drop support for old versions, this happens regularly and isn't a huge event.

Compare that to the nasty wave of updating dependencies and requirement to continue supporting old versions, especially since the code to support multiple versions was fairly awkward for a lot of projects.

Re:A strong commitment to backwards compatibility means keep... by jeltz on Tuesday June 15, 2021 @09:29AM (#27515163)
It helped for Ruby. Ruby released 1.8.6 and 1.9.1 which were both two intermediate steps between Ruby 1.8 and 2.0. 1.8.6 beibg similar to 1.8.4 but with many added 2.0 features and 1.9.1 which was almost 2.0 but with some deprecated features in it.

I got to experience both and the Ruby 2 migration was much smoother than the Python 3 one.

EDIT: To be clear, Ruby did not make it literally possible to run both 1.8 and 2.0 in the same code base but with just a few conditional statements and avoiding to use non-backported 2.0 features it was easy to write libraries which could run in both 1.8.6 and 1.9.

Re:A strong commitment to backwards compatibility means keep... by gwoplock on Tuesday June 15, 2021 @09:29AM (#27515179)
> Right, but would that have helped? Transitioning a large codebase from Python2 to Python3 is a significant undertaking, there's no way around it.

I haven't migrated from python2->3 however I've worked on projects in both. I think a "python2+3" version would have helped. With both APIs in place new code can be written the new way and old code can be migrated as it is touched. Having the ability to incrementally change code I think encourages the transition since you won't end up with a pile of broken code.

Re:A strong commitment to backwards compatibility means keep... by PeterisP on Tuesday June 15, 2021 @10:45AM (#27516254)
You could transform your 2.x code so that it would run on both 3.x python and also on recent 2.x python versions, using new features with appropriate `from __future__ import` statements; so in that regard the latest 2.x versions were those intermediate releases that could also run 'new style' code. I had a bunch of internal code that would run on both 2.x and 3.x python, and many libraries also did just that.
Re:A strong commitment to backwards compatibility means keep... by jnxx on Tuesday June 15, 2021 @02:02PM (#27519128)
So why does the Python Wiki runs Python 2 with MoinMoin Wiki? You seem to imply it is easy and quick to rewrite software to match it to new versions, and resources for this are always available?