We take compatibility in .NET Framework and .NET Core extremely seriously. We use the breaking change process to manage and consider potential breaking changes.
Although .NET Core can be deployed app local, we are engineering it such that portable libraries can target it and still run on .NET Framework as well. This means that the behavior of .NET Framework can constrain the implementation of any overlapping APIs 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.
Note that these rules only apply to APIs that have shipped in a previous RTM release. New APIs still under development can be modified but we are still cautious not to disrupt the ecosystem unnecessarily when prerelease APIs change.
To help triage breaking changes, we classify them in to four buckets:
Clear violation of public contract.
Examples:
Change of behavior that customers would have reasonably depended on.
Examples:
These require judgment: how predictable, obvious, consistent was the behavior?
Change of behavior that customers could have depended on, but probably wouldn’t.
Examples:
As with changes in bucket 2, these require judgment: what is reasonable and what’s not?
Changes to surface area or behavior that is clearly internal or non-breaking in theory, but breaks an app.
Examples:
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.
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, we may decide to add a compat switch that allows consumers to bring back the old behavior if necessary.
Accepted. In some minor cases, we may decide to accept the change if the benefit is large and the risk is super low or if the risk is moderate and a compat switch isn’t viable.
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.