Sia-Minio 集成事后复盘
我在 Google 工作期间学到的最有价值的做法之一,就是开展无责事后复盘(blame-free postmortems)。当出现问题时,要等尘埃落定,再撰写报告分析事情经过。报告会解释问题是如何发生的,并确定团队未来可以采取哪些具体措施来减轻问题的影响。
上周我看到了一个很适合进行事后复盘的机会。一个由悬赏资助的项目正式完成了将 Sia 支持集成到 Minio 中的工作,但项目耗时比预期多了几个月,而且经历了多次大规模重写。
Sia 是一种去中心化云存储技术。我以前写过关于它的文章,因为它是我最喜欢的技术之一。Minio 是一款开源、兼容 S3 的文件服务器。两者完成集成后,用户现在可以使用任何兼容 Amazon S3 的备份软件,将数据备份到 Sia 网络。
这次集成意义重大。等 Sia 在 12 月发布版本后软件趋于稳定,我计划再写更多相关内容。在此之前,我认为这是一次对集成过程进行事后复盘的宝贵机会。我联系了 Nebulous Labs 团队,他们很赞同这个想法。我联系了 Sia-Minio 集成代码的作者,他也表示支持,并同意与我共同参与报告撰写。Nebulous Labs 和 Minio 团队审阅了报告并批准发布,因此下面是我们的完整报告:
Minio 集成悬赏事后复盘
Nebulous Labs 事件 #1
日期:2017-12-01
作者:
- Michael Lynch(迈克尔·林奇)- @mtlynch - Sia 博主及 /r/siacoin 版主。
- David Gore(大卫·戈尔)- @dvstate - 开发者,悬赏获得者
审阅者
- David Vorick(大卫·沃里克)- @taek42 - Nebulous Labs 首席开发者
- Zach Herbert(扎克·赫伯特)- @zherbert - Nebulous Labs 运营副总裁
- @harshavardhana - Minio 维护者
背景:什么是事后复盘?
事后复盘是一项从近期未按计划进行的经历中汲取经验的活动。
事后复盘不追究责任:我们要找出导致糟糕结果的流程问题,而不是试图找出或羞辱个人。我们假定参与所讨论事件的所有人都具备能力且出于善意。
更多详情请参阅 SRE 一书中的《Postmortem Culture: Learning from Failure(事后复盘文化:从失败中学习)》。
摘要
7 月 19 日,Nebulous Labs 宣布悬赏 300,000 SC,征集一个能正常工作的 Sia 与 Minio 集成方案。Minio 是一款开源、兼容 S3 的文件服务器。开发者 David Gore(@dvstate)在五天后发布了概念验证(proof of concept),不到 10 天后便获得了全额奖金。
该集成又花了额外三个月才合并进 Minio 仓库。要让 Minio 接受这份代码,必须彻底重新架构代码;@dvstate 还付出了大量工作,而这些工作并未得到悬赏的正式补偿。
集成可以运行,但要完成它,必须加入悬赏中未预料到的若干限制:
- 只支持有限的文件名字符白名单,比 Sia 允许的字符范围更严格。
- 不支持多部分文件传输。
- 只有两个简单函数拥有自动化测试覆盖。
影响
这些事件最显著的影响,是与一位关键合作伙伴的集成被延迟了数月。Sia 获得 S3 兼容性是一个重大里程碑,但由于整个过程拖延太久,这项成就给人的“冲击力”似乎被削弱了。
这一过程中的波折给 Sia 带来了负面观感:
- 集成 Sia 很困难,即使使用 Sia 的原生语言 Go,也需要重复投入工作。
- 完成 Sia 悬赏很困难,因为验收标准不明确。
经验教训
进展顺利的方面
- Sia 成功集成进了 Minio。
- Sia 社区成员使用各种 S3 客户端,在不同场景下参与测试了 Minio 集成。
出现问题的方面
- 关于功能和需求的沟通不畅,导致集成经历了数次重写。
- Minio 维护者完成审阅与 PR 更新之间存在很长的延迟(有时达到数周)。
- 由于 Sia 集成 PR 进行期间 Minio 代码库发生了变化,@dvstate 不得不花费相当多的时间解决合并冲突。
我们走运的地方
- Nebulous 支付悬赏后,@dvstate 仍自愿投入数月时间继续开发集成。
- @dvstate 自愿启动、配置并出资运行了一个供 Minio 测试使用的 Sia 测试服务器。
- Minio 维护者慷慨地投入时间,连续数月审阅同一个 PR。
时间线
- 2017-07-19:Nebulous Labs 宣布一系列 Sia 悬赏,首先悬赏将 Sia 集成到 Minio。
- 2017-07-24:@dvstate 发布概念验证集成方案。
- 2017-08-03:Nebulous Labs 向 @dvstate 发放全额悬赏。
- 2017-08-09:@dvstate 首次提交 PR,将 Sia 集成到 Minio 源代码中。
- 2017-08-09:@harshavardhana 要求 @dvstate 重写 PR,使用 BoltDB 而不是 SQLite。
- 2017-08-13:@harshavardhana 同意接受 Sia-Minio 集成。
- 2017-08-16:@dvstate 完成 BoltDB 重写。
- 2017-08-28:代码审阅期间,@harshavardhana 要求 @dvstate 完全移除数据库,在没有缓存层的情况下重写 PR。
- 2017-09-26:PR 数周没有活动后,@zherbert 和 @mtlynch 要求更新状态。
- 2017-10-19:@dvstate 完成了移除缓存层的 PR 重写。
- 2017-10-24:@harshavardhana 向 @dvstate 发送补丁。
- 2017-10-25:@dvstate 关闭原 PR,并新建一个 PR,以满足 Minio 的要求并集成 @harshavardhana 的补丁。
- 2017-10-26 - 2017-11-21:@dvstate 部署并出资运行 Sia-Minio 测试节点,并向 @harshavardhana 提供访问权限。两人使用 Minio Web 应用、s3cmd 和 mc 命令行工具手动测试集成。
- 2017-11-22:Minio PR 合并。
发现的问题
需求不明确
悬赏说明没有明确规定 Sia-Minio 集成的许多细节。其中只规定“用户必须能够使用 Minio 客户端上传/下载 Sia 文件”,却没有提到 Minio 维护者提出的任何限制或要求。
此外,几位 Sia 用户通过 Sia Slack 的 #bounties 频道或私信联系 @dvstate,要求增加一些功能。由于没有权威的需求定义,@dvstate 担心忽略这些要求会导致悬赏被取消,因此实现了这些额外功能。
结果,@dvstate、Minio 维护者和 Sia 用户对以下问题产生了混淆:
- 哪些第三方库是可接受的
- Sia 集成是否允许在文件系统上维护缓存,以保存状态信息和元数据
- Sia 集成是否必须实现多部分文件传输
- Sia 集成是否必须支持存储桶策略设置
- 哪些 S3 客户端应用必须支持(例如 mc、s3cmd)
- 需要进行何种程度的手动测试,才能证明功能正常
- Sia 集成允许使用多少个 Sia 专用环境变量
- 需要达到多少测试覆盖率
- 需要或允许对 Minio UI 做哪些改动
- 需要对 Minio 文档做哪些改动
由于 Minio 维护者提出了原悬赏说明中未规定的要求,@dvstate 最终针对这些要求编写了三个截然不同的集成版本(第一个、第二个、第三个)。
建议采取的行动:
对于未来的 Sia 悬赏,应与第三方维护者合作,预先确定需求,并将这些需求纳入悬赏评奖标准。
为悬赏设立客观的验收测试。例如:
使用 siad 部署一台服务器,并在额度中存入 500 SC。
客户端使用以下命令启动 minio:
export MINIO_ACCESS_KEY=minioaccesskey export MINIO_SECRET_KEY=miniosecretkey ./minio gateway sia客户端机器上有 100 个大小从 1 KB 到 10 GB 不等、总大小不超过 4 TB 的文件,存放在
~/test-data文件夹中。文件包含嵌套文件夹,文件夹深度最多为 3 层。客户端机器成功运行以下命令:
SERVER=insert.server.hostname # replace with actual server mc config host add minio-sia \ "http://${SERVER}" minioaccesskey miniosecretkey S3v4 mc mb minio-sia/sia-test-bucket # Upload test files. mc cp --recursive ~/test-data/* minio-sia/sia-test-bucket/ # Download test files. mc cp --recursive \ minio-sia/sia-test-bucket/* ~/test-data-downloaded/下载文件的 SHA-1 哈希值与原始文件的 SHA-1 哈希值一致
如果发现悬赏公告存在歧义,应在竞赛进行期间持续更新公告,并附上变更日志,说明发生了哪些变化。
明确说明悬赏问题跟踪器是悬赏获胜要求的权威来源。
悬赏参赛者无需满足官方悬赏跟踪器之外出现的要求。
悬赏依据概念验证而非成功集成发放
Nebulous 在 Sia 核心开发者审阅后发放了悬赏,但当时 Minio 维护者尚未批准。悬赏真正的目标是将代码集成进 Minio 的代码库,否则用户会不愿部署 @dvstate 那个无人维护的分叉版本。
Sia 很幸运,@dvstate 在自己职责结束很久之后仍继续处理 PR,但悬赏真正目标的完成不应依赖悬赏获得者的善意。
悬赏发放前,大家都有尽快赢得奖金的紧迫感——要求的改动会在数小时或数天内完成。悬赏发放后,延迟增加到了数周。
这既符合预期,也合情合理,因为 @dvstate 是以志愿者身份、尽力而为地开展工作。Sia 能获得任何小于无穷大的延迟都算走运。
建议采取的行动:
- 根据成功集成而不是概念验证发放悬赏。
- 将成功合并到目标代码库明确规定为未来悬赏的要求。
Minio 集成重复了 siac 命令行客户端中的逻辑
Minio 集成代码中有 30%—40% 只是用于实现 Sia API 的逻辑。这些代码重复了Sia 核心代码库中已有的代码,因为 siac 命令行客户端实现了相同的功能。
Sia 没有为任何语言提供官方 API 绑定,包括 Sia 的原生语言 Go。
建议采取的行动:
- 为 Sia API 创建官方 Go 客户端库。让
siac成为该库的参考客户端。重构 Minio 集成,使其使用这个库。 - 对于未来要求使用非 Go 代码的悬赏,要求提交者创建一个用于实现所需 Sia API 功能的库。这个库应独立于特定应用的代码。
Minio 集成的测试覆盖率微乎其微
只有两个简单函数拥有测试覆盖,因此很难发现对 Sia Minio 代码的改动是否会破坏 Minio 的功能。
建议采取的行动:
- 将自动化测试设为未来 Sia 悬赏的要求。
审阅期间的信息孤岛
关于 PR 所需改动的关键讨论是在私下进行的。除了 @dvstate 或 @harshavardhana 之外,没有人能够跟踪进展或帮助推动 PR 向前推进。
建议采取的行动:
- 根据成功集成而不是概念验证发放悬赏。
- 要求在集中位置进行讨论(例如悬赏对应的 Github issue),以便所有悬赏申请者都能获得相同的信息。
“先完成者得”悬赏会制造不良激励
悬赏计划的规则规定:
一项悬赏只会向一个提交发放一次;除非另有说明,悬赏将发放给第一个满足该悬赏所列全部标准的个人或团队。
这会激励悬赏提交者优化方案、尽量降低实现成本,从而抑制他们在可读性、可维护性或清晰文档方面投入时间。
就 Minio 集成而言,代码确实有详尽的文档,但缺少测试,并且将 Sia 逻辑与 Minio 逻辑混在一起,这可能给未来的维护带来挑战。
这一制度也会抑制协作或改进。如果某位开发者发布了一个解决方案,其他开发者就没有动力再尝试,因为悬赏很可能会给第一个提交者。规则没有涵盖这种情况,因此也没有改进其他申请者提交方案的途径。
建议采取的行动:
- 采用不区分先后的“提交窗口”
- 规定一段不以提交速度为评判因素的时间窗口(例如,将悬赏竞赛开始后前两周收到的所有提交视为同等有效)。
- 申请者可以提前提交,但其他人可以复刻并改进其工作(必须是实质性改进,而不只是重命名几个符号)。在这种情况下,悬赏由 Nebulous 自行决定在参与开发的开发者之间分配。
- 初始提交窗口结束后,将悬赏授予第一个有效提交。
第三方验证困难
Minio 团队此前没有 Sia 经验。在 Minio 愿意合并 PR 之前,@dvstate 不得不自费部署测试服务器,并与 Minio 维护者合作完成此前未公布的一系列手动验证步骤。
建议采取的行动:
- 对于未来的第三方集成悬赏,由悬赏组织者负责验证解决方案,并与第三方合作伙伴协作,帮助他们完成验证。
- 为悬赏设立客观的验收测试。(参见“需求不明确”)。
随机一篇博客