Live data from Hacker News

SemVer has failed us

jongleberry.com

41–50 of 52 posts

Re: SemVer has failed us

#41

I want to agree with the sentiment about the human side of versioning being unreliable, but when the author "pins" the argument on the fact that pinning all versions is "annoying" s/he loses me. Pinning (and vendoring) everything is the only way to know that exactly what you expect to be deployed will be deployed when you deploy it. Anything less is inappropriate for production environments.

You're assuming that development and production version ranges will always be the same, which is false. This is what npm shrinkwrap is for, and not pinning during production is stupid. But pinning everything in development is unnecessary until you stage/deploy.

Pinning in development is equally necessary if you hope to bring sanity to your development team all using the same codebase. Not pinning may be great for a one person 'team' or modules where you control everything, but can be a major time sink when one person is seeing a bug in a patch version they have and another developer is not seeing the same bug because they are on a newer patch. Allowing developers to "clone" consistent versions of the codebase is as important as deploying consistent versions to production.

Re: SemVer has failed us

#42
post #24

Semver is busted because it makes builds non-deterministic. Building the same code tomorrow may fail if a third party dependency publishes a change violating semver. For example: https://github.com/bower/bower/issues/1404#issuecomment-4876... I unfortunately can only complain, I have no solution to offer.

Huh? Which ecosystem advocates automatic updates and doesn't allow locking the version numbers of the dependencies until a developer manually updates them?

Systems where people seem to live under the assumption that if they don't get the latest patch updates or security updates their code will somehow be inferior and they will instantly be hacked. They think that semver will magically solve the problems of having to keep your application dependencies up to date if you want the latest changes/features/fixes.

Re: SemVer has failed us

#43
post #11

You had me until "Duplicate dependencies are bad". The reason every package manager except npm and Apple's bundles are a piece of shit is because they attempt to install random dependent garbage globally and by default.

You're assuming "no duplicate dependencies" is equivalent to "install globally", which is false. In the article's context, the argument is against duplicate dependencies per project

Duplicate dependencies affecting client side "size" is highly overrated. We can make tools (and have tools) that can compare files for same content and only include them in client side bundles only once. De-duplicating the same could should be a tooling issue. If I want to use client side modules that depend on two different versions of the same library I should be able to do this. Disk space is cheap and we can do the rest via post processing.

Re: SemVer has failed us

#44
I am not sure I agree with all of OP's argument, and I don't really care for the whole "version numbers as a marketing message" thing, but for me SemVer fails miserably when it comes to binary compatibility versus source compatibility (and don't even start on semantic compatibility...).

In languages where that difference matters, let's say Java/Scala [1], there are way too many possibilities:

- bug fix: forward and backward binary compatible; basically a drop-in replacement. Package managers are supposed to resolve conflicts between those automatically,

- new feature, but backward binary compatible; just some new code alongside the old. Package managers should also be able to resolve a conflict between dependencies that depend on different versions of those.

- bug fix: forward and backward source compatible; here we have a problem: we can guarantee developers that they won't have to edit a single line of code to migrate, but we can't allow (binary) package managers to do anything. They have to rebuild their library, which means bumping their own version number. And does that means that their new version becomes binary-incompatible with the previous one, or just their dependencies?... who knows? Maybe it depends on if the consumer of that library calls into the conflicting dependency directly or only uses it indirectly? Maybe not? Can we tell?

- new feature, backward source compatibility, but no binary compatibility; same as above: package managers cannot do anything, and conflicting transitive dependencies on the new and the old may or may not be solved by recompiling one's library. The only safe bet is to wait for the dependencies to upgrade.

- all bets are off (possibly split in minor and major): here at least we know there is nothing to be hoped. But in practice after upgrading to the new API, you are faced with the same questions concerning that thing's dependencies...

And if every dependency manager within the same packaging eco-system doesn't enforce a single global versioning scheme, how can they handle any dependency version conflict anyway? They could if packages could auto-describe their semantic versioning, so basically they can't, so they don't, and we're back to source dependencies, with recompile and bump in version number for every dependency change (ok, sometimes they do try and we get JAR hell...). And since a single versioning scheme isn't enforced, people use hundreds of different ones (or just none), and the maintainer of a library has to make all of those decisions, recursively (except that below 1 level of dependency, he/she might not be able to do anything as long as even a single dependency keeps an old conflicting dependency around, but they still have to check, in case they are lucky and can do something), taking into account the different versioning semantics of each dependency. That's madness.

So in the end, if we get a conflict between dependencies far down in the dependency tree, it becomes something pretty ugly:

- if guaranteed binary compatibility, everything is fine,

- otherwise:

0) look at that dependency's official versioning scheme, usually find nothing (except for big famous libraries)

1) pick the highest common-one, try to recompile your library

2) if it works, try the tests (your library's tests, not your dependencies' tests, mind you. Even though those should probably be run, considering they directly depend on it, and use (and hopefully test) more stuff from that library)

3a) it it works, ship it and pray.

3b) it will probably fail somewhere since the dependencies in between have not be recompiled; then you can only wait for them to upgrade.

I know in the end this doesn't work so bad (well, everything is relative...), but it still makes me sad that upgrading dependencies is still human-based trial and error.

Oh. I guess this is a rant.

[1] that's just what I am the most familiar with, but you could say the same with C packages in a distro's package repo, for example.

Re: SemVer has failed us

#45
post #25

His new versioning scheme ("ferver") is built on the premise that "people don't like it when major versions change often." Seems like a fourth version number is the solution, not breaking the semantics of SemVer. I propose 4Ver. Just add a marketing version to the beginning. Update that one whenever you want (may include breaking changes). Since you have 4 numbers, you can remove the exceptions for the 0th version as…

Could still be just 3. . .

Yeah, the downside to this is that people like to differentiate between adding features and fixing bugs, which is the minor vs. patch dichotomy. Still not a horrible idea.

Re: SemVer has failed us

#46
I (along with Natalie Weizenbaum) wrote the package manager that Dart uses[1]. It's based on semver. It's good linkbait to characterize semver as broken, but not at all true. Semver works fine when you realize what it is.

[1]: http://pub.dartlang.org/

Semver is a way to communicate between people about compatibility expectations they should have between two versions of a package. When library maintainer says "this version changes from 1.2.3 to 1.3.0" that tells something useful to a human consumer of that package.

It absolutely does not communicate anything precise in the language of machines. It's not a formal system, and compatibility isn't formally defined. If you want it to be that, you're setting yourself up for hearthbreak.

Code reuse is a social process. Understand that semver is a tool at that level and you'll be pretty happy with it. In my mind, the most important feature of semver is that by associating pre-arranged semantics to versions, consumers can specify version ranges before those versions exist.

If I'm using foo 1.2.3, I can depend on foo >=1.2.3

    Part of the major issues with semver is that patchs could
    break. A feature could be "fixed", but a consumer could 
    have relied on that very buggy feature, and patching it 
    would break their app.
This is true. One man's bug is another man's feature. If you want to be fully strict, all of the behavior of a program is significant which means you can never release anything that isn't a breaking change.

Being that rigorous isn't useful. Instead, realize that most patches don't break most users. For the ones that do, that's why you pin. You are pinning, aren't you?

    Versions 
This part is straight up annoying especially as the web moves to a world where damn near everything is do semantically version them. We just shift the numbers one to the right.

So, going from 0.1.0 to 0.2.0 is a breaking change, 0.1.0 to 0.1.1 is an API addition, and 0.1.0 to 0.1.0+1 is a patch.

It seems to work really well for us.

    The current solution to the above problems is to pin all
    dependencies. However, this is absolutely stupid and 
    annoying to me. ... When every library pins, you're going 
    to have a lot of duplicate dependencies, even if they're 
    the same version!
No no no no no.

You don't pin versions in libraries, you pin them in applications.

Almost every package in the dependency graph should be using version ranges. That avoids version lock and makes it easier to satisfy shared dependencies. It also means libraries don't all have to bump patches that just change dependency versions.

But, in your application, in the root of the dependency graph, you pin everything that you're using right now. You check that in to ensure that everyone on your team and every machine gets the same versions of all of the dependencies.

You get good code reuse and deterministic builds.

This is exactly why Bundler separates out the lockfile from the Gemspec. It's unintuitive at first, but it works better than any other system I've seen once you grok it.

There is one think in semver that I think is totally inane. The latest version of the spec says build suffixes have no relative ordering. We don't do that in pub because it makes no sense. If a user has uploaded foo 1.0.0+a and foo 1.0.0+b, which version should an application get that depends on foo? Pick randomly?

Re: SemVer has failed us

#47
post #38

SemVer isn't broken, and you already outlined the obvious solution: 1. Don't depend on 0.x.x version modules unless you are willing to accept the pain of updating versions constantly. 2. Bump major versions liberally. If enough people just get used to this reality, then everything will be fine. The problem is trying to impose artificially conceived notions of how things "ought" to work on top of this. Until someone i…

Exactly, if you claim to be following semver, and your major version is 1, 2, 3; you're probably not following semver. People have to get used to the fact that bumping the major version is not a big deal. All that it means is that there was an API update or breaking change; it may have been tiny. Chrome is up to version 38; they're doing it right.

For example, IIRC, Rails 2.3.5 introduced some API changes. That should have bumped the major version.

Rails 3.0 was a "rewrite your code" type bump; that should have been signified with a name change or other similar type of marketing codename. Rails+, for example.

I was really disappointed that Linus went with "Linux 3.0" rather than "Linux 40" as the version following 2.6.39 when he finally acknowledged that the '2.6' no longer had any meaning.

Re: SemVer has failed us

#48
SemVer makes sense as a system for versioning exposed interfaces, and for versioning products where the product is just an implementation of single, coherent interface.

When a product is not principally an implementation of a single interface, including notably the case where it exposes multiple interfaces that are somewhat orthogonal (as might be the case, e.g., with an RDBMS where the SQL language support, the TCP/IP interface, etc., are all interfaces which might sensibly be versioned), it probably makes sense to use separate semver-like versions for the individual interfaces and something else for the product.

Language implementations naively seem like really good SemVer candidates by that criteria, but the sibling comment [1] addressing binary vs. source compatibility, etc., reveals how such implementations can present multiple different perspectives that are problematic.

[1] https://news.ycombinator.com/item?id=8155501

Re: SemVer has failed us

#49
post #24

Semver is busted because it makes builds non-deterministic. Building the same code tomorrow may fail if a third party dependency publishes a change violating semver. For example: https://github.com/bower/bower/issues/1404#issuecomment-4876... I unfortunately can only complain, I have no solution to offer.

Huh? Which ecosystem advocates automatic updates and doesn't allow locking the version numbers of the dependencies until a developer manually updates them?

This particular example is javascript/Bower. A fresh clone and build of any javascript project using Bower has a non-deterministic build if it uses Bower's semver capabilites.

Re: SemVer has failed us

#50
post #5

Completely agree. For a long time, I've thought that humans shouldn't be in charge of version numbers at all. The main problem is that a human isn't reliable at determining "is this change breaking?". Unfortunately our software isn't well-specified enough to allow the computer to determine version numbers automatically yet. To make this a reality, you'd need Haskell-level type safety, along with specifying other cons…

For anyone in the Haskell world, it's obvious that semantic versioning[1] doesn't work. Some non-trivial amount of that is likely due to how horribly broken Cabal is, a problem the community remains in staunch denial of. But for the rest, one problem is that because Haskell more thoroughly specifies types, individual functions can remain the same in behavior but change in type because a bug-fix, say, fixes a record t…

Haskell's problem isn't that semver (ironically called PVP in Haskell land) is broken, it's that library authors don't care about providing stable interfaces, so the set of libraries really are not compatible.
Post reply on HN