Hacker News new | past | comments | ask | show | jobs | submit login

Except in practice in all real software (including the go language!) minor and patch versions break importers all the time in small ways, AND major versions are usually used to indicate significant new features, not just breaking changes.

So your claim is reduced to ‘I don’t want v1 to break my software in ways that the dependency finds important enough for a major version’.

Not quite as reassuring is it?

Plenty of security fixes and undefined behaviour fixes break importers all the time, and often importers and exporters disagree about the severity of that. Sticking with v1 will not save you that pain.

I preferred the situation before where there was strong social pressure never to break the main branch.




This is a cultural issue.

It's not inevitable that by developing a module over time that you constantly break compability AND you want all people that depend on you to upgrade version.

Go encourages the opposite approach.

If your API is not stable, don't publish a package for public consumption, or, make sure to clearly mark it as unstable, so people know what to expect.

One of the absolute best features of Go is stability. If I have a project written a few years ago, I can always run it against the latest Go compiler and know that it will still work.

Why does this matter? I'll give you a counter example.

In 2016 I wanted to work on a mobile application project and I just picked React Native because I heard it lets you easily create cross platform applications.

I worked on it for a few weeks, then left it for about two or three months. When I tried to pick it up again, I installed the latest versions of node and npm and upgraded all packages.

The project stopped working. I had no idea what went wrong. The error messages were obtuse and several layers deep. I tried to debug it for weeks to no avail.

As a result, I abandoned the project and built just an Android version using Kotlin and Android Studio.


> I installed the latest versions of node and npm and upgraded all packages.

Laughter of recognition from this side. I am working on an application that has a tiny bit of Web UI. Basically one button, "Yes, I want this thing" and some text that guides the person staring at the button to decide if they in fact do want this or don't. I didn't write any of that code, and my Javascript knowledge is pretty rudimentary, but hey it's just a button right?

On Monday I'm sat (virtually) with the guy who wrote that part, pair programming the dependency injection stuff so that this button can actually cause stuff to happen. It builds and runs fine on my machine, we make lots of progress. During the week I focus on other parts of the system (including a red herring where we're convinced for an hour we have a DST Root CA X3 expiry issue but it's actually a syntax error in a Puppet file on the in-house node classifier), but on Friday we're ready to check the current state. However the guy who wrote the button code is out. No problem though right, I understand the larger system, just hit build?

Nope. I get a JSON parsing error, which, it turns out, is how npm or node communicates "I am the wrong major version" because of course it is. Incremental improvements to a single page with a button on it had resulted in needing a newer major version in less than one week.


It certainly is a cultural issue which is why it shouldn’t be enforced by tooling!

I also completely agree about the value of stability, which is why I don’t like this change which paradoxically encourages more churn (normalises v2,v3 etc for breaking changes, normalises large breaking changes and rewriting apis).

All APIs are slightly unstable in some sense (even adding fields can be a breaking change), so the aim should be to minimise version bloat and breaking changes and provide stability for importers, which the go language has done an amazing job at for the last decade.

To give you a counter-example the sengrid api in go has had multiple large breaking changes/rewrites and has used this v2/v3 etc scheme. It’s still a horrible experience as an importer and I’d rather they remained stable instead of introducing massive churn with the cop-out that the old unsupported version didn’t change.

In dependencies I import I want a perpetual v1 which doesn’t change over a decade and just slowly improves, not v31 - new improved rewrite this year! Which this rule explicitly encourages.


> All APIs are slightly unstable in some sense (even adding fields can be a breaking change)

Of course adding fields is a breaking change. It has never ceased to astonish me how little most programmers understand compatibility, I remember wrestling with libpng getting them to understand that e.g. no, "tidying up" the order of fields in a public structure you've published isn't safe back in the 1990s before they came to god and actually provided sane APIs which hide internal data structures.

Now, it's true that Hyrum's Law means any detectable change, even if it was never documented, will break somebody if there are enough people depending on your system. That's a big deal if you're the Linux kernel, or the HTTP/1.1 protocol, as it means even trivial "this can't break anything" fixes may break stuff. For example, as I understand it Google once broke search in Asia by changing an internal constant so that a hashmap would re-allocate (thus invalidating pointers to items in the map) slightly earlier. C++ code relying on pointers to just magically stay valid across inserts was completely wrong before they broke it, but anybody staring at a 500 page on google.com doesn't care why it broke they just want it fixed.

Most of us needn't much worry about Hyrum's law. That would be, as an old boss repeatedly told us, "A good problem to have" because it means you're having enormous impact.


> In dependencies I import I want a perpetual v1 which doesn’t change over a decade and just slowly improves, not v31 - new improved rewrite this year!

> Which this rule explicitly encourages.

I agree with the first part (I'd much prefer having a MyFunction2 in a package if necessary, than a breaking change to the package itself).

But my takeaway from the design was the exact opposite - that it discourages breaking changes, by making them a little less convenient, and that the purpose of the feature was to allow major versions to simultaneously exist to avoid build issues [1]. I think I got that impression by reading the long articles that the team lead put out about the design decisions [2], and observing that the standard libraries themselves rarely break compatibility.

Unfortunately watching various discussions some people do feel encouraged to put out new major versions since upgrades are "solved" (even though that's only from a build system perspective, you're still causing client churn).

[1] https://research.swtch.com/vgo-import

[2] https://research.swtch.com/vgo


Two problems here:

Major version nos are not in practice used for breaking changes but more usually for new features.

The unintended consequence is to make it more acceptable to add breaking changes and force upgrades to stay current.

It’s not a huge deal though and I’m interested to see how this decision works out. Personally I think it is none of the package managers business.


The problem here is that we add too much extra meaning to version identifiers. In semantic versioning, if you're at 1.38 and want to release a cool new version with many cool features and a much faster engine, while still retaining backwards compatibility, you're stuck with releasing a 1.39. If you call your new version 2.0, you signify that it's backwards incompatible.

We should have two differently-looking version identifiers, one for compatibility-tracking purposes and one for signifying the scope of changes to humans. The compatibility version numbers could look like 2ah4, where the first number is the major version, the letter (or series of letters) is a minor, increasing alphabetically and going to "aa" after "z", and the last number is a patch.


I think they are always fuzzy and that’s fine, as long as tooling doesn’t make incorrect assumptions about meaning.

Different exporters and importers have different stability requirements and expectations - it’s negotiated.




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

Search: