任务卡的意义

不同的团队对“任务卡”有不同的叫法,比如卡片、工单、Ticket、Work Item等。本文将其简称为卡或卡片。

一张卡片代表一件要完成的“事情”。根据项目管理的实践方式、任务拆分粒度,或是这个事情面向的对象不同,卡片的内容和重点也会发生变化。例如在 Scrum 敏捷开发中,卡片通常会被分为“故事卡”和“任务卡”。我的团队还会根据需要,补充“调研卡”、“Bug卡”等,让团队成员对一件“事情”的主题和目标有一个更快速、直观的预期。

无论类别怎么划分,一张有效的卡片都应该服务于下列一个或多个目标:

  • 进行高效、有效的沟通
  • 整理思维、发现问题
  • 确认需求和目标
  • 为验收提供指导
  • 便于项目规划和进度跟踪

我将简单说明一下我对每个方面的理解,以及如何更好的实现这些目标。

情景剧

打起来打起来打起来打起来

A:我们要做功能 A 和 功能 B,这里是需求你看一下。

B:好的,我列到项目计划里然后建个卡。

两周后

A:上次说的功能做好了吗?

B:做好了,你看一下。

A:功能 C 呢?

B:???你也没说啊。

A:可是写在需求里了啊。

B:那要再往后排了。

A:行吧……

两周后

A:功能都完成了吗?

B:完成了,可以 QA 了。

A:这里和这里有点问题,根据客户的新反馈,应该如此如此……

C:这个需求里没说清楚,代码写死了,我们现在的实现方式没法支持。

A:那要怎么样才能做到我希望的效果?

B:我们需要返工,会有额外的工作量,交付要延期了。

结局 1

A:不行,老板那边已经说好发布日期了,不可能改了。你们辛苦辛苦吧。

B & C 力争未果,开始 007 模式。最终成品质量不佳,年终奖没了,但好消息是收获了黑眼圈和发际线。

结局 2

重构难度超出想象,并且这种情况时有发生。最终项目延期 2 个月导致流产或失去商机。老板震怒,开发团队被裁。

结局 3

B:C,你考虑问题太不全面了,怎么能把代码写死呢,不考虑扩展性的吗?

C:需求什么样我就做成什么样,没必要过度设计。需求确认不是你负责吗?你怎么不问清楚了。

B:这里留出修改空间是行业惯例,你自己菜就别怪别人。

B 和 C 大打出手,被人偷拍发到网上,各路网友纷纷吃瓜。


可能你对类似的场景并不陌生。

为什么项目经常做到最后还要大返工?

为什么会互相甩锅?

开发和产品真的是死对头吗?

卡片是开始也是结束

卡片应该在一项任务的生命周期中贯穿始终:我们从建卡开始整理和分析信息,在开发过程中用遵循卡片的指导,并在关卡前完成对目标进行最后的验证。

正确、有效地建卡,合理地利用卡片,能帮助团队尽量规避上面这种撕逼的风险。

无效沟通 vs. 有效沟通

卡片是开发组沟通的重要渠道。

和开会、文档、甚至是在通信软件上的消息一样,卡片作为一个承载信息的媒介,它的首要职责是将想法传达出去,并在所有参与者中达成对某项信息的共识。

例如,一张故事卡,它要传递的信息是站在用户角度上的使用场景、功能描述、验收方法等。而一张开发任务卡则负责从技术角度说明任务目标,提供必要的技术信息,使开发者在实现过程中不会出现偏差。

只有当这些信息能够明确、准确的被另一个人接收和理解,才算形成一次有效沟通。反之,若信息模棱两可、有猜测成分,甚至信息本身不完全,都可以视作无效沟通

而要能有效沟通,最重要的事情是站在别人的立场上思考。这也是很多程序员不擅长的事情,因为相比与机器交谈,与人沟通会引入更多歧义,需要更多的表达技巧,也需要依赖更多的背景知识和上下文。

例如,程序员会在描述问题时不自觉地使用技术语言。如果对方是产品团队,则像 “状态管理”、“算法复杂度”这些词汇会让产品团队一头雾水,不明白它们体现在最终功能上是什么效果。更严重的问题是引入歧义,例如“transaction”在数据库查询和商业交易这两种语境下,会变成风马牛不相及的两件事情。好一点的结果是需要额外解释,增加了沟通成本;而坏的情况则是两边说了半天才发现刚才全白说了,或者各自套用词汇的相关经验,最终误读了原本的信息。

还有一种无效沟通是“因为写卡太麻烦,所以描述个大概就算了”。会有这种想法除了懒惰外,也可能是:

  1. 认为其他人已经了解了所有上下文,所以没必要再多费口舌。
  2. 在会议或其他线下场合已经有过口头交流,认为大家已经达成了共识。

第一种想法的原因还是没有站在别人的立场上来考虑问题。你不能假设另一个人有读心术,或你们的知识储备完全一致。如果是合作过很久的人,已经培养了一定的默契,那确实可以省略一些信息。但如果对方手上不止一件事情呢?如果他近期没有处理相关工作,而需要花一定时间来重新熟悉上下文呢?如果这个工作之后需要转给其他人做呢?

第二种想法则是过于依赖非纸面交流,忽略了将信息归档的重要性。每个人的记忆力不一样(比如我就老忘事),一些说过的话可能很快就会从记忆中淡化出去了。而且对话的时间太短,容易让一些思考仅停留在浅层次;而落实到纸面的信息可以让人更方便去反复咀嚼、分析、思考。退一万步讲,如果日后出现了问题,卡片也是很好的溯源工具,可以用于复盘和甩锅

总之,将信息准确地固定在卡片上,能够减少潜在的开发成本,避免因无效沟通而浪费的时间。

不要轻易开始

包括以前的我自己在内,很多人在拿到一张卡后,会匆匆看一眼,然后想:“就这?”然后自信满满的开始动手。然后在做的过程中,发现:

  • 要么是当时把问题想简单了,估算的时间根本不够用;
  • 要么是做一半发现有一些需求或前置条件没有调查清楚,又得去找负责人问;
  • 要么是按自己的理解做完了,又被打回来重做。

原因除了前文说的无效沟通导致卡片本身信息不完全或有歧义外,另一个问题是作为建卡人或做卡人,没有意识到卡片是控制风险的重要工具

建卡/看卡其实就是一个需求分析的过程。

以前端开发为例(这也是最容易出问题的地方),在拿到一个需求时,除了表面的信息,你需要把各种边界条件、用户交互动作的后果、可展示信息的密度等方面都考虑一遍。

如果是要做一个后端 API,则需要考虑 API 的参数限制是什么?这个 Endpoint 可能会在哪些场景中被使用?每种场景的调用方式一样吗?语义会有歧义吗?数据量的规模需不需要引入分页?鉴权方面有什么特殊要求?这些技术细节也属于需求的一部分。

你需要找出所有遗漏的信息,确认它们,并评估这些信息会对你的工作量造成多大的影响。你可能会惊讶地发现,这些被遗漏的细节会占你工作量的很大一部分。

一言以蔽之:不要“猜”需求

这个并不仅仅是建卡人的职责,而是所有参与者的职责。每个人充分利用自己的背景知识及对上下文的了解,对卡片的内容进行一定的头脑风暴,才能在实际动手之前尽可能识别风险点,评估实际的工作量。

顺便一提,这也是 Scrum 中提倡集体估点的原因。

明确、真实的目标

相比需求分析的重要性,更容易被忽略的是目标分析

这件事听起来可能有点像废话:把需求做完了不就是目标了吗?这话也对也不对。

问题在于对“需求”的定义。如果把“需求”理解为广义的“所有要做的事情”,那这句话当然是对的。既然要做的事情都做了,没有其他要做的事情了,那当然算完成了目标。

但我们的目的是通过卡片来进行更准确的沟通并指导开发。这种情况下,需要对需求目标进行狭义的区分。

我的个人理解是:“需求”更侧重于对上下文的描述,以及从宏观角度希望达成的效果,而“目标”则是验收标准 (Acceptance Criteria,简称 AC)。AC的作用只有一个:明确地指出当哪些条件被满足时,这项任务就做完了。

如何清晰描述一个条件,让人判断它是否被满足了呢?这里就不得不再拿出老生常谈的 S.M.A.R.T 标准:

  • Specific:目标是没有歧义的、明确的、任何人都有相同理解的描述。
  • Measurable:目标是可以被衡量的,而不是“随缘”的。如果指标可以被定量,那就一定要有个定量的目标。否则,应该尽量将欺描述成一个符合常识的结果。
  • Achievable:目标可以被达成。如果原始的要求无法满足,则必须要商量出一个 workaround。
  • Relevant:目标和需求是相关的。这个定义比较宽泛也比较“虚”。在建卡的语境下,我认为主要是考虑不要过度设计,不要想着一口吃成个胖子,把所有扩展重构啥的都算上,这很容易导致工作量失控。详见后文的控制工作量一节。
  • Time-bound:目标应该是有时间限制的,不能投入大量时间而看不到成果。同样,这一点在后文的控制工作量一节会进一步说明。

控制工作量

从项目管理的角度出发,项目中的每个最终进入执行阶段的子任务不宜过大。通常情况下,我建议一个任务的进行时间不应超过一周,即一周内应该得到一个结果。这样做有几个好处:

便于跟踪项目进度

项目的推进应该是逐步的、频繁的。长时间缺乏反馈或进度更新,会让人产生“失控”的感觉。这不但不利于向 stakeholders 汇报,而且会逐步失去对时间和优先级的控制。

便于拆分并行任务,合理分配资源。

过大的卡片意味着需要更多的时间投入在单一的任务上,而一个任务往往会是其他任务的依赖项。当这个任务迟迟得不到结果,会导致项目中的其他任务被阻塞。对任务进行合理拆分,不但可以解锁其他支线,同时也能允许多人在一个大功能上并行工作。

便于对结果进行评估,并调整后续计划。

拆分任务可以让团队频繁获得反馈,并根据反馈进行后续决策。例如,功能设计是否合理、技术上能否支持、优先级是否需要调整、是否应及时止损或使用替代方案,等等。如果盲目尝试一次性完成一个大任务,可能会导致最后才发现做的是无用功,或者因为积重难返而难以作出调整。

另外,从代码的角度讲,一个耗时过长的卡片往往对应一个巨型PR,这对于 Code Reviewer 来说无疑是痛苦的,而且也会不可避免地导致 Code Review 质量下降。

案例学习

为了更好的理解上面的内容,我们用一个栗子🌰来说明,如何将一个“一句话需求”细化成可以用于指导开发的卡片。

让我们请出和 Hello World 处于同等地位的“练手三件套”之:Todo list。

原始需求

用户可以通过一个文本框,往 Todo list 里添加新条目。

界面设计图示意界面设计图示意

分析

拿到这个需求后,可能你脑海中已经有了一个大概的实现思路。并且由于你可能曾经用过类似的软件,所以已经模拟出了一整套的交互流程。

但请注意,到此刻为止,这些想法都只存在于你的脑海中,其他人无法窥见。你需要将你的理解传达给其他人,以便:

  • 确认你的想法符合产品经理(或需求负责人)的预期。
  • 让相关开发人员都清楚细节,从而可以进一步设计和细化这个功能的实现方式、技术选型等。

假设这个 Todo list 产品会将数据存储在服务器上,前端需要与后端交互,那么进行需求分析就需要从两个方面出发:界面交互和数据处理。

经过一番思考,你可能会继续问出下列问题:

  • 每个 Todo 条目是否有字数限制?如果有,当文本超出字数限制后如何处理?
  • Todo 条目是否有纯文本之外的内容,例如文字样式、图片、链接、视频等?
  • 用户没有输入任何内容时,提交数据会发生什么?
  • 文本框中尚未输入内容时,是否显示 placeholder 文字?如果有,内容是什么?
  • 提交数据时,是否需要阻塞用户对界面的操作?如果需要,阻塞哪一部分?
  • 前端的数据交互是否完全依赖于后端?还是说前端会有缓存/optimistic update/定期同步等机制,来降低界面响应速度、提高用户体验?
  • 后端接口需要传入哪些参数?如果某项数据没有提供,是报错还是提供默认值?如果是默认值,那每个可选参数的默认值是什么?
  • 如何保证用户输入的安全性?
  • 添加新条目后,后端是返回全部数据让前端做完整更新(常见于多个客户端可同时并发修改数据的情况),还是只返回刚添加的数据,由前端本地更新列表的渲染状态。

回答这些问题就是理清需求、确定后续开发计划的过程。一些技术决策也会逐渐浮现出来,例如后端的数据表设计、数据校验方式、前端可能要引入更复杂的状态管理,等等。

改进

整理、扩充之后的需求故事卡可能会变成像下面一样:

背景

在 Todo list 中,用户可以在文本框中输入内容并提交,从而新建一个 Todo item。

  • 内容提交并保存完毕前,不允许再次提交新内容。
  • Item 内容不得超过140字,并且只接受纯文本。

验收标准

  • 用户可以通过快捷键(Ctrl/Cmd + Enter)或“添加”按钮提交内容。
    • 当文本框为空时,“添加”按钮不可用,同时不处理提交快捷键。
    • 提交时,添加按钮显示 spinner 并禁止点击,同时不再处理提交快捷键。
  • 新 Item 提交成功后,通过下向上淡入滑动的动画出现在 Todo list 底部,从而给用户提供视觉提示。
    • 如果列表过长,新 Item 在可见范围之外,则滚动列表到底部,然后播放动画,确保动画可以被看见。
  • 文本框会随用户输入检测内容长度,若超出限制则将边框改为红色,并禁用提交交互。
  • 若提交失败,则在底部弹出 Toast 显示错误信息。
  • 后端必须对用户输入进行转义。转义方式为xxx。
  • 后端API若遇到提交信息为空信息或内容过长时,返回 400 错误和可读的错误信息。

根据这些验收标准,开发组可以将其中的每一项都拆分成一张独立的任务卡,并按需提供更多的技术细节(考虑到本文篇幅过长,这里就不再列举了)。

如果你发现上面写的一些验收标准和你之前的想法不一样,这是完全正常的。这恰恰说明了对于同一件事情,每个人都有自己的观察角度和理解方式,而卡片正是让各方统一意见的重要工具。

效果

如果能够像上面的例子一样,在建卡审卡的过程中反复确认细节,你会很快体验到下面的好处:

  • 开发组对项目复杂度有了更清晰的认识,对下一步的技术实现重点有了预判。
  • 项目经理可以根据这些任务卡,进行更细致的工时估算并安排人员。
  • 产品经理“被迫”对功能进行更深入的思考,从而可以让产品设计变得更“实际”,并建立合理的预期。