您正在学习的是试看内容,报名后可学习全部内容 报名课程

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 <role>/ 作为<角色>
I'd like to <function>/ 我希望 <功能>
So that <value>/ 从而可以 <价值>

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

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的需求表示形式。

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

思考题

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

欢迎你在留言区分享自己的思考或疑惑。