反馈闭环

最终能够真正变成体验日志条目的功能请求模板

阅读约 1 分钟

功能请求模板,是一份只有四个问题的表单:这个人正在尝试做什么、什么阻碍了他们、他们尝试过什么替代方案,以及事情完成之后他们希望怎样被告知。表单上通常还会出现的其他东西——优先级选择器、工作量估算、商业价值评分——都是为接收请求的团队准备的,而提交请求的人往往会把这些内容填错。

整洁的请求并不是检验一份模板好坏的正确标准。正确的标准是:六个月后,当这个功能真正上线时,是否有人能够找到这份请求、理解它,并把消息告诉写下它的那个人?大多数模板都是为了收集信息而设计的。这一份,是为循环真正闭合的那一天而设计的。

一份功能请求模板应该包含什么

它应该包含目标、障碍、变通方案,以及一条回到请求者身边的路径。这四个字段按这个顺序排列,每一个都回答了团队之后会问的一个问题。

字段它之后回答的问题它出现在表单上的原因
你在尝试做什么?我们做出来的功能,是不是他们真正需要的那个?目标能比任何具体的方案存活得更久
今天是什么阻碍了你?“完成”到底应该是什么样子?只标出差距,不去规定具体的修复方法
你现在改用什么代替?这件事到底有多紧急?一个痛苦的变通方案比一个优先级选择器更有说服力
我们应该怎样告诉你?谁会收到”已发布”的那条消息?这是大多数模板里遗漏掉的字段

刻意不包含的东西:作为必填项的建议解决方案(作为自由文字里的评论可以,但不能作为提问的框架)、一个优先级选择器(每个提交者都会选高),以及任何工作量或价值的估算(这是团队分类之后的工作)。一份要求提供解决方案的模板,收到的是关于按钮的请求;一份要求提供目标的模板,收到的是关于结果的请求,而结果,正是体验日志条目所要讲述的对象。

这份模板

这是我们使用的 GitHub issue 模板,以表单的形式呈现。把它粘贴进 .github/ISSUE_TEMPLATE/feature_request.yml,它就会在 New Issue 页面上渲染成一份结构化的表单。通过它提交的请求,会落地成和反馈小组件提交的 issue 拥有相同字段的 issue,这一点在下一节里会很重要。

name: Feature request
description: What you are trying to do, and what stops you.
labels: ["feature-request"]
body:
  - type: textarea
    id: goal
    attributes:
      label: What are you trying to do?
      description: >-
        The outcome, not the button. "Export a month of invoices as one
        PDF" beats "add a PDF export".
    validations:
      required: true
  - type: textarea
    id: blocker
    attributes:
      label: What stops you today?
      description: >-
        Where the product runs out. An error, a missing option, a limit.
    validations:
      required: true
  - type: textarea
    id: workaround
    attributes:
      label: What do you do instead?
      description: >-
        The spreadsheet, the script, the manual step. "Nothing, I gave
        up" is a valid answer.
  - type: input
    id: contact
    attributes:
      label: How should we tell you when it ships?
      description: >-
        An email address, or leave blank to be notified only on this
        issue.

两个细节在起作用。labels: ["feature-request"] 意味着这个请求在创建时就已经被分类,而不用等到有人去做分类整理。最后一个字段之所以存在,是因为”我们会通知你”是一个承诺,而一个承诺需要一个地址。

一个功能请求应该带有哪些标签

一个功能请求应该带有一个说明它是什么的标签、一个说明它有多紧急的标签,以及一个说明它来自哪里的标签。三个标签,三个维度,每一个都由不同的读者来使用。

标签取值谁会读它
种类feature-request、bug决定它进入哪个队列的人
优先级priority:low、priority:medium、priority:high规划下一个周期的人
来源from-widget、from-form、from-support统计请求都来自哪里的人

小组件在把一次提交记录为一个 issue 时,会打上前两个维度的标签以及 from-widget;from-form 和 from-support 是为通过其他途径进来的请求准备的建议。小组件的标签是:种类(bug 还是 feature-request,仅凭消息内容由一个分类器来判断)、优先级(一份冷静而具体的崩溃报告是高;一个已经被问过的重复问题是低;任何哪怕只是暗示了安全问题的内容,无论措辞如何,都会被判为 bug 且优先级为高),以及 from-widget。这同样的三个维度,对通过上述模板手工提交进来的请求也一样有效,而这正是重点所在:不管一个请求从哪里进来,它都是一个请求。

还有一个惯例:小组件会在把 issue 记录下来之前,先把提交者的邮箱地址从 issue 正文里去掉,因为这个 issue 所在的仓库可能是公开的,然后用一个提交参考号来代替它。这个地址不会进入 issue;提交者直接在小组件里跟进结果。如果你的追踪系统对团队之外的人可见,联系方式字段也应该做同样的处理。

一个功能请求是如何变成体验日志条目的

一个功能请求变成体验日志条目,是在一个 pull request 关闭了这个 issue、并且从那个 pull request 起草出来的条目回过头链接到它的时候。这个机制依靠的是 GitHub 自己的关闭关键词:一个描述里写着 Fixes #142 的 PR,会在合并时关闭 142 号 issue。如果你的体验日志条目是从已合并的 pull request 起草的,草稿就能连同这个 issue 编号一起被携带过来,这条条目也就知道是谁提出的请求。

这正是这份模板要求提供目标、而不是解决方案的原因。当条目被写出来时,目标正是撰写者需要的那句话:“你现在可以把一个月的发票导出为一份 PDF 了”是一条体验日志条目。“新增 PDF 导出”是一条提交信息。从 pull request 起草的体验日志工具可以完成收集和关联,但措辞依然需要一个人来完成,而这个人需要目标。

上线之后会发生什么

请求者会收到通知,并附带指向该条目的链接。在我们的设置里,对于通过小组件进来的请求,这是自动完成的:一条”Shipped — <条目标题>“的评论,带有指向已发布条目的链接,会在一个人批准了该条目之后被发布到那个 issue 上,同时小组件也会向提交者展示同一条条目。用这份模板手工提交的 issue 不会收到自动评论;请按同样的规则,自己去闭合这个循环。这条评论是在批准的时候发布的,而不是在合并的时候,这是刻意的:一条在事情还没真正上线之前就说它已经上线的评论,是一个带着时间戳的、被打破的承诺。每个请求最多只会被通知一次;对同一条条目再次批准,不会产生第二条评论。

如果你是手工完成这件事,规则是一样的。不要从 pull request 那一刻就闭合循环。要从已发布的条目那一刻闭合,而且只闭合一次。信息流和小组件会把同一条条目传递给没有提出请求的所有人,也就是大多数人;而那条评论,是为提出过请求的那个人准备的。

为什么大多数功能请求模板会失败

它们的设计目的是让分类整理更容易,而它们也确实做到了这一点,代价是牺牲了对请求者来说唯一重要的那个时刻。一份有十二个字段的模板,会收到更少的请求,而它收到的那些请求,来自那些有耐心填完十二个字段的人,而这些人并不等同于真正需要这个功能的人。一份只有四个字段、其中一个是”我们该怎么联系你”的模板,会收到更多的请求,并且能够真正回应每一个请求。

FAQ

功能请求模板应该询问优先级吗? 不应该。应该改为询问变通方案。“我每周五都导出到一份电子表格里,然后重新手工录入一遍”,比提交者自己选了”高”的一个下拉菜单,能透露出更多关于优先级的信息。

请求者应该提出解决方案吗? 可以,写在自由文本里。但不要把它当作提问的框架。以解决方案的形式写出来的请求,彼此之间更难合并,也更难据此写出一条体验日志条目。

功能请求应该出现在公开路线图上吗? 一旦被纳入计划,就应该。同一个 issue 上的一个标签,会把它放进计划中的那一列,请求者就能看着它移动。公开路线图这篇文章讲的正是这套机制。

重复的请求应该怎么处理? 把新的请求链接到已存在的那个 issue 上,并标注为低优先级;不要把它关闭。每一个重复的请求,都是又一个需要在上线时被告知的人。借助 Changeloop 的自动评论,只有当 pull request 也点名了他们的 issue(Fixes #142, fixes #187)时,这个人才会被告知。

这份模板应该放在哪里? 放在将会接收 pull request 的那个仓库里,这样关闭关键词才能生效。放在一个独立追踪系统里的请求,必须在合并时手工建立关联,而这一步,正是最容易被省略的那一步。


本文的技术内容未经独立审核。如有错误,请告诉我们,我们会更正。

changeloop 相关页面: 开发者文档, changelog 工具对比

changeloop
打造闭环 changelog 的团队。用户提出需求,你的团队交付,提出需求的人得知结果。