Dep: Avoiding semantic versioning sigils

Created on 14 Mar 2017  路  5Comments  路  Source: golang/dep

TLDR: please avoid semantic versioning sigils in dep syntax.

Semantic versioning sigils are extremely confusing. They're based on non-obvious meaning giving to ASCII symbols. Most programmers are not dependency manager geeks and don't remember those by hearth. They will try to make a sense of them, and many times they fail at it, writing wrong constraints, then later bite them.

The confusion is itself generated by the fact that semantic versioning is not a good match in the context of libraries, especially Go libraries. In fact, semantic versioning introduces a difference between "minor" and "patch" version which is artificial and not useful for algorithm-based processing. The only reason why there is a minor and a patch version is for marketing purposes, to advertise a release containing more features as different from one containing only bug fixes. In the context of Go libraries, it is completely superfluous, and I don't think that people are longing to express this marketing difference in their version numbers, and even less having a way for their package manager to differentiate between upgrades minors and patches versions.

When upgrading libraries, the only thing that really matters to users if whether the upgrade will break compatibility or not. So, if we think of what a programmer might want to express about upgrades and specific versions, there are 3 main things that come to mind:

  • Freeze this exact version (never upgrade)
  • Upgrade, but without breaking build
  • Upgrade to the very last version (breaking build if necessary)

So my suggestion is to drop the semver sigils and come up with a good syntax to express these 3 different intents. A possible suggestion would be:

  • dep ensure path@version: switch to a specific version of the package
  • dep ensure -freeze [path]: freeze all/single packages to version in lock file; ignore further update/upgrade commands.
  • dep ensure -update [path]: update all/single packages to the latest non-breaking version
  • dep ensure -upgrade [path]: upgrade all/single packages to the latest version, even if breaking

dep status would then show which libraries have an update available and which have an upgrade available.

feedback

All 5 comments

I want to also add a different thought that wasn't clearly expressed above.

I don't think that (Go) programmers want to declare an intent related to how to default-update the libraries they use. I don't see (Go) programmers thinking something like "ok, let me declare that I want to default-update patch releases of gorilla/mux, while for gorilla/session I will default-update minor releases`. I think they might want to declare an intent like "use this specific version that I know it works" (freeze) or even "stay on the v1 branch, I don't trust the v2 branch", but declaring intents about how to default-update libraries is not something that I reckon (Go) programmers want.

I think this is the core of the issue when using different package managers that implement sigils and sigil-based declaration of intents. When I install a library with "npm install", I mostly have no clue about the release cycle management of that library. I can only trust the maintainers not to break semver, but beyond that how can I know whether I would to default-update minor or patch releases for a library I just installed, for a maintainer that I don't know? Especially since the difference between minor and patch release is mostly philosophical, and open to different interpretations.

This is why my proposal moves from recording the intent of default update strategy, to having specific one-off update commands.

My first question for you @rasky, is do you find your self consuming packages/libraries mostly, or do you also write packages and libraries for others to use?

I'm only looking at your github, but it would seem you mostly consume packages.

Being able to express version constraints is most useful for library authors, and is only sorta useful for someone only consuming libraries. It isn't about picking a way to "declare intent about how to default-update libraries", but rather a method for allowing other libraries, to specify declare a range of versions of your library, which they support. This allows for conflict resolution, where multiple dependencies have something in common, but with different versions.

Secondly, sigils aren't great. I dislike random characters with arbitrary meaning assigned to them, but you could just as easily have keywords like "GREATER" or data structures to declare version constraints, but I don't think you would like them much better.

Sigils are really their own separate topic, and I think your bigger issue is with version constraints/ranges, but I hope I gave more context on them above.

Personally, it's the nonstandard operators that are annoying and take some learning. Using > and < would be immediately understandable.

Looking at the docs for specifying dependencies in Cargo as an example, >, <, and = are supported, and it's possible to specify the constraints from the other operators using just these (when combined with the ability to specify multiple constraints on a package, like >= 1.2, < 2.0).

Whether that's a reason to avoid tilde and caret operators is a different question.

@idubinskiy It's a necessary but not sufficient condition.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pbennett picture pbennett  路  30Comments

sdboyer picture sdboyer  路  31Comments

mastoj picture mastoj  路  29Comments

kardianos picture kardianos  路  43Comments

cpapidas picture cpapidas  路  50Comments