Sdk: What should be default RollForward for component projects

Created on 7 Jun 2019  Â·  9Comments  Â·  Source: dotnet/sdk

We haven’t made an official decision on the default value for RollForward in our new component scenarios.

TLDR;
Should we use LatestMinor or LatestMajor for component projects by default.

The long version:
Currently RollForward is set to Minor (roll to closest available version while staying with the same major. part of the version, then roll to latest patch of that version) for all projects by default. This is the value used when no RollForward is specified by the SDK in .runtimeconfig.json. More details about RollForward are here and here.

For dynamically loaded components this value would come with problems. The most important one being ordering issues. For example let’s have two COM components A 3.0 Minor and B 3.1 Minor on a machine which has both 3.0 and 3.1 installed. If the native app activates B first, it will load 3.1 runtime and then when it activates A second it will just work (since A can run on 3.1). But if the app activates A first, it would load 3.0 (closest available match to 3.0 Minor) and then when it would try to activate B that would fail (B is not compatible with 3.0).

To overcome this problem the RollForward has two settings:

  • LatestMinor – pick the highest available version with the same major. part of the version (so 3.0 LatestMinor would roll to latest 3.* version)
  • LatestMajor – pick the highest available version (all up)

If in the above scenario A would be 3.0 LatestMinor and B would be 3.1 LatestMinor, no matter which one got activated first, they both would load 3.1 (as the latest 3.* available version).

So to make it easy for users and make things just work out of the box, we would like to set RollForward to one of the LatestMinor/LatestMajor by default on component projects.
Elinor has a PR out which introduces the notion of “component project”: https://github.com/dotnet/sdk/pull/3305

The question is if we should use LatestMinor or LatestMajor as the default for component projects.

LatestMinor:

  • Pros: Higher chance of providing the expected compatibility – in general we try really hard to avoid breaking changes for minor versions, so 3.1 is expected to be fully backward compatible with 3.0. We tell people that upgrading to minor version is “safe”.
  • Cons: Come .NET 5 components targeting 3.0 would not run on 5.0. Basically creating an upgrade problem. Combining components targeting both 3.0 and 5.0 would fail.

LatestMajor:

  • Pros: No upgrade problems – all components run everywhere and together.
  • Cons: Potentially breaking for some components as we may introduce some breaking changes between 5.0 and 3.0. That said classlibs (which components are a special case of) are already assumed to work just fine even across major versions (NuGet has no notion of compatibility ranges, and will let people use 3.0 classlibs in 5.0 projects).

Some related discussions already happened:
https://github.com/dotnet/core-setup/issues/5870
https://github.com/dotnet/core-setup/issues/5062

Thoughs?

All 9 comments

For me LatestMajor feels a bit risky as a default, but it also means things will mostly just work. I guess in this case LatestMajor is probably the better choice:

  • We will be very careful about introducing breaking changes in 5.0 and probably even more so going forward.
  • For most people things will just work out of the box
  • For the few where things break, they can easily change the setting to LatestMinor if needed. And we will probably ask people to test on new major releases (like 5.0) before deployment anyway.

@richlander @elinor-fung @AaronRobinsonMSFT @sdmaclea @jeffschwMSFT @nguerrera @jkoritzinsky @swaroop-sridhar

That said classlibs (which components are a special case of) are already assumed to work just fine even across major versions

I make this point all the time, and I get pushback that I'll try to represent. The thinking is that the app owner should be responsible for testing and retargeting their app. They may discover that a classlib they use does not work for them, and the follow up with classlib owner about it, use another classlib, work around the part of classlib that broke, etc.

Apart from that there is no difference between classlib and app, each is equally likely to break. The difference is that the classlib doesn't decide for itself where it runs.

So components are more like apps in that sense. If they manifest what is ok to use, they are the ones taking responsibility for a range that might not work.

I think the only way to adress both concerns would be to have in-proc side by side across major versions. Clr 2.0 and 4.0 could do this, right? Has it been considered for coreclr?

I'll let @jkotas comment on the runtime SxS story, I'm not aware of any plans in that direction...

I guess the component is a bit of both - like an app in that sense that it sometimes starts the runtime and like a classlib in that it sometimes gets loaded into already existing runtime.

So if we think components are more like apps, then LatestMinor would be the better default (would match app's Minor default with higher compatibility guarantees).
If we think components are more like classlibs, then LatestMajor would be the better default as it closely matches the current expectations around classlibs.

From https://semver.org/#semantic-versioning-200

Semantic Versioning 2.0.0

Summary
Given a version number MAJOR.MINOR.PATCH, increment the:
1. MAJOR version when you make incompatible API changes,
2. MINOR version when you add functionality in a backwards-compatible manner, and
3. PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

If we expect incompatible API changes in Major changes then the default should be LatestMinor.

In general we don't make incompatible API changes, even for Major releases, but library authors may...

Clr 2.0 and 4.0 could do this, right?

Clr 2.0 and 4.0 could do this in theory. We spent incredible amount of resources to build the SxS for 2.0/4.0, but it still comes with number of limitations that are hard to fix and very few apps use it in practice. We have seen folks give it a try and then deciding that it is just not worth the trouble.

We should reconsider repeating the exercise for .NET Core only if there is strong evidence that the outcome will be different.

For me LatestMajor feels a bit risky as a default,

I agree. We want to be in a place where installing latest .NET Core runtime on a machine is a very safe operation that has near zero chance of breaking anything existing on the machine (in particular on end-user, non-developer machines). We do not want to be in place where installing the latest .NET Core runtime breaks random things and folks refuse to do that. It is the situation we are in with .NET Framework and that makes any change in .NET Framework super risky.

Thus, LatestMajor should never be the default for any of our projects.

we don't make incompatible API changes

This is about probabilities. Code churn - even if you think that all that all you are doing is compatible - always results in breakages.

@jkotas In that case even LatestMinor is risky as installing new minor release could still break things. That said I agree we're much more careful about changes in minor releases.

we don't make incompatible API changes

This is about probabilities. Code churn - even if you think that all that all you are doing is compatible - always results in breakages.

Breaking changes across major version is a thing and one of the basic reasons for having a major versioning scheme. If there were never any breaking changes, then versioning as a concept would simply be a marketing exercise.

Thus, LatestMajor should never be the default for any of our projects.

Agreed.

LatestMinor it is - code change made in #3305

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fmorriso picture fmorriso  Â·  3Comments

thomaslevesque picture thomaslevesque  Â·  3Comments

aguacongas picture aguacongas  Â·  3Comments

joffreykern picture joffreykern  Â·  3Comments

srivatsn picture srivatsn  Â·  3Comments