编写正确的用户故事的工程指南

敏捷的人着迷于编写用户故事。 它确实是一种强大的工具。 但是,根据我的实践 ,很多人都做错了。

让我们来看一个例子:

As a user
I want to receive issue webhooks from Gitlab
So that I can list all current tasks

好像是一个有效的用户故事,不是吗? 实际上,这个小故事包含多个问题。 而且,如果您在其中找不到至少8个错误,则值得您阅读这篇文章。

本文分为三个主要部分:

  1. 使用默认的用户故事格式变得更好
  2. 使用BDD重写用户故事以使其可验证
  3. 将用户案例与测试,源代码和文档链接起来

尽管对于不同类别的读者来说,某些部分可能看起来更有趣,但对于每个人来说,了解完整的方法很重要。

发现和修复问题

众所周知即使乍一看看起来我们的要求不正确,我们的所有要求也必须正确,明确,完整,一致,排名,可验证,可修改和可追溯

用户故事往往没有某些给定的特征。 我们需要解决这个问题。

使用一致的语言

是否以某种方式连接了“接收问题的网络钩子”和“列出所有当前任务”? “任务”和“问题”是否相同? 可能是完全不同的事情,或者只是措辞不佳。 我们怎么知道?

这就是词汇表的用途! 每个项目都应该从定义特定术语开始,这些术语将为将来构建无所不在的语言。 我们如何首先构建此词汇表? 我们请领域专家。 当我们遇到一个新术语时:我们确保所有领域专家都正确且类似地理解该术语。 我们还应注意,在不同情况和环境下对同一术语的理解可能有所不同。

假设在咨询了领域专家后,我们发现“任务”与“问题”是同一回事。 现在,我们需要删除不正确的术语。

As a user
I want to receive issue webhooks from Gitlab
+++So that I can list all current issues
---So that I can list all current tasks

优秀的。 对于相同的实体使用相同的词语将使我们的要求更加清晰和一致。

用户不想要你的东西

当我们修改了最后一行时,引起我的注意的是,用户的目标是“列出所有当前问题”。 为什么这个可怜的用户想要列出一些问题? 这样做有什么意义? 没有用户想要。 这个要求是完全不正确的。

这表明在编写需求时一个非常重要的问题。 我们倾向于混合我们和用户的目标。 尽管我们的目标是取悦用户,但我们首先应该专注于他们。 使他们的需求比我们的价值更重要。 我们应该在我们的要求中明确表达这一点。

我们怎么知道用户想要什么? 再一次,我们没有。 我们需要向真实用户或其代表咨询。 如果我们不能问任何人,也可以自己做一个假设。

As a user
I want to receive issue webhooks from Gitlab
+++So that I can overview and track the issues' progress
---So that I can list all current issues

在收集到更多反馈之后,我们知道用户需要了解项目的进度。 没有列出问题。 这就是为什么我们需要从第三方服务接收和存储有关问题的信息。

删除技术细节

您是否遇到过一个真正想“接收问题的网络狂”的人? 没有人愿意这样做。 在这种情况下,我们还将两个不同的问题混合在一起。

用户目标和实现目标的技术方法之间存在明显的区别。 “接收问题的网络信号”显然是实现细节。 明天可以将其更改为WebSockets,推送通知等。因此,用户的目标不会改变。

As a user
+++I want to have up-to-date information about Gitlab issues
---I want to receive issue webhooks from Gitlab
So that I can overview and track the issues' progress

看到? 只剩下重要信息,实现细节被剥离。

澄清角色

就上下文而言,很明显,我们正在处理某种与开发人员相关的工具。 我们使用Gitlab和问题管理。 因此,不难猜测我们将拥有不同类型的用户:初级用户,中级开发人员和高级用户。 也许项目经理和其他人也是如此。

因此,我们来介绍角色定义。 所有项目都有不同类型的用户。 即使您认为这不是显式类型。 这些角色的形成取决于您使用产品的方式或目标。 这些角色的定义必须与我们为项目定义术语的方式相同。

在这个特定的用户故事中,我们在谈论什么样的用户? 初级开发人员是否将以与项目经理和架构师相同的方式来概述和跟踪进度? 明显不是。

+++As an architect
---As a user
I want to have up-to-date information about Gitlab issues
So that I can overview and track the issues' progress

做出明智的猜测之后,我们可以通过不同的用户角色来区分不同的用户故事。 而且,它使我们可以对所提供的功能以及由谁提供这些功能的人员进行细粒度的控制。

扩展用户故事

这个简单As a <role or persona>, I want <goal/need> so that <why>很棒,因为它既简洁又强大。 它为我们提供了一种完美的交流方式。 但是,我们至少应该了解以下格式的一些缺点。

使用户故事可验证

我们仍然存在的给定用户故事的问题是它无法验证。 我们如何确定这个故事(现在还是现在)对我们的用户有效? 我们不可以。

在此用户故事和我们的测试之间没有明确的对应关系。 如果可以将用户故事作为测试来编写,那将是非常棒的……

等待,但是有可能! 这就是为什么我们有行为驱动的开发gherkin语言。 这就是为什么首先创建BDD的原因。 这意味着我们可以用gherkin格式重写用户故事以使其可验证。

Feature: Tracking issues' progress
As an architect
I want to have up-to-date information about Gitlab issues
So that I can overview and track the issues' progress

Scenario: new valid issue webhook is received
Given issue webhook is valid
When it is received
Then a new issue is created

现在,这个用户故事是可验证的。 我们可以从字面上将其用作测试并跟踪其状态。 而且,我们现在在高阶需求和实现细节之间建立了映射,这将使我们能够了解要如何精确地满足此需求。 注意,我们没有用实现细节代替业务需求,但是我们对此予以了补充

发现不完整

一旦使用gherkin编写了用户案例,我们就开始为用户案例编写场景。 我们发现同一用户故事可能存在多种情况。

让我们看一下第一个场景:“收到了新的有效问题Webhook”。 请稍等,但是当我们收到无效的Webhook时会发生什么? 我们是否应该保留此问题? 也许我们还需要做一些额外的工作?

让我们参考Gitlab的文档作为信息源,在这些情况下可能会出错以及应采取的措施。

事实证明,我们有两个不同的无效案例,我们需要以不同的方式处理。 第一个:Gitlab不小心向我们发送了一些垃圾。 第二个:我们的身份验证令牌不匹配。

现在,我们可以再添加两个方案来完善此用户案例。

Feature: Tracking issues progress
As an architect
I want to have up-to-date information about Gitlab issues
So that I can overview and track the issues' progress

Scenario: new valid issue webhook is received
Given issue webhook is valid
And issue webhook is authenticated
When it is received
Then a new issue is created

Scenario: new invalid issue webhook is received
Given issue webhook is not valid
When it is received
Then no issue is created

Scenario: new valid unauthenticated issue webhook is received
Given issue webhook is valid
And issue webhook is not authenticated
When it is received
Then no issue is created
And webhook data is saved for future investigation

我喜欢这个简单的用户故事,现在感觉像是一个相当复杂的故事。 因为它向我们揭示了其内部复杂性。 我们可以根据不断增长的复杂性调整我们的开发流程。

对用户故事进行排名

目前,尚不清楚建筑师“概述并跟踪问题的进度”有多重要。 它比我们拥有的其他用户故事重要吗? 既然看起来很复杂,也许我们可以做些更简单,更重要的事情吗?

排名和优先级对任何产品都至关重要,我们不能忽略它。 即使我们将用户故事作为编写需求的唯一方法。 有多种方法可以优先考虑您的需求,但是我们建议您坚持使用MoSCoW方法 。 此简单方法基于四个主要类别: mustshouldcouldwon't 。 并暗示我们将在文档某个位置的项目中拥有一个单独的优先级表,该表中包含所有用户故事。

同样,我们需要询问用户每个功能的重要性。

经过与使用我们产品的不同架构师的几次交谈,我们发现这是绝对must

功能优先级经过身份验证的用户必须能够发送私人消息必须架构师必须跟踪问题的进度必须有关于传入私人消息的通知是否应该支持多个消息提供者是否可以不支持加密的私人消息不会

因此,我们现在可以修改用户故事的名称,以将其映射到优先功能:

Feature: Architects must track issues' progress
As an architect
I want to have up-to-date information about Gitlab issues
So that I can overview and track the issues' progress

...

我们甚至可以将它们链接在一起。 只需使用从已排名的需求表到具有用户故事的功能文件的超链接。

这样,我们可以确保此功能将成为第一个要开发的功能,因为它具有最高的优先级。

如果没有适当的照顾,您很快就会以混乱的用户故事,测试,源代码和文档结尾。 随着项目的不断发展,将无法确定应用程序的哪些部分负责哪些业务用例。 为了克服这个问题,我们必须将所有内容链接在一起:需求,源代码,测试和文档。 我们的目标是最终得到如下结果:

我将使用python来说明原理。

我可以将用例定义为您的应用程序可以执行的一组独特的高级操作(它看起来与Clean Architecture的观点非常相似)。

我通常定义一个称为用usecases的包,并将所有内容放入其中,这样就可以轻松地一次忽略所有现有用例。 每个文件都包含一个简单的类(或函数),如下所示:

class CreateNewIssueFromWebhook(object):
"""
Creates new :term:`issue` from the incoming webhook payloads.

.. literalinclude:: path/to/your/bdd/user-story/file
:language: gherkin

.. versionadded:: 0.2.0
"""

def __call__(self, webhook_payload: 'WebhookPayload') -> 'Issue':
# Do something ...

我使用sphinxliteralinclude 指令来包含用于测试的相同文件,以记录域逻辑。 我还使用词汇表来表明issue不仅仅是一个随机的词:这是我们在该项目中使用的特定术语

这样,我们的测试,代码和文档将尽可能地结合在一起。 我们将不必为它们担心。 我们甚至可以自动完成这一过程,检查里面的所有类usecases/.. literalinclude在他们的文档指令。

您也可以使用此类来测试我们的用户故事。 这样,您将绑定实现此用户案例的需求,测试和实际域逻辑。

任务完成!

结论

本指南将帮助您编写更好的用户案例,关注他们的需求,保持源代码的清洁,并为实现不同(但相似)的目的而尽可能地重用。

最初于 2019 年2月23日 发布在 sobolevn.me

From: https://hackernoon.com/engineering-guide-to-writing-correct-user-stories-238bb2a2b6e0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值