.NET要并库了

.NET要并库了

接下来的几个月,我们打算将.NET Core(以下简称DNC)的几个基础库合并起来,其中包括dotnet/coreclr和corefx。

.NET的Github库结构,一开始是细粒度的,目的是提高灵活度和开发者的生产效率,但是这种分离给维护者和贡献者带来了很多麻烦,比如:

  • issue应该在哪开的问题。一个issue应该开在哪个库经常是不清楚的,因为某些实现是跨库的,就把问题搞复杂了(比如一个类型可能在corefx中测试并以引用程序集的形式暴露出来,但实际上它在coreclr的System.Private.CoreLib中实现)
  • 分享源码的不便。System.Private.CoreLib和运行时的其他部分耦合在一起,因而和运行时代码共存,但是这也意味着,虽然corefx的目的是为任何底层运行时共享尽可能多的代码,但是(因为耦合的原因)还得在 System.Private.CoreLib保留一大块代码,也就是说,CoreLib在每个运行时库 (coreclr, corert, mono) 都有一个“镜像”提供服务;类似地,corefx需要访问大部分CoreLib的源码,比如导入和运行时其他部分一样的Dll文件,自动镜像会自动分享需要维护的源码,但是也经常导致延迟。这还复杂化了开发进程,一个库的改动验证常常需要手动把源码镜像到其他库一起验证改变,还要确认合并到一个库的过程不会影响到别的库。
  • 跨库PR问题。 因为运行时,CoreLib,还有核心类库都是耦合在一起的,所以添加新API,修改构建流程(比如改进静态分析),经常需要多个PR谨慎地跨库多次提交,比方说给Dictionary<>这样的类添加个方法,开发者首先得在本地coreclr库改源码,corefx库进行测试和程序集引用改动,改完了还得向coreclr和corefx各提交一个PR,缺了哪个都会失败,最后coreclr的PR会被合并,改动会被镜像到其他运行时,这些PR都被合并之后,含有这些修复的每个运行时都会有一个构建,之后这些构建都会用到corefx库中,再之后原来的corefx的PR会被重新验证,最终合并。这是最好的情况了,如果有双向依赖,事情就会复杂得多。
  • 构建可安装运行时的问题. 自包含一个自定义构建的.NET需要一些乱七八糟的知识,比如库如何工作和交互,于是开发者不能只克隆一个库,按照期望进行一个改动,简简单单的弄出一个安装程序。
  • 一致性问题. 我们搞细粒度多代码库的一个原因是,允许团队在每个库保持隔离性和独立性(不需要关注其他库的实现细节),但是这导致了很大的重复工作,比如在构建系统和CI上,然后由于每个系统最终与其他系统不同而导致缺乏一致性。

问题还跑到了运行时之外,例如,ASP.NET的维护者和社区在过去做了很大的工作,将大约55个库合并成大约5个,但是还有很多超出期望之外的库,导致了和上面所说类似的问题,除此之外,ASP.NET的库在aspnet这个组织下,还多了几个问题:

  • 库间移动issue的问题。 如果开发者在aspnet/aspnetcore提了个issue,但其实问题的源头在dotnet/corefx,GitHub是没有这样的机制,可以跨组移动issue的。
  • 许可证问题。 每个组织的许可证最后都需要分开管理。

这些问题还扩展到了工具的编写,比如,我们现在有很多库,在逻辑上构成了.NET CLI,但是实际上做一个安装程序需要跨多个库。

计划

为了解决这些问题,我们计划对库结构进行如下变动:

  • dotnet/platform. 我们计划将dotnet/coreclr, dotnet/corefx, dotnet/corert, dotnet/core-setup,和mono/mono相关的部分合并成一个新的dotnet/platform库,构建Microsoft.NETCore.App框架的一切都会进入这个库,再也不用被源码镜像问题蹂躏了。而且修改运行时行为,添加API这样的特性再也不需要在多个库之间像踩着三个鸡蛋一样跳舞,诸如此类等等。
  • dotnet/aspnetcore. 我们打算把已有的aspnet/aspnetcore移动到dotnet组织下,不仅这个主库,还需要联立很多其他的asp.net库到aspnetcore里面,比如aspnet/blazor,像efcore这种库,保持分离还是联立依旧是个开放问题,一个目标是,dotnet/platform负责Microsoft.NETCore.App的创建,dotnet/aspnetcore负责Microsoft.AspNETCore.App的创建。
  • dotnet/cli. 我们打算把dotnet/toolset和dotnet/sdk联合成dotnet/cli库.

问答

我们为什么要把库合并起来?

我们相信,将.NET的各个库联合起来能够显著改善.NET的若干方面,对维护者和贡献者都有好处,这些改进不胜枚举,比如更好的issue管理,更简单的贡献模型,更简单也更快速的构建和安装。

aspnet组织会怎么样?

作为一个分立实体的aspnet组织已经老了,是时候将其融入dotnet组,取消它了。

coreclr和corefx库会消失吗?

在GitHub的帮助下,我们打算从这些旧库把所有的issue迁移到dotnet/platform,然后锁定issue的添加,这样旧库就不再用于issue管理了,除此之外还会阻止向master分支提交PR,某种意义上这个库就是被存档了,不会有活跃的更新,但是我们还会为这些库出品的旧版DNC提供服务,因此这些正式版所代表的分支(release/2.1, release/3.0等)还会有一些受限的操作。

mono库会消失吗?

不,mono/mono存储着整个mono技术栈的源码,还会继续快乐地活下去。我们会简单地移动与System.Private.CoreLib相关的托管代码,复制少量组成非托管mono运行时的源码到dotnet/platform。我们可能会选择一些镜像的技术,来让运行时同步复制(不过不会有相同镜像的问题,因为如果两个组件需要构建相同的二进制文件,我们就不会在它们之间搞镜像),或者我们可能让它们分开,只在改动涉及到两个库的实现时,才会手动同步。

corert库会消失吗?

是的,我们计划将corert库存档,corert中的一些技术会被迁移到dotnet/platform的主分支,作为.NET的一部分出品,其他部分会被迁移到dotnet/platform的feature(特性)分支,实验在这里继续进行,这样我们就可以用corert技术继续探索,同时它的组成部分共享更加简单,也可以在实验性功能准备好之后,直接并入master。

所有的.NET组件都会变成一个库吗?

不,我们会减少.NET的库数量,但是我们并不觉得把所有库并成一个是正确的答案。

你们不觉得issue和PR的跟踪会压死人?

现状是给定仓库里的绝大多数issue都和任何独立开发者没什么关系,每个库都有几千个开着的issue和上百个PR,我们已经使用例如标签这样的系统来管理issue和PR了。老实说,我们不觉得合并会给开发者的生产工作带来显著影响,如果很不幸有意外的重大消极影响,我们会和社区合作,来消弭问题。但是,但是,GitHub上已经有很多成功的开源项目(基于DNC),至少会有多一个数量级的问题。

已有的issue如何处理?

有GitHub功能的帮助,我们计划把所有issue从老库(比如dotnet/coreclr, dotnet/corefx)迁移到新库(比如dotnet/platform),也可以重新借此强制审查老issue,并将那些不再有关系的issue关闭,或重新打开那些需要立即关注的issue。

Git历史记录怎么办?

我们大体上会保留历史记录,每个分库的git历史都会成为新库历史的一部分,但是我们以前犯了些错误(比如巨大的二进制文件,无数因为依赖和源码流动造成的自动PR,详见这篇文章),因此打算重写git历史,纠正那些有影响的错误,一些估算表明,这能显著减少库的大小和克隆库的时间,同时能帮助开发者访问项目和CI。相对于老库,新库的SHA可能会不同,不过如上述,任何对老库的旧SHA的引用还会继续工作,这些库仍然可以访问。

我还能看到我的贡献记录吗?

是,我们会合并所有的贡献历史。

这会破坏使用SourceLink的调试吗?

不,已有的库还可以接着访问,已有的SHA也会继续不变。

计划可能会变动吗?

肯定的,发这篇公告的一部分目的是听取你们希望得到的好处,以及我们可能没考虑的问题,我们还会将这些想法放在我们的计划中,必要时纠正航向。

一些重要评论

Announcement: Consolidating .NET GitHub repos · Issue #26175 · dotnet/coreclrgithub.com图标

Suchiman(这人把CoreCLR的GC移植到了CoreRT):Corert的哪部分(会被移植到新.NET库的master)?我觉得你想要推入master的是CPAOT(Cross Platform AOT)的组件(例如ILCompiler.ReadyToRun),以准备AOTv3,不过其他部分怎么不推进去?Corert的其他部分并不影响其他库,把Corert推入一个实验性分支,只是从永远的镜像问题换成永远的主分支合并问题。

Announcement: Consolidating .NET GitHub repos · Issue #26175 · dotnet/coreclrgithub.com图标

ghuntley:给你推荐一个在库之间迁移代码的工具!

google/copybaragithub.com图标Announcement: Consolidating .NET GitHub repos · Issue #26175 · dotnet/coreclrgithub.com图标

adamralph:听上去不错!不过换个角度,其他场景中有一些痛点:

  • NuGet/NuGet.Client -> dotnet/cli
  • microsoft/vstest -> dotnet/cli

两个场景中就我理解,前者搭载到后者时,都提供了dotnet指令,有什么扩大合并的计划吗,把其他类似于这样的库,也搭载进.NET CLI?

Announcement: Consolidating .NET GitHub repos · Issue #26175 · dotnet/coreclrgithub.com图标

Stephentoub:jkotas可以在corert这方面说几句,现在corert对DNC没什么贡献,并且只和构成正式.NET的库的合并工作有关系,我在这里提到它本来是想让事情更清楚,但是好像越来越糊涂了,很抱歉。提到corert是想强调,我们打算在coreclr的某些部分有所作为,意味着最终它们会进入coreclr的活跃维护分支,至于corert的其他体验功能,会保持分离,追逐新潮。

Announcement: Consolidating .NET GitHub repos · Issue #26175 · dotnet/coreclrgithub.com图标

poke:我看不出“把一切移交给dotnet组织管理”这个想法有什么好处,除了破坏深链接(deeplinks)和增加困惑。

terrajobst(immo landwerth,.NET的项目经理):一部分原因你已经指出来了,跨库搜索是个很痛苦的事情,我们在和GitHub合作,他们应该很乐意接受我们的反馈。我们不太可能跨组搞工具,倒是应该会组内搞,良好的事例包括了所有的许可建模(permission modelling)和Transfer Issue这样的工具。

对于已经合并的库,链接不是问题,我们还会保留原始的issue;对于已经移动的库,链接也不应该成其为问题,因为GitHub会处理这些。

结语

这个issue已经被置顶——关心.NET前途的人,可以到下面提出自己的诉求,一般都会得到回复,我看见 @霍姚远 已经在里面了。

编辑于 2019-08-19

文章被以下专栏收录