写在 100+ PR 兼并之际,结构性复盘,总结阅历和过错。

2023 年 2 月 13 日,经过数月的流程操作, Flutter 生态中顶级热门的 HTTP 库 dio 从 flutterchina 安排搬运到了 CFUG 安排, 而且发布了全新的 5.0 版别,开端了由新团队保护的进程。

笔者本人作为这次作业的首要推动者之一, 想借着咱们第二个里程碑——保护 dio 六个月——即将达到之际, 对作业的整体过往进行结构性的复盘,总结在开源过程中的阅历和过错, 也让咱们能够了解到这么一个风光的 package 在曩昔的一段时刻中阅历了什么样的曲折。 我也想从个人视点共享给咱们我的得失以及感触。

术语指引

Dio

github.com/cfug/dio

dio 是一个强大的 HTTP 网络恳求库,支撑全局配置、拦截器、FormData、恳求取消、文件上传/下载、超时、自定义适配器、转换器等。

flutterchina

github.com/flutterchin…

国内闻名开源安排,在 @wendux 的主导下开源了很多有用 package, 包括但不限于 diocookie_jarazlistview, 以及很多 Flutter 新手都会阅读的 《Flutter 实战》 及其第二版书稿。

CFUG

github.com/cfug

Flutter 中文用户组,首要保护 flutter.cndart.cn 本地化站点, flutter-io.cn 镜像站、各种 Flutter 活动时的本地化站(例如 Pinball, Photobooth, I/O Flip)、 发布本地化的季度问卷调查、处理 Flutter 国内相关的使用问题、安排 Flutter GDE 参加活动等。

作业原因

作为一个开源项目,假如它由一个未盈余而且爱好使然的开发者或许团队保护, 那么很有或许在一段时刻保护后就没有人回应问题或许发布更新了。 虽然 dio 是整个生态中数一数二的 package,但惋惜的是它依然没有逃过 缺少保护的魔爪

它是社区中网络恳求方面的绝对榜首梯队的 package, 由于为用户封装了很多开箱即用的特性,使得它十分受欢迎。 说两个数字进行简略的比照:

  • 在 pub 上 dio 的点赞数为 5856http 则是 6593
  • 在 pub 上依赖 dio 的 package 总共有 1328 个http 则是 3676 个
dio http
复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

从 dio 诞生至写文章时,它阅历过多次保护空档,而且由于缺少保护也遭受了两次社区分叉 (fork):

  1. 从 2021 年 6 月到 11 月,阅历了 4 个月的空档期,期间社区提出了 该项目是否仍在保护 (#1234) 的疑问,而且有人 对其进行了分叉,创建了 dio_http package。但在 10 月份原作者进行了保护,而且在 #1234 的回复完毕表明他将增加新的保护者来保护项目,所以在 11 月,分叉的 package 进行了归档,分叉进程完毕。
  2. 从 2021 年 11 月(即刚回归保护后)到 2022 年 3 月,阅历了 4 个月的空档期,虽然期间上一次增加的保护者依然在保护项目,可是由于没有发布权限,用户并没有办法直接经过新版别接收到修正和优化。
  3. 从 2022 年 3 月到 2023 年 2 月,阅历了 11 个月的空档期,期间咱们介入进行了分叉,将在后文详细介绍。

用命运多舛来形容它也不为过。 这样的弃更也给它带来了不安稳的体会和较差的对外口碑, 常常能见到有人在 issue 里苦苦等候 BUG 修正。

在 dio 的过往时刻里,我也是奉献者之一,修过一些 BUG, 也从前将 dio 扩展到字节出品的 flutter_ume 上。 这些年经过我手的 package 说多不多说少不少, 看到一个这么主流的 package 给咱们形成了不安稳的体会和较差的对外口碑,我一直想做点什么但没有成型的思路。 期间我也从前多次测验与原作者建立联络,未曾收到过回应。

你问我为什么想要掺一脚去保护一个快凉了的项目,我的答案或许是: 由于咱们深度参加社区,由于我想给开发生态带来好的影响, 由于我是 Flutter GDE 而这个身份能够带领咱们向好的方向前进, 由于将它保护好能够给社区对国内的开源项目留下更好的形象。 这样的答案或许难以让人服气,我也没有什么特别要解说的,“清者自清”? 而 dio 这样体量的 package 本身也值得被社区好好保护。

构思方案

依据以上现实,咱们终究在 2022 年 10 月 15 日进行了一场内部谈论,详尽聊了咱们的主意以及能够立下的里程碑目标,方案大致如下:

  1. 进行硬分叉而不是软分叉,即不在 repo 上相关 fork 信息;
  2. 保存原作者开源协议信息,新增 CFUG 开源协议信息;
  3. 保存全部提交记录,依据最新代码提交进行开发;
  4. 分析原库房有用的 PR,与奉献者进行谈论和审查,尽量使其兼并到分叉库房;
  5. 发布硬分叉的揭露意向,让社区知情,而且经过兼并的 PR 相关意向,以及在交际媒体发布信息,扩大知情范围,期间全部决议方案以揭露通明准则进行发布;
  6. 联络原项目保护者,将其阅历带到硬分叉持续参加项目的保护,确保保护环节的正循环;
  7. 达到相对安稳状态后,假如原库房仍未进行有用保护,发布硬分叉的安稳版,正式开端保护分叉道路。

第 2 点关于开源项目而言极其重要,一个项目从开端到完毕全部人的奉献都应当遭到尊重, 而咱们在原有的根底上进行开发,也不会降低原作者为咱们带来的好著作。

后续的展开证明了第 3 点的挑选十分重要, 它是咱们将分叉兼并回原库房的根底保障,不然全部改动都无法简略进行兼并。

方案拟定后的几天内,咱们内部其实依然对是否实施它有不同的定见, 但经过咱们的相互解说和鼓舞后,终究决定由我带头推进, 于 2022 年 10 月 18 日正式启动了方案,硬分叉 diodio3(后更名为 diox)。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

为什么是这样的方案?

对上面的方案的一些咱们或许在意的问题进行回答:

Q: 不安稳的体会和较差的对外口碑有什么依据?

A: 有,而且不少。这儿我并不会展现详细的内容,由于这些信息能够直接经过查找查询到。 在多个空档期中,dio 从前发生过数次严重 BUG 导致某个功用或某个渠道彻底无法使用, 但都没有及时修正或更新,导致在项目库房中呈现很多相关 issue 及跟帖。

Q: 为什么硬分叉?软分叉有什么问题?

A: 硬分叉不会比照现库房与原库房的差距, 能够有自己的 issue 和 PR 且不包括原库房的 issue 和 PR, 有利于咱们将项目调整为一个能够保护的状态, 而不是从一个十分复杂的状态中开端对 dio 的保护。 硬分叉和软分叉都会形成用户的搬迁,不可避免。

Q: 为什么不能想办法更新原库房?

A: 如上文所说,在这些作业期间,多人多次测验联络原作者但均未收到回应。 而其保护的项目也有相似的状况,其中一些甚至影响到 Flutter 团队处理问题的流程。 终究咱们只能挑选进行分叉。

Q: 怎么确保硬分叉的可持续性?保护者是否还能担任保护作业?

A: 在拟定方案时,这两个问题背面的疑问和危险还十分高。 咱们并没有在方案作出时就有一个成果,但随着后来的意向以及作业的展开,它们都逐步有了答案。

方案实施

带着谈论出来的方案,我开端了整个分叉流程:

  1. 2022.10.18,创建了 分叉 diox,一同开端邀请保护者参加共建 (@kuhnroyal, @ueman);
  2. 2022.10.20-2023.2.10,不断兼并来自原库房的 PR,修正并调整代码,引进新功用;
  3. 2022.12.18,发布了 分叉的意向,详细解说了咱们的身份、作业的布景、咱们的方案等;
  4. 2022.12.18,发布了分叉的 榜首个预览版别,同日揭露了 分叉库房,而且介绍了怎么从原有 package 进行搬迁的流程;
  5. 2022.12.18,交际渠道发布音讯,让用户参加相关的测验;
  6. 2023.2.10,发布 榜首个安稳版别,而且在交际渠道发布音讯。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

至此,咱们依旧没有收到原项目作者的任何反应,这样的状况把 diox 这个硬分叉推进到了安稳版这般境地。 可是假如从方案实施的视点来看,咱们完结的十分不错, 原本的保护者也积极地参加到了硬分叉的保护中,一些下流项目的作者也开端发布适配 diox 的 package。 能够说从这天起,社区开端向分叉项目转向。

作业的起色

可是就在 2 月 10 日 diox 发布安稳版的这一天,dio 世界发生了巨大的波动。

在没有任何交流的状况下,原作者在 dio 库房提交了一份声明:

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

这份发在周末的声明直接导致了社区的舆情发酵,咱们都在惊奇及惋惜,不少人也借此机会唱衰开源项目的保护。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

作业展开到这一步,关于整个社区的生态冲击是无比大的。 让整个社区转向是十分持久且消耗开发资源的一件事, 关于普通开发者而言则会在整个过程中体会到及其割裂的集成流程。

可是,在阅历了两天的周末的重视后,咱们终于联络上了原作者,或许说原作者终于联络上了咱们。 经过快速的定见交换,以及各种细节的对接后,原作者终究认同由咱们对 dio 进行保护的方案, 而且当天开端进行整个库房和已发布的 package 的全部权搬运。 谈论后敲定的操作细节如下:

  1. 原作者加入 @cfug/devs 团队,持续坚持对项目的悉数权限;
  2. 项目全部权从 flutterchina 移交到 CFUG(包括 pub),由开发团队共同持有悉数权限;
  3. diox 由于依据 dio 的提交记录开发,将在全部权搬运完结后 兼并回 dio,而且 揭露归档;
  4. 全部 diox 发布的 package 悉数 discontinued 并指引证户持续使用 dio 相关 package;
  5. 原作者及新作者发布 共同声明,解说此次接收及兼并,尽或许地消除对用户形成的影响。

至此,整件作业来了个 180 大调头, diox 完美的完结了它的使命,功成身退成为了 dio 的一份子。 而社区割裂也被及时制止,用户的生态健壮性得到了保障。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

后续展开

在作业呈现起色而且咱们与原作者操作往后,diox 彻底兼并回了 dio, 也由此 发布了全线 package 的新版别。 从这一天起,咱们正式接手了这个项目,开端依照咱们的方案进行实践操作。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

项目现状

经过 6 个月的安稳保护,dio 现已从 5.0.0 版别来到了 5.3.2 版别, 期间共解决了 141 个 issue,兼并了 101 个 PR。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

在 2023 年 3 月 22 日,咱们通报了安全问题 CVE-2021-31402 的解决状况,消除了新版别 dio 被报告有安全危险的问题。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

目前整个项目已进入安稳保护阶段,核心保护者均能及时对应处理问题, 并 经过揭露渠道发布新版别。

社区阅历

经过了从主意到安稳保护的这一段时刻,我经过预先制定好的方案、与成员们的主意磕碰、 安稳的开源才能输出、积极与其他开发者接触、重视并引导社区言论、揭露通明的决议方案准则, 以及满足的权限下放,比较完美地将这个项目盘活, 而且让项目再次成为了生态中极受欢迎且安稳的 package。

我从这件作业中总结出来的 关于开源项目的阅历 首要是以下几点:

  1. 虽然社区并不能总是把作业做好,可是要相信它们的活泼度和目标。 国外的社区在这件作业中充当了言论发酵场的重要因素,每一个使用过 dio 的人在看到项目即将崩盘之时都表达了自己的感触,从而在某些方面影响了作业的走向。在停止保护的公告宣布后,依然有多个国外社区问询是否能够接手项目进行保护,这样的积极性在国内安排中较为罕见,值得学习;
    复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
  2. 当开源项目有一定规划时,不管是不是爱好使然,一定要想尽办法让它处于可保护的状态 ,不然在多次空档期发生后,全部的参加者都会损失保护的动力,导致一个项目快速走向完毕,无法适配结构的更新。社区中现已有十分多的比如;
    复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
  3. 要想把开源项目保护好,心态要尽量向利他方向靠近。 在 dio 的这件事中,每个旁观者都会有不同的观念。有的人或许以为国内开发者在内斗,有的人或许以为咱们新作者或许仅仅老登,但不管咱们怎么想,这件作业的成果关于全部人而言都是获益的,这便是咱们展开这项方案所寻求的终究成果。
  4. 保护一个开源项目其实能够和每天刷短视频相同简略。 你只需要每天花一些时刻,回复仔细发问的 issue、研究问题发生的原因、及时向用户反应你当时的进展,就算今天你的研究没有实质性的成果,用户也会对你的进展发生安全感,而安全感也会转化成礼貌且畅快的交流,让全部的参加人在开源库房的奉献中都得到正反应,发生良性循环。
    复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?
  5. 揭露通明很重要。 当你在测验做一个揭露通明的决议方案时(例如代码结构设计),一旦你能将其表述到位,你就有很大概率能收到来自其他人有用的反应,你也得以重新评估自己的决议方案的有用性。

个人得失

毫无疑问,在这件作业中,我是遭到最大影响的人, 由于我完整地主导并参加了自始至终的全部作业, 而且每一步都是我与团队或许我自己作出的决定, 成果不管好坏也首要由我承当。

咱们先说点好听的,讲讲我收获了什么,再来谈谈失掉的东西和犯下的过错。

名誉

在保护 dio 之前,我现已长时刻游走在 Flutter/Dart 生态支撑中, 积极地为库房作出自己的奉献,帮助联络并协商一些作业。 这些奉献能够在我的 GitHub 奉献历史中可见一斑。 而在今年 (2023) 谷歌开发者全球账号也时不时地帮我宣扬, 所以叠加此次作业后,不管是国内外, 很多开发者都对我以及咱们 CFUG 形成了比较好的形象和认知。 声明发布当天,原 Flutter 团队的 Tim Sneath 也转发了咱们的内容。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

依靠着热门作业和揭露处理的方法,我摇身一变, 在突出奉献者的根底上叠加了网红特点,让更多人了解到并认可我的作业。

涨粉

这种热门作业,在哪儿发,就在哪儿涨粉,详细是什么渠道就不细说了。

统筹规划履行力

除了上文提到的方案以外,为了完结咱们定下的全部里程碑和终极目标,我在中途还做了这些事:

  • 找到从前的保护者,详细地向他们解说了作业的原委,交流咱们的目标机咱们能做出的承诺,鼓舞咱们一同为社区作出奉献;
  • 设计咱们的意向书,深思熟虑怎么把故事讲好;
  • 设置项目板,相关咱们正在处理的修正 PR,对外揭露;
  • 在社区中呼吁咱们测验改变,而且在协助咱们调整的一同收集反应。

由于细节十分多,这些作业无疑提升了我在开源项目以及叙事上的统筹规划和履行的才能。

职责

职责能够是一种收获,也能够是一种失掉。当你肩负起了保护 package 的职责,你就需要直接担任它的全部,不管功德坏事,全部人都会找你。表扬的也是你,骂的也是你。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

时刻

每个人每天的时刻是固定的,做了更多的活,参加的越多,占用的时刻也会越多。

在开端保护 dio 之前,我的每日作业流是:

  • 起床 -> 打开电脑 -> 上班 -> 闲暇时看告知 -> 有问题对应问题 -> 想到新功用完成一下 -> 关机 -> 睡觉

现在加上了 dio,大概每天会重视 5 个库房的动态,作业流就变成:

  • 起床 -> 打开手机刷告知 -> 回复谈论 -> 审查 PR -> 上班 -> 收到告知对应 -> 想到新功用完成一下 -> 循环第3步 -> 循环第4步 -> 关机 -> 循环第2步 -> 循环第3步 -> 睡觉

起床便是刷告知,睡前还是刷告知,这次真正的把家搬到了 GitHub 里。

做的欠好和做错的作业

破坏了默认的 content-type

在这次大版别的跨越和保护时,我从社区中收集了一些关于隐式指定 content-type 的定见, 从这部分人中得出的结论是:新的大版别不应该再隐式指定 content-type 了, 而是应该让用户自己确定,确保跟从用户指定的值走。

依据反应,咱们终究在 5.0.0 的正式版中加入了这项修改,而且供给了完整的搬迁指南。 可是发布后,咱们依然收到了 大量的反应, 恳求无法正常发送。 上面的社区收集好就好在寻求了咱们的定见, 坏就坏在没有考虑到像 dio 这样被大规划应用的 package 让开发者把全部代码都搬迁完结有多困难。 也有人私下找我对线了这个问题,站在不同的视点,每个人都有自己观念, 而很多人升级时也没有看搬迁指南, dio 本身关于不正确的 content-type 也没有足够的提示。 终究的成果是这次的改动确实过于大,导致了很多应用方没有办法很好地处理改变, 所以我创建了新的 ImplyContentTypeInterceptor 来恢复部分默认类型的处理。

破坏了对 src/dio_error.dart 的直接引证

在 PR 1803 中咱们废弃了 DioError,将其搬迁为 DioException。 这项更改一同也将 src/dio_error.dart 更改为 src/dio_exception.dart。 正常来说,在依赖一个 package 时,不引荐直接引证其 src/ 目录下的文件。 怪就怪在有一个 package stream_chat_flutter 直接引证了这个文件, 所以对方的作者提交了 PR, 一同保存两个文件使得旧的用法依然有用。 可是我以与最佳实践抵触,应该避免直接引证 src/ 为由拒绝了这项提交。 第二天我就看到另一位保护者在吐槽这件事:

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

咱们两边都有各自在理的当地,但我更加认同他的说法,承受一个这样的 PR 有多难呢? 下一次呈现这样的状况是否能够 LGTM,这次的阅历会带给我不相同的评判标准。

感触

这儿不是阅历,仅仅输出一些 朴实且片面的个人感触

做开源,怎么做适宜?

玩了 5 年开源,现在混到了常驻 排行榜 前 20, 发现抱着名利心做开源绝对不可,共享的心态做大以后也不可。 唯一可行的只要敞开的心态,学会承受他人的定见。 开源世界也是鱼龙混杂,很多能来 GitHub 给你开 issue 的反而是新手用户。 面对新手,有阅历的人常常会陷入“知识的咒骂”,我也从前有过这样的一段时刻, 即无法让自己从不懂这件事的视点去思考,了解新手的问题。 而能给你开 PR 的人都有自己的观念, 某种特定场景下或许真的能够帮助你的 package 变得更好。 咱们能否认同你除了一部分是依据现实外,另一部分都是依据咱们的知识。 我也从前在一个 Flutter issue 里总计被数十人点了 , 可是并不影响我与团队兼并正确的 PR 来修正这个问题。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

所以 多做,多谈论,多换位思考。

怎么保护好一个项目?

抽象的答案:用心

更精准的答案:用心留心谁(个人、安排、基金会均可)对项目的帮助最大, 仔细考虑项目的出路,实践地考虑假如项目黄了会有什么结果。

当你一开端仅仅由于一个共享而做的项目,可是后边却疏于保护的时候, 问问自己:懒?没有才能?花太多时刻?效益差?

这些对我来说都还不足以成为一个理由:懒不能让另一个协作者来操作? 没有才能不能招募平常有突出奉献的人来帮助? 花太多时刻不能把项目保管给更敞开且热心活泼的社区? 效益差不会思考商业化的途径?

说白了就算没法保护了,归档会不会,转交会不会? 非要到咱们都准备溃散了,才挪一下屁股, 这样的操作对社区而言百害而无一利。

负职责也并不是每个人都有的特质, 假如你觉得你没有,请考虑招募第二个协作者, 或许直截了当地告知咱们:项目或许无法及时保护。 把话说理解没有那么难,敞开来说话才能把作业办好。

称谢

终究,当然是列一个感谢列表:

  • 感谢 @wendux 作为创作者开发了这么一个有无数开发者喜欢和使用的 package;
  • 感谢前期支撑咱们这项作业,而且积极为咱们的分叉版别提交反应的社区成员们;
  • 感谢国外的两位协作者 (@kuhnroyal 和 @ueman) 在这数个月中持续地与我一同保护 dio;
  • 感谢 @CaiJingLong 在咱们的保护 dio 过程中供给了全部的 CI/CD 才能的支撑;

特别感谢 CFUG 的各位,从我提出主意到今天,给了无偿且足够的信心和动力, 让咱们能够成功地完结了咱们的方案,拯救了 dio 这样的热门 package。 很开心能有你们一同同行。

复盘接手 Flutter 生态中顶级热门的 dio 库的几个月,我们做了什么?

让咱们持续在 Flutter 的开源世界相见!

注:文中全部 @ 最初的 id 均为 GitHub 用户名。