Change wording with regards to breaking change in dependency #332

Closed
opened 2026-02-17 11:51:58 -06:00 by GiteaMirror · 9 comments
Owner

Originally created by @evenlis on GitHub (Aug 10, 2018).

This question has been brought up before (here and here at least). #80 references this bit of the FAQ, which states the following:

That would be considered compatible since it does not affect the public API.

However, for maven there's a gotcha in case a consumer of a project shares a dependency with said project. I outlined this in a stackoverflow question, but I'll quote the relevant bit here:

Scenario:

  • Project P has two dependencies, D1-1.2.3 and D2-2.0.0
  • D1-1.2.3 has D2-1.0.0 as a dependency
  • A class C in D1 uses (but does not expose) a class from D2 that has had a breaking change from version 1.0.0 to 2.0.0
  • P uses C

The maven dependency model dictates that since P's pom.xml explicitly states the D2 dependency, the version from the pom will be used. This causes P to break with a linkage error because of the incompatible change of the transitive dependency.

Now I understand that this arises from maven's specific dependency model, but in light of that I would suggest changing "since it does not affect the public API" to "if it does not affect the public API". That way the semver specification would make no assumptions about different dependency models and binary compatibility in programming languages.

Originally created by @evenlis on GitHub (Aug 10, 2018). This question has been brought up before ([here](https://github.com/semver/semver/issues/80) and [here](https://github.com/semver/semver/issues/148) at least). [#80](https://github.com/semver/semver/issues/80) references [this bit of the FAQ](https://semver.org/#what-should-i-do-if-i-update-my-own-dependencies-without-changing-the-public-api), which states the following: > That would be considered compatible since it does not affect the public API. However, for maven there's a gotcha in case a consumer of a project shares a dependency with said project. I [outlined this in a stackoverflow question](https://stackoverflow.com/questions/51780564/should-i-increase-major-version-on-dependency-update), but I'll quote the relevant bit here: >Scenario: > >- Project `P` has two dependencies, `D1-1.2.3` and `D2-2.0.0` >- `D1-1.2.3` has `D2-1.0.0` as a dependency >- A class `C` in `D1` uses (but does not expose) a class from `D2` that has had a breaking change from version `1.0.0` to `2.0.0` >- `P` uses `C` > >The maven dependency model dictates that since `P`'s `pom.xml` explicitly states the D2 dependency, the version from the pom will be used. This causes P to break with a linkage error because of the incompatible change of the transitive dependency. Now I understand that this arises from maven's specific dependency model, but in light of that I would suggest changing "_since_ it does not affect the public API" to "_if_ it does not affect the public API". That way the semver specification would make no assumptions about different dependency models and binary compatibility in programming languages.
Author
Owner

@jwdonahue commented on GitHub (Aug 18, 2018):

Classic diamond dependency problem. Does maven provide for side-by-side versions of the same interfaces? If not, then at the point where P introduces the D2-2.0.0 requirement, it has introduced a breaking change. The real question here is what are you versioning? Applying a version number to an API is one thing, but that same version number often doesn't apply to the package containing the API and dependency manifests. Even if P doesn't change, you've made a breaking change to the package content and the version of that package must get a major version bump.

With regard to the faq in question, I think it's misleading. Assuming the manifests you ship with your API aren't part of your API surface is absurd. Don't break my builds with minor or patch updates! If you do, I can't automatically ingest your bug fixes into my system. I'll have to have a dev look at every one of them or force my build team to spend time investigating needless build breaks.

@jwdonahue commented on GitHub (Aug 18, 2018): Classic diamond dependency problem. Does maven provide for side-by-side versions of the same interfaces? If not, then at the point where P introduces the D2-2.0.0 requirement, it has introduced a breaking change. The real question here is what are you versioning? Applying a version number to an API is one thing, but that same version number often doesn't apply to the package containing the API and dependency manifests. Even if P doesn't change, you've made a breaking change to the package content and the version of that package must get a major version bump. With regard to the faq in question, I think it's misleading. Assuming the manifests you ship with your API aren't part of your API surface is absurd. Don't break my builds with minor or patch updates! If you do, I can't automatically ingest your bug fixes into my system. I'll have to have a dev look at every one of them or force my build team to spend time investigating needless build breaks.
Author
Owner

@jwdonahue commented on GitHub (Aug 23, 2018):

@evenlis, unless you have further questions or intend to offer a related pull request, please close this issue at your earliest possible convenience.

@jwdonahue commented on GitHub (Aug 23, 2018): @evenlis, unless you have further questions or intend to offer a related pull request, please close this issue at your earliest possible convenience.
Author
Owner

@jwdonahue commented on GitHub (Aug 25, 2018):

@evenlis, is there anything else you need help with?

@jwdonahue commented on GitHub (Aug 25, 2018): @evenlis, is there anything else you need help with?
Author
Owner

@evenlis commented on GitHub (Sep 20, 2018):

Apologies for the delayed reply, these notifs somehow ended up in my spam folder.

Even if P doesn't change, you've made a breaking change to the package content and the version of that package must get a major version bump.

so, are you saying I should bump major version every time I upgrade a dependency that has a breaking change?

@evenlis commented on GitHub (Sep 20, 2018): Apologies for the delayed reply, these notifs somehow ended up in my spam folder. >Even if P doesn't change, you've made a breaking change to the package content and the version of that package must get a major version bump. so, are you saying I should bump major version every time I upgrade a dependency that has a breaking change?
Author
Owner

@jwdonahue commented on GitHub (Sep 20, 2018):

Yes. You are shipping a package that defines transitive dependencies. In a sense, those are part of your "API". They are content that you added to your package, therefore it is your responsibility to communicate the fact that you are introducing a breaking change to your customers systems. On systems that provide for side-by-side installation and use of different package versions, it isn't always the case that these transitive changes are breaking, but there are some cases where even with side-by-side, such a change will cause a break.

We can't always be responsible for every combination of API/Package versions on our customers systems, but we can and should take full responsibility for the effects we do control. In this case, you had a version x.y.z that contained a list of dependencies, and then you forced a breaking change in that list. You should now have an x'.y.z version.

You must always be cognitive of what it is you are versioning. Interfaces are simple and have no direct dependencies, but implementations and the packages that combine interfaces, implementations and also package-type ecosystem infrastructure, have more complexity. We must all take responsibility for the breaking changes that we introduce into our implementations and package ecosystem infrastructure.

It's all about what exactly is it that you are slapping that version label onto? If it's a package, you are responsible for its contents.

@jwdonahue commented on GitHub (Sep 20, 2018): Yes. You are shipping a package that defines transitive dependencies. In a sense, those are part of your "API". They are content that you added to your package, therefore it is your responsibility to communicate the fact that you are introducing a breaking change to your customers systems. On systems that provide for side-by-side installation and use of different package versions, it isn't always the case that these transitive changes are breaking, but there are some cases where even with side-by-side, such a change will cause a break. We can't always be responsible for every combination of API/Package versions on our customers systems, but we can and should take full responsibility for the effects we do control. In this case, you had a version x.y.z that contained a list of dependencies, and then you forced a breaking change in that list. You should now have an x'.y.z version. You must always be cognitive of what it is you are versioning. Interfaces are simple and have no direct dependencies, but implementations and the packages that combine interfaces, implementations and also package-type ecosystem infrastructure, have more complexity. We must all take responsibility for the breaking changes that we introduce into our implementations and package ecosystem infrastructure. It's all about what exactly is it that you are slapping that version label onto? If it's a package, you are responsible for its contents.
Author
Owner

@jwdonahue commented on GitHub (Sep 20, 2018):

Does the Maven system expose the package dependencies without my having to pull your package? Is it possible for me to pull only non-breaking changes, taking transitive dependencies into account?

@jwdonahue commented on GitHub (Sep 20, 2018): Does the Maven system expose the package dependencies without my having to pull your package? Is it possible for me to pull only non-breaking changes, taking transitive dependencies into account?
Author
Owner

@evenlis commented on GitHub (Sep 25, 2018):

Having "A -> B -> C", where "->" means a dependency: In maven it's possible to
a) Mark a dependency as optional in B, meaning it won't be included transitively by unless explicitly stated by A
b) Explicitly (in A) exclude C from being transitively included by depending on B

So I suppose unless B marks C as optional (as per "a" above), B would need to bump the major version whenever bumping C's version?

@evenlis commented on GitHub (Sep 25, 2018): Having "A -> B -> C", where "->" means a dependency: In maven it's possible to a) Mark a dependency as optional in B, meaning it won't be included transitively by unless explicitly stated by A b) Explicitly (in A) exclude C from being transitively included by depending on B So I suppose unless B marks C as optional (as per "a" above), B would need to bump the major version whenever bumping C's version?
Author
Owner

@jwdonahue commented on GitHub (Sep 25, 2018):

In the absence of side-by-side install and execution, where there are no diamond point dependencies, yes. See my response to #462. When the publisher of A is forcing a breaking change into the environment, they should bump the major version on A.

@jwdonahue commented on GitHub (Sep 25, 2018): In the absence of side-by-side install and execution, where there are no diamond point dependencies, yes. See my response to #462. When the publisher of A is forcing a breaking change into the environment, they should bump the major version on A.
Author
Owner

@steveklabnik commented on GitHub (Feb 11, 2019):

It seems the question is answered here; closing!

@steveklabnik commented on GitHub (Feb 11, 2019): It seems the question is answered here; closing!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/semver#332