[GH-ISSUE #146] What about refactoring? #1826

Closed
opened 2026-04-20 09:27:38 -05:00 by GiteaMirror · 36 comments
Owner

Originally created by @openjck on GitHub (Jul 26, 2013).
Original GitHub issue: https://github.com/semver/semver/issues/146

Semantic Versioning holds that the patch version should be incremented for...

backwards-compatible bug fixes

but that...

Once a versioned package has been released, the contents of that version MUST NOT be modified. Any modifications MUST be released as a new version.

Where does refactoring fit into this? Refactored code is modified code, but the modifications do not necessarily contain any bug fixes.

Originally created by @openjck on GitHub (Jul 26, 2013). Original GitHub issue: https://github.com/semver/semver/issues/146 Semantic Versioning holds that the patch version should be incremented for... > backwards-compatible bug fixes but that... > Once a versioned package has been released, the contents of that version MUST NOT be modified. Any modifications MUST be released as a new version. Where does refactoring fit into this? Refactored code is modified code, but the modifications do not necessarily contain any bug fixes.
Author
Owner

@Tieske commented on GitHub (Jul 27, 2013):

Good point. There are 2 ways to deal with it;

  1. API didn't change, nor any bug fixes so the version stays the same
  2. New bugs may have been introduced, so patch level must be updated

I'd go for the latter one.

<!-- gh-comment-id:21671488 --> @Tieske commented on GitHub (Jul 27, 2013): Good point. There are 2 ways to deal with it; 1. API didn't change, nor any bug fixes so the version stays the same 2. New bugs may have been introduced, so patch level must be updated I'd go for the latter one.
Author
Owner

@tbull commented on GitHub (Jul 28, 2013):

I think, this is just not the concern of SemVer. SemVer is about some kind of an API. It is something exterior, visible by the world. Refactoring is something internal, which does not even have to be noticed by the consumers of your code.

I know, we're all proud of what we have achieved after a great coding session, even more so if we can see and feel the elegance of the new code, and we're confident the whole world should know. But in this case, the answer is: Just don't tell. instead, make up an appropriate tag (independent of Semver) in your repository. Note that this implies that you don't release the new code (why should you if nothing has changed on the outside).

However, normally you will refactor for a reason, often to make your code more robust, to carry more functionality. New/modified functionality then will reflect in the API and you increase numbers accordingly. If your first step is to refactor without any change in functionality, there might still occur bugfixes (or new bugs) in the process (increase patch). If not, well, there's is no reason to make a new release.

Note, that you can re-release your stuff anytime with a new version number much of your liking. You can even assign a new major version number to the very same code. That might not be in the spirit of SemVer, but at least the spec doesn't forbid it (and I think we should keep this flexibility and hope that people wield that power wisely).

Also note that this question is similar to #128, which does not appear convincingly resolved to me. I figure, refactoring is one development step on the way to a new release. Great refactoring probably a step on the way to a new major release. Bump your version number for the release, not for the development step.

<!-- gh-comment-id:21681289 --> @tbull commented on GitHub (Jul 28, 2013): I think, this is just not the concern of SemVer. SemVer is about some kind of an API. It is something exterior, visible by the world. Refactoring is something internal, which does not even have to be noticed by the consumers of your code. I know, we're all proud of what we have achieved after a great coding session, even more so if we can see and feel the elegance of the new code, and we're confident the whole world should know. But in this case, the answer is: Just don't tell. instead, make up an appropriate tag (independent of Semver) in your repository. Note that this implies that you don't release the new code (why should you if nothing has changed on the outside). However, normally you will refactor for a reason, often to make your code more robust, to carry more functionality. New/modified functionality then _will_ reflect in the API and you increase numbers accordingly. If your first step is to refactor without any change in functionality, there might still occur bugfixes (or new bugs) in the process (increase patch). If not, well, there's is no reason to make a new release. Note, that you can re-release your stuff anytime with a new version number much of your liking. You can even assign a new major version number to the very same code. That might not be in the spirit of SemVer, but at least the spec doesn't forbid it (and I think we should keep this flexibility and hope that people wield that power wisely). Also note that this question is similar to #128, which does not appear convincingly resolved to me. I figure, refactoring is one development step on the way to a new release. Great refactoring probably a step on the way to a new major release. Bump your version number for the release, not for the development step.
Author
Owner

@Tieske commented on GitHub (Jul 28, 2013):

I agree. My nr. 2 above fails the assumption of it actually being released, which doesn't make sense if it only is refactoring and nothing else.

Maybe an FAQ entry would be nice

<!-- gh-comment-id:21681436 --> @Tieske commented on GitHub (Jul 28, 2013): I agree. My nr. 2 above fails the assumption of it actually being released, which doesn't make sense if it only is refactoring and nothing else. Maybe an FAQ entry would be nice
Author
Owner

@EddieGarmon commented on GitHub (Jul 28, 2013):

Again this goes back to what is the definition of Public API. As it is still ambiguous in the spec, you both could be right.

For a post 1.0.0 release:

If Public API is just externally exposed method signatures and they are not changed, then I agree that (if released) the PATCH number should be increased. Maybe the spec should also be changed to say something like:
3. PATCH version when you make backwards-compatible bug fixes and internal optimizations.

If Public API is exposed signatures and behavior, then (if released) the MINOR number should be increased. Here a change in performance would be a change in behavior.
2. MINOR version when you add functionality in a backwards-compatible manner,

This just adds to the point that we need a better definition of what Public API means.

<!-- gh-comment-id:21681698 --> @EddieGarmon commented on GitHub (Jul 28, 2013): Again this goes back to what is the definition of `Public API`. As it is still ambiguous in the spec, you both could be right. For a post 1.0.0 release: If Public API is just externally exposed method signatures and they are not changed, then I agree that (if released) the PATCH number should be increased. Maybe the spec should also be changed to say something like: `3. PATCH version when you make backwards-compatible bug fixes and internal optimizations.` If Public API is exposed signatures and behavior, then (if released) the MINOR number should be increased. Here a change in performance would be a change in behavior. `2. MINOR version when you add functionality in a backwards-compatible manner,` This just adds to the point that we need a better definition of what Public API means.
Author
Owner

@Tieske commented on GitHub (Jul 28, 2013):

the core reason for a version number to exist is to exactly pinpoint the asset being discussed, without any ambiguities.

SemVer extends this by specifying the format of the descriptor.

Hence; any version released, even with unchanged API and behavior, should get its own version.

<!-- gh-comment-id:21684158 --> @Tieske commented on GitHub (Jul 28, 2013): the core reason for a version number to exist is to exactly pinpoint the asset being discussed, without any ambiguities. SemVer extends this by specifying the format of the descriptor. Hence; any version released, even with unchanged API and behavior, should get its own version.
Author
Owner

@EddieGarmon commented on GitHub (Jul 28, 2013):

@Tieske I totally agree. Just playing devil's advocate to point out that we have ambiguity about what is the proper new version for the 'refactored' code.

<!-- gh-comment-id:21684209 --> @EddieGarmon commented on GitHub (Jul 28, 2013): @Tieske I totally agree. Just playing devil's advocate to point out that we have ambiguity about what is the proper new version for the 'refactored' code.
Author
Owner

@bessarabov commented on GitHub (Aug 24, 2013):

I had the same question "What part of SemVer should I change if there is only one change and it is refactoring?".

I've carefully read this thread (actually I was suprised that there was only one issues about this topic). In this thread I've found 2 possible solutions.

  • Change the PATCH level in SemVer. Solution by @Tieske. It makes sense. Every new release should have different version. There was no backward incompatible change, so the MAJOR should not be changed. The new functionality was not added, so we don't need to change MINOR. So the only level that can be changed in this situation is PATCH.
  • Don't release new version if the change is only refactoring. Solution by @tbull This also makes sense. It does not matter to the library user how that library works internally. The only thing that matters is the API.

But I like to group information in the Changes file by the SemVer level. Here is an example:

1.2.0   2013-08-09
        [Minor]
        * Added standard directory `examples` to the POD SYNOPSIS
        * Better POD markup in FAQ section
        * Added Perl 5.8 to be checked by Travis CI

        [Patch]
        * Fixing text in SYNOPSIS to match text in FAQ
        * Fixing misspell
        * Refactoring

My question: should I write information that there was refactoring in the Changes file?

PS. But what if after refactoring the library has started working N times faster? Well, in this situation I can't tell that that change was refactoring, from my point of view it is MINOR change "library works faster" and It is out of the scope of the refactoring question.

<!-- gh-comment-id:23205695 --> @bessarabov commented on GitHub (Aug 24, 2013): I had the same question "What part of SemVer should I change if there is only one change and it is refactoring?". I've carefully read this thread (actually I was suprised that there was only one issues about this topic). In this thread I've found 2 possible solutions. - Change the PATCH level in SemVer. Solution by @Tieske. It makes sense. Every new release should have different version. There was no backward incompatible change, so the MAJOR should not be changed. The new functionality was not added, so we don't need to change MINOR. So the only level that can be changed in this situation is PATCH. - Don't release new version if the change is only refactoring. Solution by @tbull This also makes sense. It does not matter to the library user how that library works internally. The only thing that matters is the API. But I like to group information in the Changes file by the SemVer level. Here is an example: ``` 1.2.0 2013-08-09 [Minor] * Added standard directory `examples` to the POD SYNOPSIS * Better POD markup in FAQ section * Added Perl 5.8 to be checked by Travis CI [Patch] * Fixing text in SYNOPSIS to match text in FAQ * Fixing misspell * Refactoring ``` My question: should I write information that there was refactoring in the `Changes` file? PS. But what if after refactoring the library has started working N times faster? Well, in this situation I can't tell that that change was refactoring, from my point of view it is MINOR change "library works faster" and It is out of the scope of the refactoring question.
Author
Owner

@Tieske commented on GitHub (Aug 24, 2013):

the two options are not exclusive, the solution is to combine them. Everything released must be uniquely identifiable. But you only release something when it actually makes sense to release it.

So simple refactoring without impact, is not released. If it provides a major performance increase, you do release (and version).

Whether or not to add it to the changes file is probably dependent on your target audience. An end user application won't have any benefits from it. But if it is a library targetted at other developers, you might want to include it.

<!-- gh-comment-id:23210360 --> @Tieske commented on GitHub (Aug 24, 2013): the two options are not exclusive, the solution is to combine them. Everything released must be uniquely identifiable. But you only release something when it actually makes sense to release it. So simple refactoring without impact, is not released. If it provides a major performance increase, you do release (and version). Whether or not to add it to the changes file is probably dependent on your target audience. An end user application won't have any benefits from it. But if it is a library targetted at other developers, you might want to include it.
Author
Owner

@tebanep commented on GitHub (Feb 28, 2016):

I think PATCH should also take into account refactoring as the process could both introduce new bugs or create performance improvements and users should know. Though the API has not changed, the program they are using is not the same that is being newly released, and this can create confusion.

<!-- gh-comment-id:189966642 --> @tebanep commented on GitHub (Feb 28, 2016): I think PATCH should also take into account refactoring as the process could both introduce new bugs or create performance improvements and users should know. Though the API has not changed, the program they are using is not the same that is being newly released, and this can create confusion.
Author
Owner

@benwiley4000 commented on GitHub (May 23, 2017):

Maybe the times have changed, but the thought of sneaking refactoring changes into an existing release sounds like blasphemy to me! Might just be the school of npm, which discards the possibility of doing that...

Anyway, I came to this thread wondering what the standard versioning procedure should be for refactoring/optimizations, and it seems like there isn't yet a solid recommendation.

My leaning is: obvious refactoring should happen before a release is cut. After that release is cut, refactoring can wait - commit it to the repo, and include it with the next release. If the refactoring was vital, it was probably to address a performance issue, which counts as a bug - warranting a patch version bump. It could also be argued that performance boost is a "feature." I'm really not sure how that should be interpreted.

Can we get some recommendation entered into the spec FAQ?

<!-- gh-comment-id:303296855 --> @benwiley4000 commented on GitHub (May 23, 2017): Maybe the times have changed, but the thought of sneaking refactoring changes into an existing release sounds like blasphemy to me! Might just be the school of npm, which discards the possibility of doing that... Anyway, I came to this thread wondering what the standard versioning procedure should be for refactoring/optimizations, and it seems like there isn't yet a solid recommendation. My leaning is: obvious refactoring should happen before a release is cut. After that release is cut, refactoring can wait - commit it to the repo, and include it with the next release. If the refactoring was vital, it was probably to address a performance issue, which counts as a bug - warranting a patch version bump. It could also be argued that performance boost is a "feature." I'm really not sure how that should be interpreted. Can we get some recommendation entered into the spec FAQ?
Author
Owner

@binki commented on GitHub (May 29, 2017):

Once a release is made, that release should never be changed. PATCH is used to indicate changes that should not break the API. This includes refactoring. Semver clearly states:

Once a versioned package has been released, the contents of that version MUST NOT be modified. Any modifications MUST be released as a new version.

Refactoring is a modification—even if it doesn’t cause any behavior change. You should be able to unambiguously identify the release pre-refactoring and post-refactoring.

The reason for requiring a new version for each released modification is that you might be mistaken and have accidentally introduced a behavior change. But that doesn’t mean that if you can skip the version increment if you can somehow “prove” that you didn’t introduce any behavior changes or bugs.

The only reason you would ever want to reuse a version number in a re-release after a refactoring or bugfix is if your API consumer is not using semver. Then the only way to get such a consumer to be willing to use the new release of the library is to re-use an existing version number. But, then, in such a situation, semver is not being respected, so the semver spec has nothing to say about that situation.

<!-- gh-comment-id:304551888 --> @binki commented on GitHub (May 29, 2017): Once a release is made, that release should never be changed. PATCH is used to indicate changes that *should not* break the API. This includes refactoring. Semver clearly states: > Once a versioned package has been released, the contents of that version MUST NOT be modified. Any modifications MUST be released as a new version. Refactoring is a modification—even if it doesn’t cause any behavior change. You should be able to unambiguously identify the release pre-refactoring and post-refactoring. The reason for requiring a new version for each released modification is that you might be mistaken and have accidentally introduced a behavior change. But that doesn’t mean that if you can skip the version increment if you can somehow “prove” that you didn’t introduce any behavior changes or bugs. The only reason you would ever **want** to reuse a version number in a re-release after a refactoring or bugfix is if your API consumer is **not** using semver. Then the only way to get such a consumer to be willing to use the new release of the library is to re-use an existing version number. But, then, in such a situation, semver is not being respected, so the semver spec has nothing to say about that situation.
Author
Owner

@Tieske commented on GitHub (May 29, 2017):

@binki I think this is a solid reasoning on how to deal with it, within the boundaries of the current semver spec.

But a FAQ entry explaining this as such would be nice.

<!-- gh-comment-id:304621425 --> @Tieske commented on GitHub (May 29, 2017): @binki I think this is a solid reasoning on how to deal with it, within the boundaries of the current semver spec. But a FAQ entry explaining this as such would be nice.
Author
Owner

@jwdonahue commented on GitHub (Dec 2, 2017):

#339

<!-- gh-comment-id:348668694 --> @jwdonahue commented on GitHub (Dec 2, 2017): #339
Author
Owner

@jwdonahue commented on GitHub (Dec 2, 2017):

@openjck

A refactor can be considered a patch-level change if nothing is broken by it. There MUST never be two packages with different contents, having the same version number. SemVer is as much about what your customer's expect as it is about what you are saying with the version. Refactored code is simply not the same as the previous version and should therefore get a version bump. Security conscious consumers need to know whether you've made changes to the code.

Please close this issue at your earliest possible convenience.

<!-- gh-comment-id:348669006 --> @jwdonahue commented on GitHub (Dec 2, 2017): @openjck A refactor can be considered a patch-level change if nothing is broken by it. There MUST never be two packages with different contents, having the same version number. SemVer is as much about what your customer's expect as it is about what you are saying with the version. Refactored code is simply not the same as the previous version and should therefore get a version bump. Security conscious consumers need to know whether you've made changes to the code. Please close this issue at your earliest possible convenience.
Author
Owner

@openjck commented on GitHub (Dec 2, 2017):

Is there plan to update the spec to make this clear? As described in the issue description, the spec contradicts itself right now.

<!-- gh-comment-id:348669756 --> @openjck commented on GitHub (Dec 2, 2017): Is there plan to update the spec to make this clear? As described in the issue description, the spec contradicts itself right now.
Author
Owner

@jwdonahue commented on GitHub (Dec 2, 2017):

@openjck, clone semver/semver.org, make your proposed changes and issue a PR to semver/semver.org. Little discernible work has been going on here at semver/semver lately. Personally, I think refactoring is in fact a bug fix, whether you actually wrote up a bug or work ticket to cover the changes, it's work done to remove accumulated engineering debt (design bugs) and falls into the category of bug fix, if no interface or behavioral changes were made.

<!-- gh-comment-id:348719311 --> @jwdonahue commented on GitHub (Dec 2, 2017): @openjck, clone semver/semver.org, make your proposed changes and issue a PR to semver/semver.org. Little discernible work has been going on here at semver/semver lately. Personally, I think refactoring is in fact a bug fix, whether you actually wrote up a bug or work ticket to cover the changes, it's work done to remove accumulated engineering debt (design bugs) and falls into the category of bug fix, if no interface or behavioral changes were made.
Author
Owner

@Tieske commented on GitHub (Dec 3, 2017):

See #415

<!-- gh-comment-id:348811258 --> @Tieske commented on GitHub (Dec 3, 2017): See #415
Author
Owner

@jwdonahue commented on GitHub (Dec 3, 2017):

@Tieske, please issue a pull request for your proposed changes to semver/semver.org, I like them, I will say so in a review of the code there, but I can't promise it will be accepted.

<!-- gh-comment-id:348823260 --> @jwdonahue commented on GitHub (Dec 3, 2017): @Tieske, please issue a pull request for [your proposed changes](https://github.com/Tieske/semver/commit/85ee7f8064601ca8c148fe78d6eba94367dd0434) to semver/semver.org, I like them, I will say so in a review of the code there, but I can't promise it will be accepted.
Author
Owner

@Tieske commented on GitHub (Dec 4, 2017):

@jwdonahue isn't semver/semver the source for semver/semver.org ?

<!-- gh-comment-id:348996782 --> @Tieske commented on GitHub (Dec 4, 2017): @jwdonahue isn't `semver/semver` the source for `semver/semver.org` ?
Author
Owner

@Tieske commented on GitHub (Dec 4, 2017):

if not, then why are there 2 repos?

<!-- gh-comment-id:348997353 --> @Tieske commented on GitHub (Dec 4, 2017): if not, then why are there 2 repos?
Author
Owner

@jwdonahue commented on GitHub (Dec 5, 2017):

@Tieske, I've asked that same question myself, no answer yet. All the actual work appears to be a happening over on sermver/semver.org.

@Haacked, inquiring minds want to know why two repo's?

<!-- gh-comment-id:349152282 --> @jwdonahue commented on GitHub (Dec 5, 2017): @Tieske, I've asked that same question myself, no answer yet. All the actual work appears to be a happening over on sermver/semver.org. @Haacked, inquiring minds want to know why two repo's?
Author
Owner

@haacked commented on GitHub (Dec 6, 2017):

semver/semver is the repository for the Semver specification. Any changes to the spec itself should go here. The semver/semver.org repository is the Jekyll repository that generates https://semver.org. Anything on the website that isn't in the spec should go there including translations and potentially supporting materials down the road.

<!-- gh-comment-id:349486750 --> @haacked commented on GitHub (Dec 6, 2017): semver/semver is the repository for the Semver specification. Any changes to the spec itself should go here. The semver/semver.org repository is the [Jekyll](https://jekyllrb.com/) repository that generates https://semver.org. Anything on the website that isn't in the spec should go there including translations and potentially supporting materials down the road.
Author
Owner

@jwdonahue commented on GitHub (Dec 6, 2017):

I think the readme.md file in each of the repositories should make it clear what they are each used for and provide links to the actual specification. Currently, the readme.md file in semver/semver, seems to be the spec itself.

<!-- gh-comment-id:349493424 --> @jwdonahue commented on GitHub (Dec 6, 2017): I think the readme.md file in each of the repositories should make it clear what they are each used for and provide links to the actual specification. Currently, the readme.md file in semver/semver, seems to be the spec itself.
Author
Owner

@silkentrance commented on GitHub (Dec 7, 2017):

While refactored code must never break existing tests, it might. If it breaks existing test, one would have to refactor the tests as well.

Get your gears straight.

@jwdonahue please close this regardless as it is nonsense.

<!-- gh-comment-id:349824783 --> @silkentrance commented on GitHub (Dec 7, 2017): While refactored code must never break existing tests, it might. If it breaks existing test, one would have to refactor the tests as well. Get your gears straight. @jwdonahue please close this regardless as it is nonsense.
Author
Owner

@mjavadhpour commented on GitHub (Jan 4, 2018):

Good article to handle refactor and release: Four strategies to version APIs and services

<!-- gh-comment-id:355409252 --> @mjavadhpour commented on GitHub (Jan 4, 2018): Good article to handle refactor and release: [Four strategies to version APIs and services](https://www.ibm.com/developerworks/library/mw-1710-phillips/index.html)
Author
Owner

@dorianneto commented on GitHub (Aug 24, 2018):

Good discussion! This is something I had a lot of doubts about how to act. Thanks all!

<!-- gh-comment-id:415746855 --> @dorianneto commented on GitHub (Aug 24, 2018): Good discussion! This is something I had a lot of doubts about how to act. Thanks all!
Author
Owner

@jwdonahue commented on GitHub (Oct 7, 2018):

@openjck, can you please close this issue at your earliest possible convenience? We're trying to reduce the number of none actionable open issues. Thank you.

<!-- gh-comment-id:427626526 --> @jwdonahue commented on GitHub (Oct 7, 2018): @openjck, can you please close this issue at your earliest possible convenience? We're trying to reduce the number of none actionable open issues. Thank you.
Author
Owner

@openjck commented on GitHub (Oct 7, 2018):

I'm happy to close, but I don't think this is really resolved. The three categories—major, minor, and patch—aren't exclusive. In addition to refactoring, others have pointed to documentation improvements as something that isn't covered by any of them.

I'll close, but I'll recommend additional attention to #415.

<!-- gh-comment-id:427626778 --> @openjck commented on GitHub (Oct 7, 2018): I'm happy to close, but I don't think this is really resolved. The three categories&mdash;major, minor, and patch&mdash;aren't exclusive. In addition to refactoring, others have pointed to documentation improvements as something that isn't covered by any of them. I'll close, but I'll recommend additional attention to #415.
Author
Owner

@nsajko commented on GitHub (Mar 1, 2025):

We're trying to reduce the number of none actionable open issues.

How is this not actionable? It's simply a bug in the spec. The specification should make it clear what to do with:

  • refactoring changes
  • performance improvements
  • doc changes
  • etc

The ambiguity conflicts with the very purpose of Semver.

<!-- gh-comment-id:2692194404 --> @nsajko commented on GitHub (Mar 1, 2025): > We're trying to reduce the number of none actionable open issues. How is this not actionable? It's simply a bug in the spec. The specification should make it clear what to do with: * refactoring changes * performance improvements * doc changes * etc The ambiguity conflicts with the very purpose of Semver.
Author
Owner

@ljharb commented on GitHub (Mar 1, 2025):

@nsajko the specification already makes it clear. is it breaking something? major. is it adding something? minor. Is it literally anything else, including an infinite list of things that it would be silly to enumerate? patch.

<!-- gh-comment-id:2692441310 --> @ljharb commented on GitHub (Mar 1, 2025): @nsajko the specification already makes it clear. is it breaking something? major. is it adding something? minor. Is it *literally anything else, including an infinite list of things that it would be silly to enumerate*? patch.
Author
Owner

@openjck commented on GitHub (Mar 1, 2025):

@nsajko the specification already makes it clear. is it breaking something? major. is it adding something? minor. Is it literally anything else, including an infinite list of things that it would be silly to enumerate? patch.

Having thought about this a bit last night, I do think updating the patch number after refactoring makes the most sense, if the refactoring needs to be released at all. I think it's also fine not to release refactored code until something more meaningful changes.

However, respectfully, and without trying to be needlessly pedantic, the spec doesn't appear to say that. As far as I can tell, the spec only talks about the patch number in relation to bugs. Please correct me if I'm wrong.

If this issue hadn't seen much activity since I opened it, I wouldn't suggest this, but given that there's been a fair number of comments and emoji reactions, maybe it would be good, and even save you all some frustration, to very briefly mention in the docs that everything else (everything that isn't a breaking API change or a feature) can be reflected by an incremented patch number.

<!-- gh-comment-id:2692454733 --> @openjck commented on GitHub (Mar 1, 2025): > [@nsajko](https://github.com/nsajko) the specification already makes it clear. is it breaking something? major. is it adding something? minor. Is it _literally anything else, including an infinite list of things that it would be silly to enumerate_? patch. Having thought about this a bit last night, I do think updating the patch number after refactoring makes the most sense, if the refactoring needs to be released at all. I think it's also fine not to release refactored code until something more meaningful changes. However, respectfully, and without trying to be needlessly pedantic, the spec doesn't appear to say that. As far as I can tell, the spec only talks about the patch number in relation to bugs. Please correct me if I'm wrong. If this issue hadn't seen much activity since I opened it, I wouldn't suggest this, but given that there's been a fair number of comments and emoji reactions, maybe it would be good, and even save you all some frustration, to very briefly mention in the docs that everything else (everything that isn't a breaking API change or a feature) can be reflected by an incremented patch number.
Author
Owner

@haacked commented on GitHub (Mar 1, 2025):

Having thought about this a bit last night, I do think updating the patch number after refactoring makes the most sense

I think these are orthogonal concerns. If the refactoring introduces a breaking change, then the Major version should changed. If a new feature was added during the refactoring, then increment the minor. And if the refactoring fixes a bug or improves performance (which could be regarded as fixing a perf bug), then increment the patch.

If it's a rare "pure" refactoring and no behavior has changed, not even bug fixes, then what's the point of releasing it? Releasing it is a collective inconvenience to all the package consumers who will be told that there's a new version of the package only to discover there's no bug fixes. When I see a new version of a package, I like to find out what bugs were fixed. It would be a waste of my time to investigate a new patch version only to discover nothing's changed. It's a disservice to the package consumers for what benefit?

One of the key points of Semver is to help package consumers decide whether they'll take an upgrade or not. A new package version that isn't an upgrade seems like a pointless exercise. At most, make it a pre-release of the next patch version if you feel compelled to release the same version again.

<!-- gh-comment-id:2692463708 --> @haacked commented on GitHub (Mar 1, 2025): > Having thought about this a bit last night, I do think updating the patch number after refactoring makes the most sense I think these are orthogonal concerns. If the refactoring introduces a breaking change, then the Major version should changed. If a new feature was added during the refactoring, then increment the minor. And if the refactoring fixes a bug or improves performance (which could be regarded as fixing a perf bug), then increment the patch. If it's a rare "pure" refactoring and no behavior has changed, not even bug fixes, then what's the point of releasing it? Releasing it is a collective inconvenience to all the package consumers who will be told that there's a new version of the package only to discover there's no bug fixes. When I see a new version of a package, I like to find out what bugs were fixed. It would be a waste of my time to investigate a new patch version only to discover nothing's changed. It's a disservice to the package consumers for what benefit? One of the key points of Semver is to help package consumers decide whether they'll take an upgrade or not. A new package version that isn't an upgrade seems like a pointless exercise. At most, make it a pre-release of the next patch version if you feel compelled to release the same version again.
Author
Owner

@jwdonahue commented on GitHub (Mar 2, 2025):

Where does refactoring fit into this? Refactored code is modified code, but the modifications do not necessarily contain any bug fixes.

The reason the spec essentially says "one versioned artifact per unique version string", is to avoid ambiguity. If you have multiple packages, each claiming to to be the same version V of that package, but they have different content hashes, which one is the real version V? Was one of them tampered with? What other SemVer rules were violated?

When you refactor code, you are in fact, fixing a bug. Maybe it's not a customer visible bug, or you're organization uses something like a non-bug "work order" to kick-off the effort, but there is some inherent defect in the code that is being fixed by the refactoring. Engineer's do not modify code without some underlying reason(s). Whether you bump major, minor or patch, depends on the level of risk you are taking with the release of those refactored bits. If you've done your job correctly, you probably fixed a whole slew of code defects, so it's likely just a patch bump.

If you don't have any unit or acceptance tests to prove you didn't break anything, you might want to consider adding those, or giving your product a major bump, just in case.

<!-- gh-comment-id:2692526118 --> @jwdonahue commented on GitHub (Mar 2, 2025): > Where does refactoring fit into this? Refactored code is modified code, but the modifications do not necessarily contain any bug fixes. The reason the spec essentially says "one versioned artifact per unique version string", is to avoid ambiguity. If you have multiple packages, each claiming to to be the same version V of that package, but they have different content hashes, which one is the real version V? Was one of them tampered with? What other SemVer rules were violated? When you refactor code, you are in fact, fixing a bug. Maybe it's not a customer visible bug, or you're organization uses something like a non-bug "work order" to kick-off the effort, but there is some inherent defect in the code that is being fixed by the refactoring. Engineer's do not modify code without some underlying reason(s). Whether you bump major, minor or patch, depends on the level of risk you are taking with the release of those refactored bits. If you've done your job correctly, you probably fixed a whole slew of code defects, so it's likely just a patch bump. If you don't have any unit or acceptance tests to prove you didn't break anything, you might want to consider adding those, or giving your product a major bump, just in case.
Author
Owner

@jwdonahue commented on GitHub (Mar 2, 2025):

However, respectfully, and without trying to be needlessly pedantic, the spec doesn't appear to say that. As far as I can tell, the spec only talks about the patch number in relation to bugs. Please correct me if I'm wrong.

Nope! I don't think you are wrong. But then, that is true of so many other things the spec does not say explicitly. Another thing that is true:

The spec says pretty much all that it has to say, for a thoughtful engineer, to be able to resolve those things on their own. Ya, many of us lack the confidence in our interpretations, but then we have this huge body of issues, discussing virtually all of those unsaid things.

If the spec tried to say everything, it would say nothing at all, because it would be virtually useless.

<!-- gh-comment-id:2692972703 --> @jwdonahue commented on GitHub (Mar 2, 2025): > However, respectfully, and without trying to be needlessly pedantic, the spec doesn't appear to say that. As far as I can tell, the spec only talks about the patch number in relation to bugs. Please correct me if I'm wrong. Nope! I don't think you are wrong. But then, that is true of so many other things the spec does not say explicitly. Another thing that is true: The spec says pretty much all that it has to say, for a thoughtful engineer, to be able to resolve those things on their own. Ya, many of us lack the confidence in our interpretations, but then we have this huge body of issues, discussing virtually all of those unsaid things. If the spec tried to say everything, it would say nothing at all, because it would be virtually useless.
Author
Owner

@openjck commented on GitHub (Mar 2, 2025):

I hear that, and it makes sense. I also agree with your advice that everything else (everything other than API changes and backwards-compatible features) can be a patch release (e.g., 1.0.0 -> 1.0.1), or an engineer can choose not to release those things until something more important needs to be released.

Given that advice, I'm comfortable with semver locking this comment thread. I don't think there's likely to be much more productive discussion here, and we've come to a reasonable (and imperfect, like everything) resolution.

<!-- gh-comment-id:2692977805 --> @openjck commented on GitHub (Mar 2, 2025): I hear that, and it makes sense. I also agree with your advice that _everything else_ (everything other than API changes and backwards-compatible features) can be a patch release (e.g., 1.0.0 -> 1.0.1), or an engineer can choose _not_ to release those things until something more important needs to be released. Given that advice, I'm comfortable with semver locking this comment thread. I don't think there's likely to be much more productive discussion here, and we've come to a reasonable (and imperfect, like everything) resolution.
Author
Owner

@jwdonahue commented on GitHub (Mar 3, 2025):

@haacked (good to hear from you again):

If it's a rare "pure" refactoring and no behavior has changed, not even bug fixes, then what's the point of releasing it? Releasing it is a collective inconvenience to all the package consumers who will be told that there's a new version of the package only to discover there's no bug fixes.

An excellent point, but there are cases where code smells, lead to refactoring. While not every stinky bit of code causes noticeable defects to most customers, it can be argued that a well run organization, can justify a refactor release, particularly if it's the refactor, the day before the code is put into maintenance or retirement mode.

<!-- gh-comment-id:2692979637 --> @jwdonahue commented on GitHub (Mar 3, 2025): @haacked (good to hear from you again): > If it's a rare "pure" refactoring and no behavior has changed, not even bug fixes, then what's the point of releasing it? Releasing it is a collective inconvenience to all the package consumers who will be told that there's a new version of the package only to discover there's no bug fixes. An excellent point, but there are cases where code smells, lead to refactoring. While not every stinky bit of code causes noticeable defects to most customers, it can be argued that a well run organization, can justify a refactor release, particularly if it's the refactor, the day before the code is put into maintenance or retirement mode.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/semver#1826