-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Add guidance for .NET library dependency versions #49958
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
base: main
Are you sure you want to change the base?
Conversation
Added guidance for selecting .NET library dependency versions, including strategies, tradeoffs, and recommendations for library authors.
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.
Pull Request Overview
This PR introduces comprehensive guidance for .NET library authors on selecting dependency versions when targeting multiple .NET framework versions. The document outlines three primary strategies (latest supported versions, TFM-specific versions, and branching), their tradeoffs, and provides concrete recommendations with code examples.
Key changes:
- New guidance document explaining dependency version selection strategies for .NET libraries.
- Decision matrix comparing engineering, servicing, and update friction costs across strategies.
- Code examples demonstrating each approach using System.Text.Json references.
| |---------------------------------------|------------------|------------------|------------------| | ||
| | Latest Supported Versions (Option 1) | Moderate | Low | Moderate | | ||
| | TFM-Specific Versions (Option 2) | Low | High | Low / Moderate | | ||
| | Branching | Low | Low | High | |
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.
| | Branching | Low | Low | High | | |
| | Branching | Low | High | High | |
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.
No, the engineering cost of the branching solution is low. Here I use "engineering" to mean steady-state engineering cost in main and I contrast that with "servicing cost". Let me know if you can think of a better term to use.
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.
I'm wondering if we should even give this option. What is an example of a library that would follow this? Where they basically only add new functionality to the latest TFM support? Are there any examples outside of the .NET Team?
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 is the option for any product that leverages branches to control risk. I do think it's important to call this out, since it does relate to plenty of folks asking these questions, and shows customers how we solve this problem. It's also a fine compromise, since it can be done after the fact for an on-demand release (eg: a security bug, for instance).
I can run a scan of nuget to see which packages use branching like this.
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.
In the top 100 non-microsoft packages, the following use branches to manage risk, determined by observing lower major versions published after higher major versions.
AWSSDK.Core
Castle.Core
Moq
AutoMapper
FluentValidation
Npgsql
FluentAssertions
NUnit
NLog
AWSSDK.S3
RabbitMQ.Client
FluentValidation.DependencyInjectionExtensions
Npgsql.EntityFrameworkCore.PostgreSQL
Elasticsearch.Net
AWSSDK.SecurityToken
FluentValidation.AspNetCore
NodaTime
jQuery
MessagePack
AWSSDK.SQS
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.
That query seems inconsistent with the definition of "Option 3: Branching"
but branch your library in sync with target frameworks. This is the same as Option 1, but each time a new framework is added, a new major version / branch is created to allow for updating the major version of dependencies and adding the new target framework.
The only packages in your list that I know does that are the 2 Npgsql ones.
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.
Right, but folks can be familiar with branching a general strategy, just because they don't use it precisely the way described doesn't mean it's a foreign idea.
It's also important to understand that it's how all the .NET libraries deal with this problem, and what characteristics that creates.
Maybe I can add a note under branching that some .NET packages do this and drop support for past frameworks (to further reduce engineering cost in the current codebase) but how we DON'T recommend that folks do this in general for libraries since it requires consumers to multi-target their dependencies, while normal branching strategies just give folks the option to multi-target dependencies.
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.
Maybe I can add a note under branching
That sounds good to me. Thanks
Show contrast to framework overlapping package and not.
|
|
||
| Library authors face challenges when deciding which version of a .NET dependency to reference. Newer versions have more API and features, but may require a local redistribution increasing servicing responsibilities of the library and size of the application. The decision impacts: | ||
|
|
||
| - **Friction of updates** on older runtimes |
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 list of decision impacts is only focusing on the negatives. It doesn't touch on the benefits of utilizing newer features and APIs, bug fixes, performance improvements, etc., nor on what folks need to do to work around the lack of such things, like polyfills, which can be both hard to get right (if possible to get 100% right) and require substantial amounts of code.
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.
I do cover that below, I see most of that as rolling up in "engineering cost". Let me know if you can think of another column to add here to focus on "quality" of the dependencies.
Co-authored-by: Stephen Toub <stoub@microsoft.com>
This is first draft. I might be assuming too much familiarity with the problem space. Please provide feedback 🤝
Internal previews