其他用户已登录 如果继续 则会将他们断开连接_做需求分析,使用用户故事工具的禁忌,你知多少?...

此文来自于:翻译 IIBA 官网 博客文章

用户故事是一个与软件开发的敏捷方式相关的术语。 当我们想到Scrum时,通常会将其以 User Story 及其他方式联系在一块。

什么是用户故事?

当然,它是一个非常流行并广泛应用的技术。常常被用来做个性化需求。它用简短而明确的方式描述了指定类型的用户想要做什么及为什么这么做。总而言之,它进化了被交付的价值。

有时候人们习惯从狭义上理解用户故事,仅作为核心部分,即“价值声明”。这是描述实现特定故事时所传递的价值的声明。让我们首先解决这一部分。

价值声明

通常一个“价值声明”是基于一个范本,可能最受欢迎的是:

“As a

“As a

这给了我们一个三个主要元素的结构:

行为《谁?》—表明了一个特定的用户类型(设计行为与这个系统互动,例如,管理员、顾客、供应商等等)。通常识别了各种各样的用户群体,他们使用这个系统的原因不同,权限级别也不同。

行为---描述了在这个系统中,设计好的行为主要目的是什么,已执行的活动的描述

价值---具体阐述 已实现背后描述交付价值的原因。不幸运的是,这是非常容易犯错的一个元素,因为它经常不会被适当地展示或者有时候直接跳过。在我看来,这会造成一个非常严重的问题:要交付的业务价值已经消失,而它却成为我们关注的中心。

e25b39212b428ddb9f6ed5fd7da38907.png

用户故事的其他元素

剩下的元素是:

标题-可选择的。它通常是一个用户故事目标一句话简短的陈述

对话---用户故事应仅作为与项目团队和其他利益相关者进行进一步讨论的简介,是进一步考虑和相关建模的基础。 此元素不应被视为可见的书面文字片段。 而是应强调每个故事都需要更广泛的对话。

验收标准———他们帮助细化用户故事工具及确认它的界限。这儿有很多需要遵守的条件以便它确认需求价值是否需要被交付?

用户故事工具适合每个情景?

行进一步的讨论和考虑,以寻求适当的解决方案。 听起来不错,实际上如此好,以至于这种技术经常被滥用。

我听说过一个观点,那就是:敏捷不会辨认出这个文档,或者它只能辨认出其仅仅允许的格式。当然了,这个观点是错误的。

在过去我曾经作为业务分析师工作过的一个团队中,我遇到以下情况:当我们遇到由我的团队开发的系统要与另一个团队开发的系统集成时,我问另一个业务部门。 分析师分享了这些文档,以便我可以了解他们一部门,比如说其功能,可用的界面等。因而我收到了与他们的部分开发相关的153个用户故事的列表…当然,这些用户故事是这几年开发的, 它们是在以后的修改中创建的,并且在用户案例中也进行了描述。 因此,基于可用列表为系统创建一致的愿景似乎是一项极其艰巨的任务。

这是一个非常典型的例子,尽管用户故事通常非常有用,但不应将其用于所有目的。

f47126604c643f85490d78e8729c727a.png

在哪里使用用户故事?

总之:无论你什么时候需要存储以短期目标为基础的需求,及有一个要强调其交付价值的需求时。除此以外,为了找到共同的理解及继续从事创建一个解决方案模型的工作,用户故事工具被用来做进一步讨论的介绍。

除此之外,由于其特殊的性质,可以将工作划分为一些精炼的功能或质量要求,因此,用户故事可以用于:

优先讨论

工作评估

产品研发和其版本计划

 画高级需求地图

设计验收测试

追踪和报告工作进程

a85a70604e5cccd51423c288e32c9d97.png

什么地方不适合使用用户故事工具?

首先,用户故事不能被用作一个长期的需求储存工具。他们被证明不是用于开发和维护产品的文档的良好基础。大部分原因是没有其他额外的文档,仅仅依靠用户故事工具,如果要重建当下的系统声明就变得非常困难。

重要的是要记住:通常来说仅仅凭用户故事自己,没有任何背景不能让研发团队有效率地工作。他们需要更大的范围,以提升已实施变更、目标和对系统各个组件影响的理解水平。它可能提供我们使用其他的技术和不同类型的文档。

我的建议

· 按照其名称使用用户故事:记录短期使用的要求

· 将它们视为进一步讨论的介绍,而不是固定且不可协商的要求

· 不要试图使所有内容都适合用户故事。 使用其他形式的文档来支持它,该文档更适合您的需求,例如图表,界面模型,用例描述等。

· 对于长期维护需求,请使用其他合适的技术。

· 始终记住要交付的价值的正确描述(请参阅上述用户故事结构的最后一个元素:价值声明)

d8c475629483588e60fd89dfed4f44ab.png

关于作者:

Radek在担任业务分析师和产品负责人方有丰富的专业经验。 他是一名专业人员,曾与各种IT团队合作,为不同规模的组织(从小型初创企业到国际公司)做过项目。

Radek是国际商业分析协会波兰分会的会员。 他持有IIBA颁发的以下证书:CBAP(业务分析专家认证),CCBA(业务分析能力证书,比CBAP证书含金量低一点)和IIBA-AAC(敏捷分析证书)。

Radek与多家公司和机构合作,担任商业分析培训师。

参考文献:

A Guide to the Business Analysis Body of Knowledge® (BABOK® Guide). Version 3.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,你的问题是关于禁忌搜索算法在车辆路径规划问题中的运用,对吧?没问题,我为你解答。以下是我对禁忌搜索算法在带时间窗的车辆路径规划问题中的理解。 首先,什么是禁忌搜索算法?它是一种启发式搜索算法,主要用于解决组合优化问题,如旅行商问题、车辆路径规划问题等。禁忌搜索算法通过维护一个禁忌表来避免陷入局部最优解,同时利用邻域搜索来探索更多的解空间。 在车辆路径规划问题中,我们需要找到一组车辆的路径,使得每个客户都能在规定的时间窗内被服务,并且最小化车辆的行驶距离或时间。这个问题可以建模为一个带时间窗的车辆路径规划问题,其中每个客户对应一个时间窗,表示在这个时间窗内可以进行服务。我们需要设计一个算法来求解最优的车辆路径。 禁忌搜索算法可以用于解决带时间窗的车辆路径规划问题。具体来说,我们可以将每个解表示为一组车辆的路径,然后利用邻域搜索来寻找更好的解。在搜索过程中,我们需要维护一个禁忌表,记录一些不允许的移动操作,以避免陷入局部最优解。 例如,我们可以定义一个邻域操作为交换两个客户的位置,然后根据目标函数(如车辆行驶距离或时间)来评估移动的好坏。如果这个移动可以使得目标函数更优,那么就接受这个移动;否则,我们需要将这个移动加入禁忌表中一段时间,防止重复搜索同样的解。在搜索过程中,我们需要不断更新禁忌表,以避免陷入局部最优解。 下面是一个简单的 Java 代码实现禁忌搜索算法解决带时间窗的车辆路径规划问题。 ```java public class TabuSearch { public static void main(String[] args) { // 初始化车辆路径 List<List<Integer>> routes = initializeRoutes(); // 初始化禁忌表 Map<String, Integer> tabuTable = new HashMap<>(); // 初始化当前最优解 List<List<Integer>> bestRoutes = new ArrayList<>(routes); double bestCost = calculateCost(bestRoutes); // 迭代搜索 for (int i = 0; i < maxIterations; i++) { // 随机选择一个邻域操作 Move move = selectMove(routes); // 计算移动后的车辆路径以及目标函数 List<List<Integer>> newRoutes = applyMove(routes, move); double newCost = calculateCost(newRoutes); // 判断是否接受移动 if (shouldAccept(newCost, bestCost, tabuTable, move)) { routes = newRoutes; if (newCost < bestCost) { bestRoutes = new ArrayList<>(newRoutes); bestCost = newCost; } } // 更新禁忌表 updateTabuTable(tabuTable, move); } // 输出最优解 System.out.println(bestRoutes); } /** * 初始化车辆路径 */ private static List<List<Integer>> initializeRoutes() { // TODO: 实现车辆路径的初始化 } /** * 计算车辆路径的目标函数(如车辆行驶距离或时间) */ private static double calculateCost(List<List<Integer>> routes) { // TODO: 实现目标函数的计算 } /** * 随机选择一个邻域操作 */ private static Move selectMove(List<List<Integer>> routes) { // TODO: 实现邻域操作的选择 } /** * 应用移动操作,得到新的车辆路径 */ private static List<List<Integer>> applyMove(List<List<Integer>> routes, Move move) { // TODO: 实现移动操作的应用 } /** * 判断是否接受移动操作 */ private static boolean shouldAccept(double newCost, double bestCost, Map<String, Integer> tabuTable, Move move) { // TODO: 实现移动操作的接受判断 } /** * 更新禁忌表 */ private static void updateTabuTable(Map<String, Integer> tabuTable, Move move) { // TODO: 实现禁忌表的更新 } } /** * 表示一个移动操作(如交换两个客户的位置) */ class Move { int i; int j; public Move(int i, int j) { this.i = i; this.j = j; } } ``` 以上代码只是一个简单的示例,具体实现需要根据具体的问题进行调整。希望能对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值