Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This 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.)



To 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.


> Even if an API stays exactly the same, something about what it returns could subtly change

Where I work, we call that a breaking change. If a consumer of our API codes for a particular response, and we change that response, then we could break their application.

No one wants to have to validate deeply nested objects to test if they do indeed return the thing we promised to return in our contract...


So in your world, almost every bugfix is a breaking change, right? Either that or all of your bugs affect only side effects. That seems impractical to me.


It's all about the distinction between contract and implementation.

The difference with bugfixes is that pre-bugfix the intended API contract - including behaviour, not just signature - was not respected by the implementation and post-bugfix the implementation becomes (more) correct WRT the intended contract.

IOW:

- On a semver patch bump the API contract does not change but the implementation of that contract was incorrect.

- On a semver minor bump the API contract receives an addendum, the previous contract is still in effect as a subset of the new contract.

- On a semver major bump the preexisting API contract is voided and is replaced by a new contract. The new contract may or may not include all or part of the old contract as a subset. Breaking change => major bump is an implication, not an equivalence: one is completely free to bump major purely for marketing reasons.

Of course, the difference between theory and practice is that they're the same in theory: the contract is an ideal, the implementation may come close but will always fall short in some way.

I feel like many of both semver detractors and advocates get lost in theoreticals, reality is fuzzy, just use the damn thing. Or don't and pick up another scheme, but be abundantly clear about how your versioning scheme works so that users can make sense of it and automate version requirement declarations in their dependency manager.


Great explanation.

I think the confusion over what constitutes a breaking change stems from the fact that, in practice, contracts are often very underspecified, sometimes to the point of being omitted entirely ("This function just does the obviously correct thing"). A classic example would be whether an API that munges filesystem paths should resolve symlinks or not -- if this is unspecified, then changing that behaviour is technically not a breaking change, but is likely to upset some fraction of your users, who may have even done some experiments to find out what the code does, and assumed that that undocumented behaviour won't change.

(This is not an argument against semver at all -- just an observation that contracts are hard, and mostly need to be much more detailed than they typically are, and this "detail gap" seems unlikely to ever completely go away.)


> A classic example would be whether an API that munges filesystem paths should resolve symlinks or not -- if this is unspecified, then changing that behaviour is technically not a breaking change

Another example would be Ruby 2.4 changing String#upcase & friends from handling ASCII only to being unicode aware with a new argument to override and changing the default. Technically a breaking change but actually silently fixes a ton of bugs.


> 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).


It 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.


> 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.


Exactly - 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.


In other words, Hyrums Law[0] in action.

[0]: With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.


And remember “we” is often you, the maintainers of the packages you rely on, the maintainers of the packages that they rely on, the maintainers of the packages that THEY rely on… All need to have lock-step agreement about what a “breaking” change is, and all need to have communicated it clearly.

The result though is the same, semantic versioning or no: If something changed you must retest. This is why all that’s needed is a “do I need to retest?” flag. Major/minor/patch is irrelevant if you need to keep things working.


Which is why I would give this versionong scheme the name "honest versioning". It's not following semver and it's honest about it. If all semver projects took it seriously, we'd see far more v12.0.0's and the likes. But we don't.


If a minor version only adds features then it shouldn't trip one up. That's the idea anyway.


100%

The best thing by far about semver, if accurately followed, is that it encourages strict and accurate versioning based on what changed.

I've seen teams use both approaches, side-by-side, the willy-nilly pick a version as you please group offered a significantly less stable product.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: