拉取请求审查指南编辑

对 Kibana 做出的每一个更改都必须符合高标准,虽然拉取请求的质量最终由作者负责,但 Kibana 团队成员有责任在审查过程中进行验证。

坦率地说,不可能建立一个具体的清单来涵盖我们在审查拉取请求时可能遇到的所有情况,因此本文档试图列出一些明显的共同要求,同时也概述了我们在进行任何拉取请求审查时应该有的一般理念。

我们不期望也不打算让拉取请求审查采用本文档的形式,即最上面的指南总是先应用,最下面的指南总是最后应用。应该将整个文档视为一个整体,而不是一系列必须按顺序完成的待办事项。

虽然审查过程始终由 Elastic 工作人员完成,但这些指南适用于所有拉取请求,无论它们是由社区成员还是 Elastic 工作人员创建的。

目标受众编辑

本文档的目标受众是拉取请求审查员。对于 Kibana 维护者来说,拉取请求审查是我们对贡献过程唯一拥有完全控制权的部分。任何给定拉取请求的作者可能不了解我们对拉取请求的最新期望,并且他们可能根本没有阅读过我们的指南。作为审查员,我们有责任指导人们完成这个过程,但如果没有一套通用的书面原则,就很难始终如一地做到这一点。

拉取请求作者也可以从阅读本文档中受益,因为它将有助于在早期在作者和审查员之间建立一套共同的期望。

快速拒绝编辑

每个拉取请求都是不同的,在审查任何给定的拉取请求之前,审查员应该考虑处理拉取请求审查的最佳方式,以便如果最终拒绝更改,则应尽早在流程中完成。

例如,审查员可能希望尽早在产品级别审查包含新 UI 功能的拉取请求。另一方面,也许作者正在提交一个过去由于关键架构决策而被拒绝的新功能,在这种情况下,审查员可能应该在深入研究其他任何内容之前,先关注架构的健全性。

三大重点编辑

我们希望在所有拉取请求中遵循许多独立的要求和指南,但有三件事特别突出,比其他所有事情都重要。

  1. 我们希望产品中进行此更改吗?

    仅仅因为一个人花时间构建了一些东西,并不意味着我们希望产品中存在这种变化,这就是为什么我们鼓励每个人在着手做之前先提出问题来描述他们想要做什么。

    我们添加的每个功能都会永久地分散我们对构建和支持其他功能的注意力。从字面上看,我们可以维护的功能数量是有限的,因为它们都需要我们投入一点时间和精力,因此,审查项目的增强功能不仅要审查其质量,还要审查其增加的价值、维护负担以及它们与我们对项目的长期目标的一致性,这一点很重要。

    随着时间的推移,情况也会发生变化,因此,不断重新评估我们围绕是否希望项目发生某些变化而做出的决定非常重要。有些更改需要花费大量时间来构建,并且有可能在我们完成这些更改时,情况已经发生了足够大的变化,以至于我们不再希望项目发生变化。

  2. 这种变化在架构上合理吗?

    围绕如何从技术上构建变更做出糟糕的决定意味着我们立即承担了技术债务,这将不必要地分散我们未来改进项目的精力,因为我们需要维护现有的变更、追查错误,并最终在未来重新构建该领域。

    没有一种万能的方法来评估给定的更改在技术上是否合理,因此我们必须依靠我们在构建软件方面的具体知识和经验。当两位经验丰富的开发人员对什么是和不是架构合理的意见不同时,这尤其困难,因此需要作者和审查员都表现出同理心,尽一切努力去理解对方,并就前进的道路达成共识。

    这里的目标不是找到一个最佳架构,因为这不太可能被量化。任何问题通常都有许多架构合理的解决方案,因此审查员应该客观地关注该目标,而不是他们自己对如何构建更改的愿景是否“更好”。

  3. 是否有足够的测试来确保这种变化在未来不会被破坏?

    如果我们依靠手动测试来捕捉错误,我们就无法扩展我们的开发工作,也无法继续有效地改进和维护产品。手动测试是我们最后一道防线,它是确保产品稳定的效率最低、成本最高的方法。这意味着我们对产品进行的每一项更改都需要有足够的测试覆盖率。

    这不仅仅是测试文件数量的问题。测试本身的代码与产品中的代码一样重要。

    我们所有的代码都应该有单元测试来验证其行为,不仅包括“快乐路径”,还包括边缘情况、错误处理等。当您更改模块的现有 API 时,应该始终至少有一个失败的单元测试,这意味着我们需要验证所有使用该 API 的代码是否在必要时都能正确处理更改。对于级别足够高的模块,这意味着产品中会出现重大更改,我们需要相应地进行处理。

    除了广泛的单元测试覆盖率之外,拉取请求还应包括相关的功能和集成测试。在某些情况下,我们可能只是在测试与文件系统、网络、Elasticsearch 等集成的编程接口(例如服务)。在其他情况下,我们将通过 HTTP 测试 REST API,或者将屏幕截图/快照与先前已知的可接受状态进行比较。在最坏的情况下,我们使用 selenium 在 Kibana 的运行实例上进行基于浏览器的功能测试。

    增强功能几乎总是以广泛的单元测试为基础,以及功能和集成测试。错误修复应始终包括回归测试,以确保将来不会再次出现相同的错误。

产品级审查编辑

审查员不仅要评估代码本身,还要评估产品中面向用户的更改的质量。这通常意味着他们需要在本地检出分支并“试用”它。除了“我们希望产品中进行此更改吗”的详细信息之外,审查员还应该寻找错误并评估实现的功能的可访问性和实用性。应特别注意错误情况和边缘情况,以确保它们在产品中得到妥善处理。

一致性、风格、可读性编辑

拥有相对一致的代码库是我们构建可持续项目的重要组成部分。在任何时候都有数十名活跃的贡献者,我们依靠自动化来帮助确保一致性 - 我们通过 CI 强制执行一套全面的代码检查规则。我们还将推出 prettier,使其更加自动化。

对于无法轻松自动化的内容,我们维护了一个风格指南,作者应遵守该指南,审查员在审查拉取请求时也应牢记该指南。

除此之外,我们就进入了主观领域。像“这不太可读”这样的说法几乎没有帮助,因为它们无法量化,但这并不意味着审查员应该完全忽略由于编写方式而难以理解的代码。编写任何特定代码都没有绝对“最佳”的方法,因此追求这种方法不应该是我们的目标。相反,审查员和作者都必须接受,可能有很多不同的适当方法可以用代码完成同一件事,只要贡献使用的是其中一种方法,那么我们就很好。

另一方面,如果审查员指出某个特定的代码块难以理解,那么第一个查看代码的人就很难理解它。如果审查员强烈认为这是一个问题,他们应该向作者提出这个问题以供考虑,并可能提出替代方案。审查员必须务实,他们的目标应该是推动讨论向前发展,而不是简单地设置障碍。

如果有疑问,参考代码库中的“现有技术”,尤其是在贡献代码库的区域内和周围,通常是一个好主意。

也可能有些时候,一个人会受到某个特定贡献的启发,想要引入一种新的代码风格方式,而我们已经有不同的风格指南或“现有技术”。在拉取请求中提出这一点是可以的,但最终该讨论应该分支到一个单独的问题或拉取请求中,以更新相应的指南。如果此更改是由审查员提示的,则不应阻止原始拉取请求。如果更改是由作者提示的,则他们可以选择更新拉取请求以与我们现有的指南保持一致(首选),或者他们可以选择完全阻止拉取请求,直到该单独的风格指南讨论结束。

吹毛求疵编辑

吹毛求疵是指审查员在拉取请求中找出微不足道且不重要的细节,并要求作者更改它们。这是一个完全主观的类别,不可能普遍定义,并且对吹毛求疵制定一个能让每个人都满意的全面政策也同样不切实际。

审查员应该能够自在地就拉取请求给出任何反馈,无论它多么微不足道。作者应该同样能够自在地忽略他们认为微不足道且无关紧要的反馈。

通常,审阅者对于他们将要给出的反馈是否吹毛求疵有自己的看法。虽然不是必需的,但将反馈标识为吹毛求疵非常有帮助,例如“nit:在此处添加换行符会有所帮助”。这有助于作者理解您的意图。

处理分歧编辑

审阅者和作者之间发生意见冲突很常见,而且有时很难调和这些意见。理想情况下,人们可以本着这些准则的精神共同努力达成共识,但如果这不起作用,最好让第三个人参与讨论。我们的拉取请求通常有两名审阅者,因此合适的第三个人可能已经很明显了。否则,请联系最合适的职能领域,或者在领域不明确的情况下联系技术负责人。

不恰当的审阅反馈编辑

一段反馈是否适合拉取请求通常取决于最初给出反馈的动机。

主要基于“我会如何编写这段代码?”的心态来*要求*作者进行更改是不合适的。审阅者没有编写代码,他们在审阅过程中的关键目的不是将贡献修改成他们自己会写成的形式。如果审阅者想提供这种类型的反馈,他们应该像在吹毛求疵部分提到的那样将其限定为“nit”,以明确表示作者可以选择接受或拒绝。

诸如“这太糟糕了”之类的煽动性反馈根本就不是反馈。它既刻薄又无益,而且永远不合适。

清单编辑

为所有可能的拉取请求中应该发生的所有事情建立一份全面的清单是不切实际的,但这并不意味着我们缺乏一套可以列举的具体最低要求。以下项目应针对任何拉取请求进行仔细检查

  • CLA 检查通过
  • CI 作业运行并通过
  • 符合我们各种风格指南的精神
  • 具有全面的单元测试覆盖率
  • 自动化测试提供了高度的信心,确保更改在无需手动验证的情况下继续有效
  • 包含适当的产品文档 (asciidocs)
  • 任何新的 UI 更改都可供不同能力的人员访问,包括但不限于颜色对比度足够、键盘导航和 aria 标签
  • 在适当的情况下采取了充分的安全保护措施,尤其是在呈现 API 响应、解析表达式、编译 URL、加载外部内容或重定向时
  • PR 标题总结了更改(没有“修复错误编号 123”)
  • PR 描述包括

    • 更改内容的详细摘要
    • 更改的动机
    • 如果 UI 发生变化,则提供屏幕截图
    • 指向 PR 关闭的每个问题的链接(例如,关闭 #123)