Hacker News new | ask | show | jobs
by eridius 3468 days ago
If you're using a proper type-safe compiled language then most "subtle" breaking changes can't possibly be missed because your code won't compile anymore (assuming you used that API to begin with). You don't need a major version number to call attention to the fact that one parameter of one method changed from a boolean flag to a set of options, anyone who's using that method will find that out pretty quickly.

The main reason semver is done the way it is is so you can do things like have package managers automatically pick the latest compatible version, since incompatibilities are denoted by the major version number. That's why I'd prefer major.breaking.minor.patch, because you can still have the package manager automatically detect compatible versions, but you don't end up in the crazy land of releasing a library at v27.

2 comments

> If you're using a proper type-safe compiled language then most "subtle" breaking changes can't possibly be missed because your code won't compile anymore (assuming you used that API to begin with). You don't need a major version number to call attention to the fact that one parameter of one method changed from a boolean flag to a set of options, anyone who's using that method will find that out pretty quickly.

1. What if it's a dll, .so? You upgrade and find out that your program is broken.

2. Sometimes the API stays the same but the code behind the API changes a result (for example, secure_hash goes from MD5 to bcrypt)?

3. What about non-type safe languages (like HTML or JS, so things like Firefox or Chrome)?

The point is that you should avoid breaking other people's code if you can. What happened if that removal of one function in that one module costs me a full years of work?

Sometimes you can't help yourself. PHP had register_globals. Some people were able to use it safely (initialize all variables before use), but PHP rightfully realized the security implications and disabled it. However, it broke code, and a lot of it.

These are things you should think about and heavily before breaking code. It may be one line for you, but for all the millions of people who use your library it could be thousands of man-years of work.

> What if it's a dll, .so? You upgrade and find out that your program is broken.

If it's not backwards-compatible then it needs to bump the appropriate version number (in my proposal, that would be the second dotted component). So I'm not sure what you're trying to say here.

> * Sometimes the API stays the same but the code behind the API changes a result (for example, secure_hash goes from MD5 to bcrypt)?*

If it's a non-backwards-compatible behavioral change then maybe you need to design your API better such that this kind of change is expressed in the API. After all, if you expect anybody to ever upgrade to your new bcrypt version, you need to provide some path for people to still work with their older MD5 hashes anyway.

> What about non-type safe languages (like HTML or JS, so things like Firefox or Chrome)?

Not something I particularly care about. Though it doesn't really matter anyway; even if you think the breaking change number is too "subtle", anyone who's manually upgrading to a new version instead of letting their package manager do it should already be prepared to deal with breaking changes, because if there aren't breaking changes then their package manager should have been happy to upgrade without any manual intervention.

> The point is that you should avoid breaking other people's code if you can. What happened if that removal of one function in that one module costs me a full years of work?

I have no idea what point you're trying to make here. My suggestion was just about changing the format of the version number, and has no bearing whatsoever on the actual breaking changes you do or don't introduce. I'm certainly not advocating for removing functionality.

I think, and correct me if I'm wrong, but I think he's saying that semver's system that forces major version bumps for breaking changes is good because it discourages the maintainer from making breaking changes more frequently than he is comfortable releasing a new major version. That is, the effect of getting a maintainer to batch up breaking changes in exchange for version consistency is positive, and thus semver should not be changed as you propose, because it would decrease the cost of releasing a breaking change.
There's still a cost associated to releasing a breaking change, which is users have to manually upgrade, their package manager won't silently upgrade for them. So if I release a breaking change, I know any bugfixes included in it or later builds will take a while before they end up in the hands of users, because most people tend to put off dealing with breaking changes until they have time to actually investigate the changes.

But with my proposal, users can see that the breaking change is a "minor" one, and therefore they don't need to be prepared to learn about a bunch of big changes in order to upgrade.

That is even worse, because now you have to look at two numbers to see if something's breaking or not. If you change the API, you bump the major. If you don't want to bump the major, then either figure out a way to do it with the original API, such as a different number of arguments, or put that module in a package that can be installed seperately. Given your original example, you may have package Foo 1.0 which includes subpackage Bar, but you have subpackage Bar 2.0 which people can install separately if they need to. Bumping the major tells people straight out that things have changed. Two majors means that people have to keep track of two numbers for that -- can you tell at a glance if 54.32.593.3 is compatible with 54.33.594.4, for example.
With my proposed version scheme, you won't ever get 54.32.593.3. That's kind of the whole point. So instead you'd be comparing 1.2.1.1 and 1.3.0.2, which is a lot easier to read.
The point of Semantic Versioning is to tell you something.

So let's say you have Compiler 5.3.2

It means that the important thing is compiler #5. Upgrading from 4 to 5 is a _Big Deal_. You may have to rewrite all your code.

Within 5, you have a version 3. 3 has features A,B,C which 2 doesn't have. Most additions go there. So it should be safe to upgrade.

Within that, you have bugfix #2. That _should_ always be upgraded, unless you rely on undocumented features.

So it's easy for me to tell if I should upgrade.

So upgrading from Apache 1 to Apache 2 may brake config scripts and .htaccess files. Don't upgrade on production build.

Upgrading Apache 1.1 to 1.2, See README, Should be fine, do a small test on your testing machine.

Upgrading Apache 1.1.2 to 1.1.3. Probably a security fix. Do so. Immediately.

---------

The OP's numbering system doesn't tell me anything. should I upgrade 5.4.3.2 to 5.5.0.0? Will it be safe? Probably not. You may have to schedule a full testing load just to be sure.

What about from 5.4.3.2 to 6.4.0.0? Same thing. You have to do a full testing.

And if you _really_ break old code, do everyone a favor and rename your project (So, no, please don't call Go C++ V.13 or something)

You seem to be very confused. Upgrading from 5.4.3.2 to 5.5.0.0 with my scheme is no different than upgrading from 54.3.2 to 55.0.0 with traditional semantic versioning. I'm not suggesting any change to the actual model of semver, I'm literally just saying that I want to tack a new component on to the front for human consumption purposes.
In a library, breaking releases should be far fewer than "regular" feature releases. My point is that if you break code more than a few times in the history of your library, you'll get a revolution. For example, see Python 2->3, which was a relatively "small" fix (which just happened to affect pretty much half of existing string processing code), and PHP, where they seem to introduce and then turn around and remove those features every couple years (mysql, no, mysqli, no, PDO? Are we there yet?)
There's a big difference between massive sweeping breaking changes, and small breaking changes. What I care about is the ability to do smaller breaking changes, and the new "major" version number that I tacked onto the front is to signify the large sweeping changes instead of the smaller breaking changes.
As a consumer, that first number becomes irrelevant if it's not the "is this going to break my shit?" number. Why have it? It's not communicating something useful to me. Cut it.
But it does communicate something useful! It tells you "this isn't a huge change, it's a minor change that just happens to break backwards-compatibility in some fashion". Most products reserve major version number changes for when there's particularly large or important changes to the product. Committing to semantic versioning means losing that. The upside is your package manager knows when it's safe to silently upgrade. The downside is the actual humans looking at your product have no idea which versions they need to actually do some work to support, versus which ones just have minor breaking changes that may not even affect them.
In Semver the first number is not "is this going to break my shit?", it's "is it potentially breaking my shit?" in this proposed alternative the first number is "this is definitely going to break your shit", the second number is "this may break your shit, check the changelog to see if it affects you"
Sounds like using three numbers is not bad enough.