mirror of
https://github.com/semver/semver.git
synced 2026-07-11 03:53:53 -05:00
[GH-ISSUE #311] Change in behavior #6214
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @tallesl on GitHub (Jun 7, 2016).
Original GitHub issue: https://github.com/semver/semver/issues/311
The spec is well defined when it comes to changing the API, take the following paragraph for instance:
Pretty straightforward.
But what about substantial behavioral changes? There are times that you make big changes in a code behavior without changing a thing on its API. Is that a patch?
Example 1
Suppose there's a library that sends emails. Let's say that on version
1.0.0it simply sends emails as plain text, no configuration there.On its second release the author changes the library to send emails as HTML instead, without changing anything on its API. It does that automatically. What's the version?
For the user that rely on the fact that it sends only plain text emails, that's a major (
2.0.0). For the user that may be interested in sending emails with rich content now and doesn't bother with HTML being automatically assumed, that's a minor (1.1.0). For the user that expects semver to be solely about the API as the spec mentions it, that's a patch (1.0.1).Example 2
Imagine a scheduling library for an object oriented language that accepts custom jobs designed by a user. The user gives the library the type of its job implementation and some cron-like scheduling.
On current version the library instantiates one single job object and calls it (the same object) every time its schedule is fired.
Now someone points out the fact that may be a better design to instantiate a new object for each time the scheduled is fired. The author of the library finds the argument convincing and changes the library, but no API change was needed.
If one uses the library only with stateless jobs that's a patch alright. But what if some of the library users were relying on the fact that it treated the jobs as singletons?
(this last example is a real scenario by the way)
@haacked commented on GitHub (Jun 7, 2016):
The behavior of an API is part of the API, not just the shape of the API. So in Example 1, I'd consider that a breaking change and increment the major version. Another way to look at it is that SemVer is about communicating intent and risk of breaking to consumers. If a large number of customers would consider it a breaking change, then you could increment the major.
For example, in Example 1, instead of replacing text with HTML, you used multi-part mime type to send an email as both, you could argue that's just a minor increment because existing emails continue to work as before and only those who opt-in to the HTML get HTML.
For example 2, I'd argue that it depends on whether the singleton behavior is explicitly called out as part of the design of the API. It seems to me that people are relying on an implementation detail if they assume the singleton. So I would not increment major unless I had strong data to indicate that changing this behavior would break a large number of my customers.
The reason is in general, consumers of an API should be discouraged from coupling to heavily to implementation details. For example, private reflection is a classic example. Every change to software has the potential to be a breaking change. People could be relying on timing of your code and a performance optimization could break their apps. But these are cases where perhaps they get what they deserve when a minor change breaks them.
I'll close this since there's nothing actionable here, but feel free to continue the discussion or reopen if the answer is not satisfactory. 😄
@krzysiekpiasecki commented on GitHub (Jun 7, 2016):
From point 7:
Release as Minor.
@tallesl commented on GitHub (Jun 8, 2016):
@Haacked
I'm A-OK with most of the remarks you made, specially the last one on relying too much on implementation details.
But I'll have to disagree with you here. I think you can use the term "API" loosely implying the code that is underneath it (as a synonym for "program" or "library"), but in a strict sense I wouldn't think so. An API It's an (application programming) interface!
Take Wikipedia's definition for instance:
There's a note on FAQ addressing this issue:
My point is that this remark is just too important to be left on FAQ. In my opinion, the summary and the introduction gives the impression that to come with a version number is just a matter of taking a look on the API.
@FichteFoll commented on GitHub (Jun 8, 2016):
An API usually makes promises about what happens when you use it in a certain way (like arguments). If the API states in its documentation "sends an email" then changing the way the email is sent is not a breaking change to the API. If it states "sends a plaintext email" and you start sending multi-part mime, it becomes a breaking and major change.
@haacked commented on GitHub (Jun 8, 2016):
I should have been more precise. SemVer is typically used to version a package or library. If the behavior changes significantly, then you increment the major version of the library.
Your example with the singleton assumes an implementation as the change is in behavior and not the API. So I assumed your example really referred to a library because as you point out, an API is independent of an implementation so talking about a behavior change doesn't make sense in the context of the API.
In sum, if the API doesn't change, its version doesn't. But a specific implementation of it might version independently of the API it implements.
@tallesl commented on GitHub (Jun 8, 2016):
Agreed.
If there was no change in the API and no change in implementation, well, nothing changed. If there was no change in the API but there was a change in implementation you have to change the version, after all you have something to distribute here.
I sincerely didn't get this one. Are you mentioning things like Java folks that creates packages that are only an API without any implementation at all?
I think we're starting to repeat ourselves here. I just want to end here saying that if you combine the definition of API
with what the spec says on its introduction
it gives the wrong impression what breakage really is (behavior is completely left out).
@crazedsanity commented on GitHub (Jun 8, 2016):
Well, look at it this way: how much does the implementor have to change when upgrading?
Consider it in simpler terms, from the perspective of the implementor (the developer that's actually utilizing the library in question):
PATCH: I can upgrade with no change to the code.
MINOR: There's some work to do, but nothing substantial
MAJOR: Plenty of code to change/refactor/rewrite
@tallesl commented on GitHub (Jun 8, 2016):
@crazedsanity
By not using the word "API" you didn't step in the confusion I'm addressing in this issue. The spec on the other hand does use the word.
@haacked commented on GitHub (Jun 8, 2016):
@tallesl I see your point. In the introduction to SemVer, it starts off by talking about packages.
And then it moves into a discussion of the API without really defining API.
So if we strictly define API as just the "interface" a breaking change that doesn't change the interface wouldn't change the major version.
I never noticed this because I always read this as:
So the question is, what's the best most minimal way to address this?
@tallesl commented on GitHub (Jun 8, 2016):
@Haacked
I think the best/most minimal way to address this is by adding a short statement on the introduction stating what we have been discussing here. I also would recommend to add it just after the quote that uses "API" to define what patch, minor and major is (that's the troublesome part IMO).
What about
It's a slightly modified sentence from the FAQ.
@haacked commented on GitHub (Jun 8, 2016):
I like it, but want to tweak it a bit. How about?
@tallesl commented on GitHub (Jun 8, 2016):
Even better 👍
P.S.: Maybe that FAQ statement becomes redundant now that we "promoted" the remark to the introduction, even though they are not literally identical.
@krzysiekpiasecki commented on GitHub (Jun 8, 2016):
IMHO you have probably developed a new library function, so next release is 1.1.0 but you MUST still support the old function, which sends plain text until next MAJOR because of old clients. You can manifest also old function as deprecated if you want remove this function in a future with next MAJOR release.
@israel-lugo commented on GitHub (Sep 20, 2016):
I would suggest that (the main?) part of the problem is with the term "API". It seems some people read it as "the sum of your program's public functions and their expected behavior", with "behavior" being left for a case-by-case analysis, whereas some people read "API" in the stricter sense of "Application Programmer Interface".
I've opened issue #331 for discussing precisely this matter. I believe "API" is too limiting and could be improved by replacing it e.g. with "Interface" or something that means "the full interaction with the program".
Yes, an introduction can be added, and a FAQ entry and so on, but perhaps if we find a better suited term, the extra explanations cease to be necessary.
@jwdonahue commented on GitHub (Oct 9, 2018):
Reference #468 for tracking.
@danbirle commented on GitHub (Feb 12, 2021):
can semver be used in frontend projects? we've been using it for a while now but some of us are torn when it comes to deciding what flag to use when we have a Visual Change? (you know.... designers decided that font looks better with font-weight: 100 in some places).
@crazedsanity commented on GitHub (Feb 12, 2021):
I don't see and reason why you couldn't use it for frontend code. It's
likely different than backend code, so versioning is a little different.
I would suggest incrementing patch level, as it doesn't fit a major/minor
change. This basically just reflects that there was a change in the code,
but nothing too big.
Make sense?
On Fri, Feb 12, 2021, 6:30 AM 'Razvan Dan Birle' via github <
github@crazedsanity.com> wrote:
@haacked commented on GitHub (Feb 12, 2021):
You can certainly use it for frontend projects. However keep in mind what the purpose of SemVer is. Its primary goal is to help people to evaluate the risk of upgrading a dependency to a new version. This is particularly important with libraries/packages. If a library publishes a new major version, upgrading to that new major version could break every system that depends on it.
With a front-end project, you want to evaluate the dependencies. If your project is not a dependency to other systems, then the version doesn't serve much person other than to communicate the amount of change that occurred. It's more a marketing version than a technical version.
If others depend on your project, then the version matters more because it can communicate how much work it will be to upgrade.
With that framing in mind, let's go back to your question. As @crazedsanity noted, if you change the font, there's probably 0 risk to upgrading to the new version. In that case, incrementing Patch makes sense. Minor version would make sense if the visual change introduces a new capability that wasn't there before. Major version would indicate that the visual change may break people's existing workflows (maybe you removed a feature).
Hope that helps.
@danbirle commented on GitHub (Feb 15, 2021):
Makes sense, I'll go with this approach. Thank you both!