11|如何有效编写用户故事?

你好,我是徐昊,今天我们来继续学习 AI 时代的软件工程。

前面几节课我们讲解了如何使用 LLM 辅助业务建模,这个过程里,我们非常依赖用户故事作为业务上下文的输入。那么怎么写好用户故事,就成了我们利用 LLM 建模的关键。

今天我们就了解一下用户故事,以及为什么用户故事是适用于 LLM 的需求表示形式。

用户故事与功能需求

对于之前尝试使用用户故事管理需求的同学,可能一直有这么个疑问,用户故事一共也就三两句话,怎么能把复杂的功能需求说清楚呢?而这恰恰是用户故事的强大之处,也是用户故事能够匹配 LLM 的原因。

让我们回看一下在前面的几节课中一直使用的例子:

作为学校的教职员工(As a faculty),

我希望学生可以根据录取通知将学籍注册到教学计划上(I want the student to be able to enroll in an academic program with given offer),

从而我可以跟踪他们的获取学位的进度(So that I can track their progress)

在这个用户故事中,我们并没有给出用户界面交互的流程,那么也就意味着,这个用户故事可以用不同的技术方案实现。

比如,如果这是一个 Web 系统,那实际操作的过程可能是,学生打开页面,看到自己的录取通知书,点击完成注册。同样的流程也可以在手机应用上实现,只不过交互流程就变成在手机上打开一个界面,看到自己的录取通知书,点击完成注册。

当然,没有用户界面的情况也可以实现,比如这是一个后台的 API 服务,那么需要根据学生的录取通知书调用对应的 API 完成注册。

而在这个用户故事里,我们并没有提及具体的技术方案到底是什么。这也就是用户故事与功能需求的一个重大差异。用户故事侧重于定义问题,而功能需求往往包含着解决方案。

正如我们前面的课程中提到的,在使用 LLM 辅助时,问题的定义是困难的,而获取解决方案则容易得多。就以这个用户故事为例,我们可以很容易地让 LLM 给出不同的技术解决方案。比如想要实现为 Web UI:

用户故事
=======
作为学校的教职员工(As a faculty),
我希望学生可以根据录取通知将学籍注册到教学计划上(I want the student to be able to enroll in an academic program with given offer),
从而我可以跟踪他们的获取学位的进度(So that I can track their progress)
任务
===
请为这个用户故事设计基于Web的交互流程

再比如,我们也可以让 LLM 帮助我们将这个需求实现为 RESTful API:

用户故事
=======
作为学校的教职员工(As a faculty),
我希望学生可以根据录取通知将学籍注册到教学计划上(I want the student to be able to enroll in an academic program with given offer),
从而我可以跟踪他们的获取学位的进度(So that I can track their progress)
任务
===
请为这个用户故事设计API

当我们关注于问题定义时,恰好也能帮我们应对需求的改变。回想一下过去二十年的技术变迁,从企业内网应用转为 Web 应用,到移动应用,再到前后端分离、功能服务化等等。我们有太多的时候,需要在不同的技术解决方案上,达成同样的目的,实现同样的价值。

当关注知识本身和问题定义时,可以让我们抽离具体的解决方案。因而用户故事本身就是一个更关注知识管理的需求管理方法。通过用户故事提炼知识之后,就可以借助 LLM 帮助我们在不同的技术解决方案上迁移了。

如何有效编写用户故事

有太多的文章和书籍是关于如何编写用户故事的,你可以参考 Mike Cohn 的《User Stories Appiled》以及 Alistair Cockburn《Writing Effective Use Cases》。这两本书的介绍更为全面。这里我着重分享一些我个人认为特别有用的技巧。

我们常用的用户故事格式通常是三段式:

As a/ 作为 < 角色 > I’d like to/ 我希望 < 功能 > So that/ 从而可以 < 价值 >

我们首先需要注意的是,对于任何一个用户故事而言,角色 - 价值是不变的,而功能可以随时发生改变,是用户故事中“可协商”的部分。换句话说,角色 - 价值定义了要解决的问题,而功能只是解决这个问题的一种方法而已。举个例子:

As a 系统管理员

I’d like to 注册用户通过用户名 / 密码登录系统

So that 追踪不同用户的行为

在这个用户故事中,“系统管理员 - 追踪不同用户的行为”是问题定义,而“注册用户通过用户名 / 密码登录系统”则是功能。这个功能可以换成其他形式,而不影响我们要解决的问题。比如“注册用户通过微信账号登录系统”也是一个可行的解决方案:

As a 系统管理员 I’d like to 注册用户通过微信账号登录系统 So that 追踪不同用户的行为

第二点需要注意的是找到真正的价值。真正的价值并不一定发生在发起操作的这个角色身上。在这个登录的例子中,另一个常见的写法是:

As a 注册用户 I’d like to 通过用户名 / 密码登录系统 So that 访问我的个人信息

这里我们认为价值体现在“注册用户 - 访问我的个人信息”,而不是“系统管理员 - 追踪不同用户的行为”。那么我们就需要区分哪个才是真正的价值。也就是登录是系统管理员受益更多,还是注册用户受益更多?

很显然,在一些场景下,用户登录对于用户本身并没有受益,比如,需要登录才能访问别人写的文章。这就是额外的步骤,并没有额外的价值,那么价值就不可能是发起操作的这个角色。类似的情况还有很多,比如员工打卡,显然员工自身的收益不会多过管理者,因而不能从员工的角度书写这个故事。

第三点就是如何编写有意义的价值陈述。价值陈述需要从用户故事拆分的方式入手,才能找到合理的切入点去阐述,否则容易陷入对于功能的复述。比如,在不知道其他功能的前提下,用户登录很容易就会写成:

As a 注册用户 I’d like to 通过用户名 / 密码登录系统 So that 我们可以登录系统

想要改正这个明显没什么价值的价值陈述方式,我们需要思考这个用户故事是怎么切分出来的,与它相关的有哪些其他用户故事,才能更好地完成价值的陈述。这里,我总结了一个用户故事拆分方式,可以帮助我们更好地寻找价值陈述:

按照这样的方式拆分用户故事时,我们需要找到不同用户角色的目标,并根据这些目标设计整体解决方案。整体解决方案中包含业务中的核心概念、关键规则和主要流程。然后我们再根据整体解决方案,设计不同角色的用户旅程。接着我们就可以从用户旅程上切分用户故事了。那么此时,用户故事只有三种写法:

  • So that 可以满足某个用户角色的目标
  • So that 可以满足整体解决方案的规则或流程
  • So that 可以进行用户旅程的下一步

比如以学籍管理系统为例。教职员工这个用户角色,核心目标是追踪学生是否完成了教学计划的学习;而学生这个用户角色,他的核心目标是按照教学计划完成课程学习。

那么针对于这些目标,我们的整体解决方案是什么呢?我们的方案是:

  • 设定一个教学计划,其中包含学生应该完成的所有课程,以及相应的学位。

  • 为每一位学生指定一个学籍,也就是学习某个教学计划的资格。

  • 学生需要根据教学计划,注册对应的课程。

  • 学生可以根据教学计划,学习对应课程,并获得成绩。

  • 每年依据学籍以及学生选课的成绩,判断学生是否能够毕业。

其中包含的主要流程是:发放录取通知、注册学籍、选课以及结业。根据整体解决方案,我们可以设计不同角色的用户旅程,比如,教职员工就是发放录取通知和结业的流程。而学生就是注册学籍和选课的流程。

那么学生注册学籍的用户故事,可以有这么几种写法:

作为学校的教职员工, 我希望学生可以根据录取通知将学籍注册到教学计划上, 从而我可以跟踪他们的获取学位的进度(满足角色的宏观目标)

作为学校的教职员工, 我希望学生可以根据录取通知将学籍注册到教学计划上, 从而我可以跟踪他们的学籍与成绩判断他是否能够毕业(满足具体解决方案)

作为学生, 我希望可以根据录取通知将学籍注册到教学计划上, 从而我可以跟踪教学计划学习对应课程(进行用户旅程的下一步)

这三种写法都是可以接受的用户故事。如果希望用户更加抽象一些,可以使用满足角色的宏观目标或满足具体解决方案的写法。

小结

用户故事的特性被总结为 Card、Conversation 和 Confirmation,这表示少而精的文字描述(Card),一段对话以及需与交付团队和客户澄清的细节。这是一个典型的不可言说知识。然而也从侧面表明了,用户故事本身就是一种不可言说知识的管理工具。

在 LLM 的时代,我们应该永远优先聚焦于问题的定义,然后才是解决方案。用户故事恰好符合这些条件,所以它是适用于 LLM 的需求表示形式。

关于用户故事的编写还有很多细节和技巧,详细内容可以阅读我推荐的两本书,其中有更多有用的推荐。

思考题

请按文中介绍的方法,根据你现在工作的场景拆分一下用户故事?

欢迎你在留言区分享自己的思考或疑惑,我们会把精彩内容置顶供大家学习讨论。