-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Update breaking change docs #13718
Update breaking change docs #13718
Changes from all commits
ab30810
3b782dc
68e4910
531e402
a208342
e9aefe1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,19 @@ | ||
| Breaking Changes | ||
| ================ | ||
| # Breaking Changes | ||
|
|
||
| We take compatibility in the .NET Framework and .NET Core extremely seriously. | ||
|
|
||
| Although .NET Core can be deployed app local, we are engineering it such that portable libraries can target it and still run on the full desktop framework as well. This means that the behavior of the full .NET Framework constrains the implementation of any overlapping API in .NET Core. | ||
| Although .NET Core can be deployed app local, we are engineering it such that | ||
| portable libraries can target it and still run on the full desktop framework as | ||
| well. This means that the behavior of the full .NET Framework constrains the | ||
| implementation of any overlapping API in .NET Core. | ||
|
|
||
| Below is a summary of some documentation we have internally about what kinds of things constitute breaking changes, how we categorize them, and how we decide what we're willing to take. | ||
| Below is a summary of some documentation we have internally about what kinds of | ||
| things constitute breaking changes, how we categorize them, and how we decide | ||
| what we're willing to take. | ||
|
|
||
| Note that these rules only apply to API that have shipped in a previous RTM release. New API still under development can be modified but we are still cautious not to disrupt the ecosystem unnecessarily when prerelease API change. | ||
| Note that these rules only apply to API that have shipped in a previous RTM | ||
| release. New API still under development can be modified but we are still | ||
| cautious not to disrupt the ecosystem unnecessarily when prerelease API change. | ||
|
|
||
| To help triage breaking changes, we classify them in to four buckets: | ||
|
|
||
|
|
@@ -16,47 +22,93 @@ To help triage breaking changes, we classify them in to four buckets: | |
| 3. Unlikely Grey Area | ||
| 4. Clearly Non-Public | ||
|
|
||
| ### Bucket 1: Public Contract | ||
| *Clear violation of public contract.* | ||
| ## Bucket 1: Public Contract | ||
| *Clear [violation of public contract][breaking-change].* | ||
|
|
||
| Examples: | ||
| * throwing a new/different exception type in an existing common scenario | ||
| * Renaming or removing of a public type, member, or parameter | ||
| * Changing the value of a public constant or enum member | ||
| * Sealing a type that wasn't sealed | ||
| * Making a virtual member abstract | ||
| * Adding an interface to the set of base types of an interfaces | ||
| * Removing a type or interface from the the of base types | ||
| * Changing the return type of a member | ||
| * ...or any other [incompatible change][breaking-change] to the shape of an API | ||
|
|
||
| [breaking-change]: breaking-change-rules.md#source-and-binary-compatibility-changes | ||
|
|
||
| ## Bucket 2: Reasonable Grey Area | ||
| *[Change of behavior][behavioral-changes] that customers would have reasonably | ||
| depended on.* | ||
|
|
||
| Examples: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we link to this section of the other document. |
||
|
|
||
| * Throwing a new/different exception type in an existing common scenario | ||
| * An exception is no longer thrown | ||
| * A different behavior is observed after the change for an input | ||
| * renaming a public type, member, or parameter | ||
| * decreasing the range of accepted values within a given parameter | ||
| * A new instance field is added to a type (impacts serialization) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only if we support cross version binary serialization right? Do we?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we have to. |
||
| * changing the value of a public constant or enum member | ||
| * Change in timing/order of events (even when not specified in docs) | ||
| * Change in parsing of input and throwing new errors (even if parsing behavior | ||
| is not specified in the docs) | ||
|
|
||
| ### Bucket 2: Reasonable Grey Area | ||
| *Change of behavior that customers would have reasonably depended on.* | ||
| These require judgment: how predictable, obvious, consistent was the behavior? | ||
|
|
||
| Examples: | ||
| * change in timing/order of events (even when not specified in docs) | ||
| * change in parsing of input and throwing new errors (even if parsing behavior is not specified in the docs) | ||
| [behavioral-changes]: breaking-change-rules.md#behavioral-changes | ||
|
|
||
| These require judgment: how predictable, obvious, consistent was the behavior? | ||
| ## Bucket 3: Unlikely Grey Area | ||
| *Change of behavior that customers could have depended on, but probably | ||
| wouldn't.* | ||
|
|
||
| Examples: | ||
|
|
||
| ### Bucket 3: Unlikely Grey Area | ||
| *Change of behavior that customers could have depended on, but probably wouldn't.* | ||
| * Correcting behavior in a subtle corner case | ||
|
|
||
| **Examples:** | ||
| * correcting behavior in a subtle corner case | ||
| As with type 2 changes, these require judgment: what is reasonable and what’s | ||
| not? | ||
|
|
||
| As with type 2 changes, these require judgment: what is reasonable and what’s not? | ||
| ## Bucket 4: Clearly Non-Public | ||
| *Changes to surface area or behavior that is clearly internal or non-breaking | ||
| in theory, but breaks an app.* | ||
|
|
||
| ### Bucket 4: Clearly Non-Public | ||
| *Changes to surface area or behavior that is clearly internal or non-breaking in theory, but breaks an app.* | ||
| Examples: | ||
|
|
||
| **Examples:** | ||
| * Changes to internal API that break private reflection | ||
|
|
||
| It is impossible to evolve a code base without making such changes, so we don't require up-front approval for these, but we will sometimes have to go back and revisit such change if there's too much pain inflicted on the ecosystem through a popular app or library. | ||
| It is impossible to evolve a code base without making such changes, so we don't | ||
| require up-front approval for these, but we will sometimes have to go back and | ||
| revisit such change if there's too much pain inflicted on the ecosystem through | ||
| a popular app or library. | ||
|
|
||
| This bucket is painful for the machine-wide .NET Framework, but we do have much | ||
| more latitude here in .NET Core. | ||
|
|
||
| ## What This Means for Contributors | ||
|
|
||
| * All bucket 1, 2, and 3 breaking changes require talking to the repo owners | ||
| first: | ||
| - We generally **don't accept** change proposals that are in bucket #1. | ||
| - We **might accept** change proposals that are in #2 and #3 after a | ||
| risk-benefit analysis. See below for more details. | ||
| - We **usually accept** changes that are in bucket #4 | ||
| * If you're not sure in which bucket applies to a given change, contact us as | ||
| well. | ||
|
|
||
| ### Risk-Benefit Analysis | ||
|
|
||
| For buckets #2 and #3 we apply a risk-benefit analysis. It doesn't matter if the | ||
| old behavior is "wrong", we still need to think through the implications. This | ||
| can result in one of the following outcomes: | ||
|
|
||
| * **Accepted with compat switch**. Depending on the estimated customer impact, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this talking about .NET Core or just .NET Framework? I don't think we should ever have compat switches (a la .NET Framework) for .NET Core, especially not for future fixes we make.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have compat switches for .NET Core.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you link me where we're using them? I searched around and didn't see any. If we have some for existing code that's a bit unfortunate, but I really don't think we should have any more going forward, personally.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @AlexGhiondea would know more but check this out:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mellinoe why do you think we should not have compat switches? They are quite useful in various scenarios. Currently we do not have the quirk semantics for them (i.e. Automatically enable switches based on TFM) but one can define them in the json file for your application and/or set them in code. The link Immo added is about the quirks inside Corelib, but we also have them inside system.Xml as well.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It is what we have been in full .NET Framework. In .NET Core, we should be more data driven and only have quirks for behaviors that are proven to be actually breaking real .NET Core apps and being asked for. My 2 cents... .
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I remember right, it was an intentional decision to not quirk every single breaking change. The idea (at the time) was that we would handle breaking changes by package versions. If we introduced a break in a version, people would either upgrade to the new version and deal with the break, or continue to use the previous version and not be impacted. That model works great until we start talking about shared framework and the possibility of rolling forward user applications. In that case, you are talking about a very similar model to what we have on Desktop where the framework on which a user application is running on might change underneath them. And for these cases we have to have a way to prevent breaking them. I don't think quirking every change is the way to go - we don't do that on Desktop either. Having some good telemetry as @jkotas suggests is going to make it easier to decide if a change needs a quirk or not.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I guess this is where part of my confusion is coming from, because "rolling forward applications" is something that the product is explicitly designed to forbid right now, on quite a few different levels. Compat switches make a little more sense in that world, although I still don't like them as a technical solution.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think no one is arguing that we need to quirk every single breaking change. The purpose of this document is to outline what flexibility we have and how we're thinking about the process, specifically for .NET Core. In fact, you're preaching to the choir as I was involved in quite a few (perfectly fine 😄 ) API additions that we had to back out or quirk due to the (insanely) high bar for .NET Framework. That's why I'm spreading the word that app-local deployments are the way to go. At the same time, @weshaggard keeps reminding me (and right fully so) that the combination of success and sharing will involve a higher compat bar than we like. However, I also think it will never be as high as it is for .NET Framework. But practically speaking, compat switches/TFM-specific behaviors will eventually be the saving grace in order to not prevent progress.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes lets avoid quirks as long and much as possible... but there will come a day in .NET Core were we will need them mark my words :) |
||
| we may decide to add a compat switch that allows consumers to bring back the | ||
| old behavior if neessary. | ||
|
|
||
| * **Accepted**. In some minor cases, we may decide to accept the change if the | ||
| the benefit is large and the risk is super low or if the risk is moderate and | ||
| quirking isn't viable. | ||
|
|
||
| This bucket is painful for the machine-wide .NET Framework, but we do have much more latitude here in .NET Core. | ||
| * **Rejected**. If the risk is too high and/or the improvement too minor, we may | ||
| decide not to accept the change proposal at all. We can help identify | ||
| alternatives such as introducing a new API and obsoleting the old one. | ||
|
|
||
| ### What This Means for Contributors | ||
| * All bucket 1, 2, and 3 breaking changes require talking to the repo owners first. | ||
| * If you're not sure in which bucket applies to a given change, contact us as well. | ||
| * It doesn't matter if the old behavior is "wrong", we still need to think through the implications. | ||
| * If a change is deemed too breaking, we can help identify alternatives such as introducing a new API and obsoleting the old one. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💭 This would still apply if the exception type and scenario is explicitly documented
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you asking whether documentation changes anything? No, because people usually can't and thus don't test if their code works in accordance to our docs. They test whether their code works with our implementation :-)