Skip to content

Adding guidance on what is considered a breaking change in the .NET SDK #45288

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

Merged
merged 4 commits into from
Mar 20, 2025

Conversation

baronfel
Copy link
Member

@baronfel baronfel commented Dec 3, 2024

Adding guidance for breaking changes in the .NET SDK

@ghost ghost added Area-Infrastructure untriaged Request triage from a team member labels Dec 3, 2024
@baronfel baronfel force-pushed the doc-change-guidance branch from ee0019b to f67cb20 Compare December 3, 2024 20:59
@aortiz-msft aortiz-msft marked this pull request as ready for review February 28, 2025 00:31
@Copilot Copilot AI review requested due to automatic review settings February 28, 2025 00:31
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Overview

This PR introduces a draft guidelines document for managing breaking changes and diagnostics in the .NET SDK and updates the README to include a reference to the new document.

  • Introduces a comprehensive draft outlining procedures, types of changes, and available configuration knobs.
  • Updates the documentation index to include a link to the new guidelines.

Reviewed Changes

File Description
documentation/project-docs/breaking-change-guidelines.md Added a draft document outlining breaking change guidelines for the SDK.
documentation/README.md Updated to include a link to the new breaking change guidelines.

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

@aortiz-msft
Copy link
Contributor

@baronfel, @marcpopMSFT - I have pushed a commit with updates to the original draft from @baronfel . Would you please take a look? Who else should review?

Copy link
Contributor

@donnie-msft donnie-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to see breaking changes procedures called out!
One thing I'm unclear on is who is the audience for this? Overall, the wording feels very strong and not welcoming for public contributions. It feels like an instruction manual for the PM team or similar. Is that the goal?

Comment on lines 8 to 12

* introducing new changes in a staged/gradual way
* trying to tie opinionated analyzers/diagnostics to a mechanism that requires explicit user opt-in
* providing a way to opt out of a change entirely

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The other bulleted lists begin with a capital letter. I prefer capital for lists and would suggest doing that here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

### Cut-over to new behavior after a long introduction period

After the change has been introduced in a gradual way, cut over to the new behavior. This may mean removing the old behavior entirely, or it may mean making the new behavior the default and providing a way to opt out of it. It is important that you
provide enough time for users to adapt - for example the `dotnet new --list` example above took an entire major release to make the new forms the default.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest a newline for each start of sentence to make future updates cleaner.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm following the convention of other markdown in the repo.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Git diffs on markdown work better with my suggestion. Up to you whether that's important.

Have some kind of knob that allows users to opt out of the change entirely. This could be a flag, an environment variable, or a global.json setting. This allows users to continue using the old behavior if they need to in exceptional situations. It is
important to document this knob and its behavior in the SDK documentation. It is also important to define a timeline for when this knob will be removed entirely, forcing users to adopt the new behavior.

For systems like Analyzers that time may be 'never', because the cost of detection is so low. This is a product-level decision that is hard to give universal guidance for.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Maybe italics instead of a code callout for never

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


Changes that are expected to cause significant disruption should only be introduced behind the Target Framework knob. This eliminates business continuity and allows developers to address changes needed as part of scheduled work to migrate a codebase to a new TFM.

Concrete example: NuGet warnings for vulnerable transitive dependencies were introduced only for applications targeting .NET 10 and higher.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the terminology "concrete" is a bit strong and unnecessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change to "specific"

## Other recommendations

* If possible, introduce significant breaking changes in a non-LTS release.
* Publish blog posts and update public documentation as appropriate as early as possible.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who is the audience for this document? Who are we asking to publish a blog? I would imagine this is an internal PM responsibility, but it reads to me like we are asking anyone contributing to the SDK to publish a blog.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

@Nigusu-Allehu Nigusu-Allehu self-requested a review March 3, 2025 16:49

## Configuration Knobs

The following knobs are available to enable/disable these changes (some may not apply to all kinds of changes):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change waves and LangVer also apply to the tooling ecosystem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LangVer - I read https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version, and it looks like it's the same as TFM for .NET Core. So, I'm wondering in which cases langver would be used instead of TFM.

Change waves - I found a description here: https://learn.microsoft.com/en-us/visualstudio/msbuild/change-waves?view=vs-2022. Moving forward, do we recommend people using change waves or using the new SdkAnalysisLevel property?

@baronfel

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LangVersion is often the same as the numeric part of TFM, but that's purely a convenience. Users often set it explicitly when

  • multitargeting and wanting to ensure a consistent level of analysis across TFMs
  • when they want to use preview language features

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MSBuild Change Waves are necessary still for changes to MSBuild engine behavior, especially changes that occur before project evaluation takes place (e.g. globbing). MSBuild engine changes remain a place where we do not have great user-facing controls. MSBuild logic (props/targets files) are great for SdkAnalysisLevel, WarningLevel, etc knobs that we already have.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

In general, we want to make updating the .NET SDK as smooth as possible for developers. This means:

* introducing new changes in a staged/gradual way
* trying to tie opinionated analyzers/diagnostics to a mechanism that requires explicit user opt-in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what opinionated means in this context. Maybe just remove or are there specific types of diagnostics that you would include and some you wouldn't.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* Implementation changes for MSBuild Tasks
* NuGet Restore algorithm enhancements
* Changes to DotNet CLI grammar
* Changes to defaults in CLI flags that impact behavior
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes to CLI behavior itself. For example, we're considering changing dotnet clean to clean everything, not just your tfm/rid config which is what it does today.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

### Implement changes in an informational/non-blocking way initially

What this means will vary change-to-change. For example, for a change expressed as an Analyzer or MSBuild diagnostic, consider
Informational level severities initially. For a behavioral change on a CLI, consider an informational message written to the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

theoretically, this is also breaking but we have to draw a line somewhere and I think if some script is reading and depending on the stderr output, that seems like a reasonable line to draw.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rainersigwald - Based on your experience, should changes int the output be considered breaking?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes in output can certainly be breaking. MSBuild has had to demote some high-importance info messages (e.g. dotnet/msbuild#9228) because including location and/or a code made them look "too much" like warnings for enough users.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed.


If a change in introduced in an informational/non-blocking way, determine the time frame where it is safe to increase the severity. For Analyzers, this may mean tying it to the next value of AnalysisLevel (which is downstream of TFM). For small MSBuild and NuGet diagnostics, this may mean tying it to the next Warning Level or SdkAnalysisLevel. For CLI changes, this may mean tying it to the next LTS major version of the SDK. Ideally the way you would structure this increase would be automated and documented so that users know what's coming down the pipe.

### Cut-over to new behavior after a long introduction period
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, for CLI grammar, our model has been one release with both the new and old, one release with a message when using the old, and then remove in the third release. I don't know if we've done a good job of always having a release where they are both available first and I'm also not always in a rush to remove things later. An example would be dotnet package add versus dotnet add package.

I don't know if you want to specifically call out this as gradually increase over major release fwiw.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I called this out separately now.


### Always provide a way to opt out of the change

Have some kind of knob that allows users to opt out of the change entirely. This could be a flag, an environment variable, or a global.json setting. This allows users to continue using the old behavior if they need to in exceptional situations. It is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to avoid global.json settings. That should be used in limited scenarios and not for flags like this. I also think that env variables are not preferred if you can help it as you have to set them before you run (though they are required for some types of changes like msbuild enginge changes). By flag, you should call out project property (unless you meant something else).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed.

### Always provide a way to opt out of the change

Have some kind of knob that allows users to opt out of the change entirely. This could be a flag, an environment variable, or a global.json setting. This allows users to continue using the old behavior if they need to in exceptional situations. It is
important to document this knob and its behavior in the SDK documentation. It is also important to define a timeline for when this knob will be removed entirely, forcing users to adopt the new behavior.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, I might never remove some knobs if they are simple properties or env variables. I don't think Roslyn removes langver support but we should check with them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh, you mention that may be never for analyzers below. I might include items that have a simple on/off.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the break line.


### Tie potentially impactful changes to the TFM targeted by the application/library.

Changes that are expected to cause significant disruption should only be introduced behind the Target Framework knob. This eliminates business continuity and allows developers to address changes needed as part of scheduled work to migrate a codebase to a new TFM.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might explicitly state that this is preferred where possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current wording is a bit stronger, and I think that's something good. Thoughts?


## Other recommendations

* If possible, introduce significant breaking changes in a non-LTS release.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, .NET leadership does not consider there to be a separate bar for LTS versus STS when it comes to things like this. Not sure if you included this coming from VS guidance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.


Concrete example: NuGet warnings for vulnerable transitive dependencies were introduced only for applications targeting .NET 10 and higher.

## Other recommendations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to mention the breaking change label, tactics, or any of the internal aliases?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is public documentation, but the breaking-change label is relevant. I'll add that.

@aortiz-msft aortiz-msft changed the title Draft of guidelines for managing various kinds of breaking changes in the SDK Adding guidance on what is considered a breaking change in the .NET SDK Mar 20, 2025
@aortiz-msft aortiz-msft merged commit 3f5719f into dotnet:main Mar 20, 2025
8 checks passed
### Cut-over to new behavior after a long introduction period

After the change has been introduced in a gradual way, cut over to the new behavior. This may mean removing the old behavior entirely, or it may mean making the new behavior the default and providing a way to opt out of it. It is important that you
provide enough time for users to adapt - for example the `dotnet new --list` example above took an entire major release to make the new forms the default.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Git diffs on markdown work better with my suggestion. Up to you whether that's important.

## Required process for all .NET SDK breaking changes

* Create an issue in the appropriate GitHub repository to track the change, if one does not already exist.
* Add the breaking-change label to the issue. This label should be available in all .NET repositories that ship as part of the .NET SDK. If the label is not available, please file an issue in [dotnet/sdk](https://github.com/dotnet/sdk).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Add the breaking-change label to the issue. This label should be available in all .NET repositories that ship as part of the .NET SDK. If the label is not available, please file an issue in [dotnet/sdk](https://github.com/dotnet/sdk).
* Add the breaking-change label to the issue. This label should be available in all .NET repositories that ship as part of the .NET SDK. If the label is not available, please file an issue in [dotnet/sdk](https://github.com/dotnet/sdk/issues).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Infrastructure untriaged Request triage from a team member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants