不断发展的.NET生态系统

2020-12-16 02:00:57

该文档是.NET 6规划过程的输出。它是从Microsoft的角度编写的,并且是基于我们对.NET生态系统的了解的问题陈述和断言的集合。最后的各节包含我们要采取的后续步骤,以验证或无效本文档中的某些显式(或隐式)假设。我们正在与.NET Foundation有关生态系统增长的工作组进行合作,并在那里也介绍了此文档。

如今,客户和内部合作伙伴经常(甚至每周一次)与我们联系,以建立.NET生态系统中已经存在的库,因为人们认为他们无法信任第三方-有时甚至在技术不可靠时也可以信任第一方。 39; .NET的一部分。这导致了一个负面循环,从而增加了Microsoft的新一等库,这进一步突显了质量和寿命仅由Microsoft提供的观点,并且这种观点还在继续。

在.NET Core 3.1时间框架内,我们启动了一个成熟度模型,由于多种原因,该模型与.NET社区的合作并不顺利,但主要是因为我们采用了&与社区沟通。我们相信我们可以从这一经验中学到东西,然后再次提出这个想法。

总体目标是使.NET使用者能够做出信任决策,并鼓励客户(内部和外部)信任Microsoft所建的库。这项工作将包括使用库时(例如使用NuGet UI添加软件包时)的用户体验,一组定义好的实践(例如使源代码和符号可用于调试以及允许修补代码),定义的开发过程(如何分发发行版,处理重大更改和安全性问题)以及旨在增加非Microsoft控制的库集的计划。

在.NET生态系统中关键模型的采用可能需要数年时间,但是.NET 6的目标是创建愿景,从.NETFoundation和整个开源社区获得支持,并获得其中的一些基本面就位。

人们认为其他生态系统(尤其是Java,JavaScript和Python)具有更多的技术多样性,因此总体上来说更强大。从历史上看,我们曾教过客户期望所有功能都来自微软。由于我们无法构建所有内容,尤其是不能按照其他OSS生态系统的发展步伐进行构建,因此.NET的受信任库集必须不仅限于Microsoft。

我们需要规范化实践,使应用程序开发人员可以依赖不受Microsoft控制的库。

这要求我们使客户更容易评估质量,并使包装作者更容易提供一致的质量。本文档中的其他目标解决了这一问题。

这也需要微软改变文化。如今,当涉及到库&框架投资。等到我们知道需要一个库(例如,新的序列化协议)时,我们会常规研究现有的选项,但通常最终会滚动自己的选项,因为没有什么比照原样适合我们了,或者我们没有时间或没有时间。我们相信,我们将无法成功影响现有图书馆的设计。这会导致Microsoft误以为是知觉。之所以不在OSS生态系统中,是因为我们的解决方案通常会得到进一步推广,并且通常会紧密集成到平台中,从而使现有解决方案的吸引力降低。几位维护者认为这是他们放弃或避免建立看似基础的库的原因。请参阅本节的博客文章指针。

为避免这种情况,我们需要开始与现有库的所有者接触,并与他们合作以提高其质量(这意味着过程,模式和工具可用性的文档,这是本文档中的另一个目标解决的问题)。我们已经使用gRPC,OpenTelemetry和Apache Arrow / Spark相当成功地做到了这一点,但是它应该成为一种通用做法。我们甚至应该考虑一个正在进行的工作项,以积极地调查广泛使用的库,并帮助它们提高质量或加强其与.NET开发人员体验的集成。本文档中有一个单独的目标,该目标描述了为第三方提供支持的产品扩展点的需求。

当我们创建尚无生态系统的全新技术时,我们还需要更改方法,例如针对.NET Core的基于GPIO的IOT库就是这种情况。代替我们构建所有项目,我们应该以不是唯一的维护者的方式创建新项目,并积极寻找并邀请外部贡献者参与长期所有权和维护。这也包括我们的命名模式。例如,使用Microsoft命名包和名称空间已成为一种规范,这对于创建多供应商项目不是很友好。

.NET OSS生态系统中存在的一个挑战是,大多数成功的图书馆都是由一个人作为爱好开发的。虽然这通常会导致获得高评价的库(因为它们是爱的劳动),但它会给维护者的职业倦怠带来很高的风险,从而给支持和寿命带来不确定性。这在我们在.NET Foundation和董事会成员中看到的项目中也得到了体现-几乎没有人能奢侈地得到公司的酬劳来完成这项工作。

当您查看其他基金会(例如Linux Foundation或ApacheFoundation)时,会看到完全不同的图景:大多数维护人员并不是将其作为一种业余爱好,他们是员工,并且作为工作的一部分而从事这项工作。这在《在公共场所工作:开源软件的制作和维护》一书中也有介绍。

虽然.NET生态系统(三星或Unity)中存在例外,但这并不是规范。 Microsoft应该在.NETFoundation方面发挥更积极的作用,并帮助创建一个由公司赞助的“维护者计划”的程序,也就是说,他们赞助一名或多名帮助维护给定库的员工他们的工作。目标是创建类似于Apache Foundation的工作方式的库,这些库由各公司的员工共同拥有。这将替代金钱赞助,因为金钱赞助无法提供可靠的收入,因此对减少维持者的作用很小。压力,因为它仍然要求在OSS承诺与工作和个人生活之间取得平衡。也许微软也应该游说使.NET Foundation与Apache相似,Apache显然已经做出了一致的努力,以确保项目委员会成员的多样性,以使单方撤回权益不会危害项目。

另一个挑战是支持。似乎有一种感觉,即始终支持Microsoft生产的代码,而其他任何代码都不支持。我们经常听到需要支持的原因,这就是为什么选择非Microsoft库的原因,但目前尚不清楚这是否意味着可以选择付费支持,还是只是缺乏对库是否会被信任的信心。大约在明天。我们应该在这一领域进行客户开发,并使用结果告知是否需要为非Microsoft库提供付费支持。如果有的话,我们应该与.NET Foundation一起定义该模型的工作方式,以便公司可以为他们无法控制的库提供支持。这不仅包括Microsoft,还包括其他公司(例如Red Hat,Samsung或希望提供付费支持的其他公司)。

我们需要为图书馆定义联合所有权机制。我们应该在IOT库的上下文中尝试这样做(并可能会引起其他客户的要求,例如我们可能永远不会添加到BCL的其他集合)。

我们需要与现有的OSS维护人员进行客户开发,以了解维护人员是否是解决维护人员倦怠并确保项目寿命的好计划。

我们应该使用遥测,客户和合作伙伴输入来选择一组非Microsoft拥有的库,我们可以帮助它们做得更好。这包括提供API审核,以及提供修复程序和功能。目的是要不断努力,以便我们将专业知识传播到Microsoft以外,并使无论谁拥有代码的.NET更好的实践规范化。

Microsoft,企业客户和ISV的内部合作伙伴,这些合作伙伴使用OSS库并且对质量和支持有所关注

为了平衡竞争环境,并使.NET平台可以推广和押注非Microsoft控制的技术,我们需要能够提供经过精心策划的发现与开发功能。第一方和第三方使用的可选组件的采购经验。

在Microsoft,我们努力提供端到端的体验,例如,构建Windows Forms应用程序需要一个共享框架,一组项目和项目模板,Visual Studio中的工具以及文档。我们将所有这些作为核心产品的一部分提供,因为这使体验变得无缝。

借助.NET 6和对移动工作负载的支持,我们正在转向一个模型,其中.NET的一部分是可选的。这样可以确保核心产品体积小巧,安装方便,同时仍支持整个.NET。

但是,这项工作本身并不能保证第三方也可以提供客户可以轻松发现和安装的可选组件,因此,这之间仍然可能有明确的界限(来自Microsoft)。和"这是第三方"。

同时,我们不想提供像nuget.org这样的开放式注册表作为发现和扩展核心产品的主要机制,因为这会带来很多噪音。我们仍然想要精心策划的体验。唯一的区别是策展集可以包含Microsoft和非Microsoft提供的功能。

.NET开发人员具有一个用于发现和获取其他工作负载的单一入口点。该入口点将用于所有第一方提供的组件,例如ASP.NET Core,EF Core和Xamarin。

体验将Microsoft提供的组件呈现为非Microsoft提供的组件的对等体。这有助于发现相关技术,并确保客户可以为工作选择最佳工具。

选择了可用组件集。该列表必须由某个方拥有,但不必只是Microsoft(但我们也应该拥有)。例如,可能会有一个.NET Foundation工作组来决定哪些技术足够重要,可以成为该核心产品的一部分。这就要求定义一个标准,该标准要求组件必须通过传递的标准,包括相关性,质量和项目运行状况。

将内置组件(例如ASP.NET Core和EF)移动到可选的工作负载模型中,以公平地竞争环境并确保扩展点的表达性。

为需要通过可选组件(例如模板,共享框架和工具)扩展的产品所有部分提供扩展点。

我们的图书馆生态系统完全围绕包含二进制文件的NuGet软件包。客户必须确信使用预构建的代码不会使他们陷入困境。这包括在必要时能够复制它们的能力,还包括安装软件包不会由于NuGet未能尽早浮出水面的不兼容性而导致构建或运行时错误。

.NET的生态系统使用二进制文件作为主要的交换机制。这解决了各种问题,尤其是保护用户避免必须复制构建环境。这也是启用多语言生态系统的原因。总而言之,二进制文件对于.NET都非常有效,特别是因为底层格式非常丰富且具有自描述性。

.NET对二进制文件和程序包使用Authenticode签名。 .NET Foundation使成员项目更容易获得代码签名证书,并积极推动其项目这样做。最重要的是,官方的NuGet画廊会对软件包进行签名,以指示它们来自nuget.org。

但是,一个未解决的问题是源代码和二进制文件之间的链接。尽管nuget.org上的很大一部分软件包都是开源的,并且经常链接到GitHub存储库,但无法确保所指向的源代码也确实与提交给nuget.org的二进制文件匹配。上载程序,或者因为上载程序使用了受感染的工具链,该工具链注入的代码不是源代码的一部分。

换句话说,仅仅因为您可以信任源代码并不意味着您可以信任二进制文件。虽然nuget.org扫描软件包中的病毒和恶意软件,但无法检测到所有可能的恶意软件。据您所知,某人或某物注入了一些矿工。

使用NuGet程序包也减少了恶意信任问题:程序包管理器UI将提供可能未安装或与该程序无关的程序包。当客户尝试仅使用它们以查看NuGet无法安装软件包或(更糟糕的是)在运行时看到应用程序崩溃时,这会令人沮丧并削弱信任。在很多情况下,这不是包装中的错误,在NuGet方面缺少使用包装信息来与客户沟通将使用什么和不使用产品的功能。

一个密切相关的问题是,找到与项目兼容的软件包可能会对.NET生态系统中的开发人员构成挑战。

程序包使用者将在尝试安装给定程序包之前先了解它们是否可以工作。他们应该通过查看NuGet软件包的详细信息来清楚地了解支持哪些平台,而不必猜测。通过安装软件包或下载软件包进行检查,以确保其平台上有可用资产。

我们需要创建一个验证工具,该工具可以检查是否可以复制给定的二进制文件。

验证工具需要集成到NuGet.org提取管道中,以便可以在搜索和打包页面中提供结果。

我们需要改进NuGet图库和NuGet包管理UI,以提供有关兼容性,与使用项目类型的相关性,受欢迎程度和质量指标(例如维护程度)的信息。

NuGet.org,用于验证上载的程序包,并作为整体程序包/项目运行状况的一部分显示状态。

内部合作伙伴Terrapin,这是保护Azure Ring 0和Ring1服务的一项工作。

使用.NET Core和Xamarin我们已经将跨平台作为图书馆作者的主流要求。但是,我们缺乏全面的工具和指导来确保图书馆开发人员陷入成功之境,这导致软件包无法正常工作,进而损害了我们的生态系统。对于新兴平台而言,这尤其成问题,因为这些平台的采用率不足以引起图书馆作者的特别关注。

自从我们完成.NET Core 1.0以来,我们一直在努力开发NuGet可以做的事情。但是,我们已经解决了许多仅针对平台层的难题,而不是着眼于库作者的日常工作。在dotnet /运行时回购中,我们使用自定义工具来构建软件包,其他回购,更重要的是,我们的客户不使用。这使得构建包含例如本机代码或需要为不同的操作系统或CPU体系结构构建不同二进制文件的程序包的软件包变得非常困难。特别是,对运行时标识符(RID)进行多目标处理的能力不强完全支持。

此外,我们作为SDK的一部分提供的工具具有接近零验证的功能,可证明多目标程序包的格式正确。例如,针对.NET Core 3.1和.NET Standard 2.0的多个目标程序包需要确保针对.​​NET Standard 2.0二进制文件编译的代码可以针对针对.NET Core 3.1生成的二进制文件运行。在dotnet /运行时仓库中,我们有工具来确保确实如此,但是我们的客户无法轻松使用。即使在第一方(例如Azure AD库)的情况下,我们也普遍看到了此问题。

尽管使用诱饵&切换方式,我们构建跨平台软件包的指导仍然非常初级。尤其是随着.NET5以及操作系统特定框架名称的出现,我们需要提供更多的说明性指南。

需要以与针对不同框架的多目标相同的方式来支持所有操作系统和CPU架构的多目标。

软件包会自动进行验证,以确保消费者不会遇到性能兼容性问题,因为所提供的资产与其自身的不同多目标版本不兼容。

我们需要提取并生产API兼容性工具(例如ourAPICompat),并将其纳入软件包多目标体验中

使用二进制文件作为主要的交换工具,并与包装/装配体标识结合使用,使人们更难以进行实验和依赖补丁。其他生态系统不会遭受相同程度的影响,因为它们要么基于源,要么具有解决此问题的特定功能。

从一开始,.NET就具有身份的概念(通过强大的命名和GAC)。从本质上讲,NuGet是该想法的延续。身份很重要,可以共享。但是,当只有一个方可以在该身份下生产人工制品时,也存在问题。有了强大的命名,这最初是设计使然。在.NET Core中,我们几乎已经消除了这个约束,对于.NETFramework,我们提供了公共签名来解决(在一定程度上)。

如果使用NuGet软件包,则此问题很难解决。中央nuget.orgregistry要求只有拥有给定软件包的一方才能提供新版本。但是,当您想在本地修改软件包(例如,尝试OSS贡献)或想对软件包遇到的问题进行修补时,这可能会非常不便。

我们应该使应用程序开发人员更容易将包依赖关系转换为他们可以控制和打补丁的源依赖关系。在某些情况下,可能希望使修补版本(公开或内部)可用。

但是,这通常需要一个新的程序包ID,这意味着所有消费者都需要重建其所有依赖项才能使用新的ID。更好的选择是允许应用程序作者将程序包ID(和版本)重定向到其他ID(和版本)。这也解决了软件包作者不再维护软件包或不想为特定的操作系统或框架支持该软件包的问题。可以由其他人提供该程序包,应用程序作者可以用分叉的程序代替规范的程序。

其他生态系统(特别是Java和NPM)具有私有依赖的能力,其中给定的程序包依赖被视为实现细节,并且不会成为消费者的直接依赖。例如,这将允许Azure SDK依赖JSON.NET,而不必限制应用程序是否可以使用哪个版本的JSON.NET(Java将此阴影称为阴影)。为了可靠起见,着色需要强制着色的依赖项不能泄漏到公共API中。

NuGet需要支持重定向图中的程序包ID。非阴影依赖项只能在应用程序级别进行替换,而阴影依赖项可以在对其进行着色的级别进行替换。

以下是批评Microsoft不能很好地与OSS生态系统配合使用的博客文章列表: 为了支持这些对象 ......