Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Follow SemVer #2888

Closed
keithamus opened this issue Nov 22, 2013 · 27 comments
Closed

Follow SemVer #2888

keithamus opened this issue Nov 22, 2013 · 27 comments

Comments

@keithamus
Copy link
Contributor

Backbone.JS is a project with a large following, but regular "minor versions" (e.g 1.1.0) break compatibility with existing Backbone codebases.

To make it easier for developers to determine if a new version of Backbone includes backwards-compatible features vs backwards-incompatible api changes, Backbone's versioning scheme should follow semantic versioning (SemVer)

The gist of semver is as follows:

Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

This would make the existing version (1.1.0) a 2.0.0 version (as most of the changes broke existing API) which would clearly indicate to developers that the API is different, and allow developers to utilise npm's wildcard versions (e.g "1.x", "~1")

@jashkenas
Copy link
Owner

Thanks, but strictly following "semantic" versioning wouldn't work out very well for Backbone. Given that the project is almost all surface area, and very little internals, almost any given change (patch, pull request) to Backbone breaks backwards-compatibility in some small way ... even if only for the folks relying on previously undefined behavior.

If we strictly followed "semantic" versioning, it would probably be Backbone.js 43.0.0 by now — which doesn't help anyone evaluate the actual progress of the project.

So, as I like to joke — not "semantic" versioning, romantic versioning.

Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make a major new release, or significantly update and/or stabilize the API.
MINOR version when you add minor new features.
PATCH version when you make tiny changes, likely to go unnoticed by most.

This allows folks, immediately upon hearing about a new release, to get a rough sense of its scope. As to backwards compatibility — ideally every release, even major ones, are backwards-compatible. And when they can't be, because an API is changing, it should be done in a way that isn't too difficult to upgrade.

But avoiding any change to the API, and waiting for a "MAJOR" release to be ready would be a terrific impediment to progress. And the alternative of frequently incrementing the MAJOR version number is incredibly unhelpful.

Honestly, I'd prefer a simpler scheme that just used BIG.SMALL version numbers — like most desktop applications do ... but I'd worry about it breaking package managers and other tooling.

@spadgos
Copy link

spadgos commented Nov 22, 2013

What's the problem with being at Backbone 43.0.0?

  • Sent from Chrome 32.0.1700

@leadVisionary
Copy link

+1 for spadgos@ question. Version numbers are arbitrary. For some reason, we have agile web apps trying to keep within the same ranges as OSes. Many apps freak out about going past 10...but most of the projects you're modeling off of (Windows, Linux, etc) have 1 year/multi-year dev cycles before release, so 1.x -> 2.x is a big deal. An agile project moves very quickly, incrementing quickly makes sense too.

@mxriverlynn
Copy link
Contributor

I also disagree with the reasoning behind this.

Marionette is on v1.2.3 right now, and is doing it's best to follow strict semantic versioning. So far, we haven't had any issues even though we are "all surface area" as well. We've added new features. We've fixed bugs. But v1.0 is still compatible with v1.2.3. We've deferred tickets for a v2 release when they are API or expected behavior breaking changes.

Major releases with breaking changes don't have to happen every week when a pull request is accepted. These can (and should) be pooled in to major release that encompass enough value for a large release with a major version bump.

As it stands, breaking compatibility in a v1.1 release causes a lot of pain for plugin and add-on developers, like the MarionetteJS team. We had to back-fill behaviors with patches in our code, so that we can remain viable for both v1.0 and v1.1... it's not a fun situation. The ripple effects of a core library like Backbone having breaking changes, are enormous... it's not just Backbone that is affected.

@bobholt
Copy link

bobholt commented Nov 22, 2013

I agree this seems more like a case of "don't want to" rather than "can't." Breaking changes such as #2461 have no real sense of urgency, and could have waited for a major version update if you don't want the 43.0.1 problem.

For me, the biggest problem with Backbone not respecting semver (among other things) is in teaching and evangelizing Backbone. It's not great to tell a group of students or potential customers that everything in your stack is going to work in a certain way... except for Backbone.

There have always been two huge caveats when "evangelizing" Backbone: it's not AMD out of the box, and it doesn't respect SemVer, so don't take the version numbers seriously. One of those is fixed. Let's fix the other.

@knowtheory
Copy link
Collaborator

Honestly, I'd prefer a simpler scheme that just used BIG.SMALL version numbers — like most desktop applications do ... but I'd worry about it breaking package managers and other tooling.

@jashkenas we could just always leave the 3rd digit at .0 :)

That'd probably map semantically to SemVer a little closer than what we're doing right now. Maybe that'd tamp down on some of the passive-aggressive crypto-political sniping about how it's somehow technically wrong not to follow SemVer.

I think Bob's point is right in that it's more important to clearly articulate what system we follow, irrespective of what system we follow.

p.s. I did not mean to imply that @keithamus's issue is passive aggressive and I'm sorry if it came off that way. Definitely legit to discuss how Backbone communicates changes to users.

@lukeasrodgers
Copy link
Contributor

👍 for semver. I am primarily interested the version of a given piece of software not as an index of its progress but of its compatibility.

Generally, after 1.0 (when I'd expect things to be mostly stable and working), version numbers are largely meaningless as indicators of progress. Software X at version 10 may be much less mature, have fewer features than Software Y at version 2. If you want to know about the progress of a piece of software, you have to look at its changelog or roadmap.

Knowing that Backbone (or whatever) is at 2.4.3 means nothing in terms of its features. It should, however, mean that I can upgrade from my 2.0.4 without anything breaking.

@jamesplease
Copy link
Contributor

If we strictly followed "semantic" versioning, it would probably be Backbone.js 43.0.0 by now — which doesn't help anyone evaluate the actual progress of the project.

A very minor / maybe nonexistent problem. Not following semver? Big problem.

@Anachron
Copy link

👍, semver is a must-have for such a big project.

@braddunbar
Copy link
Collaborator

I'm with @knowtheory. 43.0.0 looks a bit odd but I think 1.43.0 would be fine and no one would get surprise breakage after npm install.

@Anachron
Copy link

Who cares about version numbers being high?
It's a standard, if you can use it, you should use it.
I don't even understand why this discussion is going for so long.

@jdalton
Copy link
Contributor

jdalton commented Feb 19, 2014

👍 It would have prevented some of the issues in #2996 and #2997, and problems others have had w/ several other Backbone releases.

@spadgos
Copy link

spadgos commented Feb 20, 2014

@braddunbar that (and the rest of the reasons "against") sounds like it's valuing the aesthetics of the version number over its actual meaning.

@acstll
Copy link

acstll commented Feb 20, 2014

Thanks, but strictly following "semantic" versioning wouldn't work out very well for Backbone.

I think it's more about Backbone working well for its users (with dependency management). Which following semver would guarantee…

@akre54
Copy link
Collaborator

akre54 commented Feb 20, 2014

More frequent releases would help catch showstopper bugs faster. I think it's too much to ask people to constantly run edge versions of Backbone just to get the bugfixes they need.

@samccone
Copy link

samccone commented Mar 4, 2014

+1 @derickbailey

Just as an example these are since 1.1.0, the idea behind patch releases is these fixes should not be needed at all.

marionettejs/backbone.marionette@5a498d2

marionettejs/backbone.marionette@baed36b

marionettejs/backbone.marionette@e13e912#diff-3c2771f47bdfe073ea95bfa54a37a972R167

@ericelliott
Copy link

For packages in npm or bower, this isn't even up for debate.

When you publish a package with npm or bower, semver is part of the API contract you enter into. When you break that contract, you break other modules that depend on yours. You break production code that depends on your module.

The question is not, "should we use semver?" The question is, "do we want to be good citizens in the ecosystem?"

If the answer is no, that should be advertised loudly and clearly, because it's not safe to just install your package like you would any other package that follows the API contract.

@akre54
Copy link
Collaborator

akre54 commented Jun 16, 2014

When you publish a package with npm or bower, semver is part of the API contract you enter into.

No, it's not. npm install --save backbone@1.1.2 is not an onerous requirement.

@samccone
Copy link

@akre54 I am interested in your perspective about semver I know @jashkenas thoughts on it but what are yours.

@ericelliott
Copy link

@akre54 Yes, it is. npm assumes that all packages in the repository follow semver. That's how it determines which packages are compatible with which.

From the package.json doc:

"Version must be parseable by node-semver, which is bundled with npm as a dependency. (npm install semver to use it yourself.)"

If your version numbers lie when they're interpreted as semver, that's not a correct parsing. Thus, you're breaking the package.json contract, and you're breaking compatibility with how people use package versions in the npm ecosystem.

That's not just a matter of personal preference. It's a matter of package interoperability.

Is it possible to force your package to play nice if it doesn't use semver? Sure, it is, but if you don't call it out loudly and boldly at the top of your readme -- few users will know that it's necessary, and when you introduce a breaking change, their code could very easily break.

Once you publish your packages to package repositories, versioning becomes part of the interoperability contract. You ignore that contract at the peril of your users.

@ericelliott
Copy link

npm install --save backbone@1.1.2 is not an onerous requirement.

Knowing which of the thousands of packages that go into a full blown application you have to do this with is an onerous requirement. Forcing users to tightly lock down the versions of all their packages because a handful of modules don't follow the rules is an onerous requirement, because it complicates the matter of keeping up with bug fixes, security patches, etc...

There are very good reasons to follow semver. "My package number might get really big" is a terrible reason not to use semver. Tracking the progress of your application is a distant second reason for package versions. The most important function of the version is to know, "will this version work with my application?"

BTW, if your package number would get really big, maybe that's a code smell. You only have to bump the major version when you make a breaking change. A breaking change by definition is one that breaks the open/closed principle. Open for extension, closed for breaking changes. All good APIs follow the open/closed principle as closely as they reasonably can, so that users can keep pace with the API, and changes don't break existing code.

@wookiehangover
Copy link
Collaborator

I think the lesson learned here is "don't use ~ or ^ when pulling in Backbone via package.json"

@akre54
Copy link
Collaborator

akre54 commented Jun 16, 2014

@akre54 I am interested in your perspective about semver

In general I agree with the arguments here, but I do have to wonder if bumping the major version is the best course of action on every breaking change (and again, with Underscore being mostly surface area, that's a lot). Underscore is used in a great deal of third-party libraries, and requiring them all to keep up with huge versions would be onerous and perilous. (Should a package released today depend on Underscore up to version 2? 1.7? 1.6.x? Should it pin its dependencies at the expense of perhaps requiring a separate Underscore from the main project?)

I think the lesson learned here is "don't use ~ or ^ when pulling in Backbone via package.json"

yep.

@ericelliott
Copy link

I think the lesson learned here is "don't use ~ or ^ when pulling in Backbone via package.json"

I've outlined above why this should not be the takeaway lesson.

@acstll
Copy link

acstll commented Jun 17, 2014

I think the lesson learned here is "don't use ~ or ^ when pulling in Backbone via package.json"

That's what you do, as a consequence, to protect your code from breaking.

The lesson would be more like "following semver is good for everyone, not doing so is not."

@dgbeck
Copy link

dgbeck commented Jun 17, 2014

I can appreciate the value in "romantic" versioning. Too bad they don't coexist very well.

Should be noted that there will always be projects that don't follow semver very strictly, and those that attempt to but fall short, so the system always leaks a little.

At least Backbone is generally very good about not breaking things.

@samccone
Copy link

@dgbeck things break all the time per versions see my earlier comment


So I think the value in following semver that has not really been talked about is the fact that you guys can push minor features and bug fixes and allow people who depends on it upstream to get these changes for free.

To me this is a great value add but obviously this comes at the cost of complexity for the maintainer.

jpwilliams added a commit to inngest/inngest-js that referenced this issue Mar 27, 2023
…#151)

## Summary INN-1009

Providing a TS library means supporting various versions of TypeScript.
Above just watching public API changes, this means:

- Ensuring we have an explicit earliest supported TS version
- Ensuring we have an explicit earliest supported Node version
- Ensuring that earlier TS versions maintain the same level of inference
across all tooling

TypeScript introduce breaking changes with minor increments, which seems
to be the norm among tooling with a large surface area (see [Follow
SemVer · Issue #2888 · jashkenas/backbone
(github.com)](jashkenas/backbone#2888 (comment))).
This also means that TS changes faster than it appears to and that it's
harder for users to upgrade TS versions, even though semver might
suggest otherwise.

Most TS configs will also type-check any installed libraries every time
code is built, which results in errors on TS `<4.7.0` as the earlier
compiler can't even parse the file due to unexpected characters (see
#150).

## Actions

There are some fantastic resources covering this problem (see
https://www.semver-ts.org/), but even tooling such as
[downlevel-dts](https://github.com/sandersn/downlevel-dts) takes a long
time to support the latest TS releases (it currently still doesn't
support some 4.7 features) _and_ some of the "down-leveling" just falls
back to wider types such as `any` or `unknown`, which could be
insufficient depending on where it is.

The easiest step to take is to add some CI testing for various
TypeScript versions and ensure that tests pass and compile. We have a
lot of type-only unit tests to assert inference functionality, so
testing that against earlier TS versions should do the trick.

With this, we can pretty easily support >=4.7.0, though going any
further would require some chonky rewrites. The main culprit being
[instantiation
expressions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#instantiation-expressions)
released in [TypeScript
4.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html).
This PR is mostly about adding a framework for asserting and committing
to a specific TS version support, then support for earlier versions can
be added in further PRs.

Time-wise, it means we can comfortably support TS versions within the
last 10 months, and specify that fact in our `peerDependencies`.

- ✅ **TypeScript 5.0** - March 2023 (<1mo)
- ✅ **TypeScript 4.9** - November 2022 (~4mo)
- ✅ **TypeScript 4.8** - August 2022 (~7mo)
- ✅ **TypeScript 4.7** - May 2022 (~10mo)
- ❌ **TypeScript 4.6** - Feb 2022 (~1y1mo)
- ❌ **TypeScript 4.5** - November 2021 (~1y4mo)
- ❌ **TypeScript 4.4** - August 2021 (~1y7mo)
- ❌ **TypeScript 4.3** - May 2021 (~1y10mo)
- ❌ **TypeScript 4.2** - Feb 2021 (~2y1m)
- ❌ **TypeScript 4.1** - November 2020 (~2y4m)
- ❌ **TypeScript 4.0** - August 2020 (~2y7mo)

To test types, we'll do a couple of actions:

- [x] Add a new `test:types` script that will test that `dist/` and
`src/**/*.test.ts` compile correctly.
This will ensure that users with the default of `skipLibCheck: false`
can properly build the code, and compiling test files ensures that all
type tests are also working.
- [x] Add CI matrix to test multiple TS versions against the above files

## Related

- #150

---------

Co-authored-by: Igor Gassmann <igor@igassmann.me>
morinim added a commit to morinim/ultra that referenced this issue Mar 28, 2024
Text from Jashkenas's [Backbone repository](jashkenas/backbone#2888). It's well written and many considerations are completely transposable.

Moreover previous experience with SemVer in Vita (https://github.com/morinim/vita) has not been completely satisfactory.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests