浅谈“排队”

上个星期在QCon北京分享了我们团队在翻译“User Story Applied”项目中的一些经验(Slide已经上传到SlideShare上)。其中主要应用了排队理论。我在演讲过程中做了一个调查,令我吃惊的是,听众中只有三个人听说过排队理论。由于排队理论是敏捷开发的一个重要理论基础,因此我觉得很有必要在这里介绍一下排队理论及其应用。

image

日常生活和工作中经常会见到排队,排队意味着等待,同时也就意味着系统中有一些关键资源,这些资源已经过载,也就意味着浪费,因此提高系统效率的十分有效的手段是减少系统中的排队现象,缩短关键资源面前的队列。而排队理论是解决排队现象的十分有效的工具。

排队理论最早应用于电信领域的交换网络,首先交换网络的实现为例来看一下排队理论的具体应用。

  • 信息并不是被整体传输,信息被分割成多个标准大小的信息包进行传输。
  • 信息不是按照一开始建立从端到端的信息链路传输。每个信息包都包含地址信息,独立传输。会根据一定的规则根据网络阻塞的状况动态调整路由。
  • 通过衡量端到端的延迟以及丢包率来衡量系统的性能和效率。
  • 如果某个路由发生阻塞,该路由会拒绝服务新的信息包,导致丢包现象。

排队理论十分有效地解决了交换网络中负载不均衡的问题,提高资源利用率,提高系统稳定性以及扩展性。其实我们在软件开发中也会遇到很多类似的问题。在项目组的关键资源或者关键路径上经常会有很长的任务队列,比如测试团队有很多的测试任务需要完成;项目组的核心开发成员必须要同时应付多个任务等等。与此同时也会有很多人无事可做,只能等待或者做一些优先级不高的任务。软件开发中的排队现象会导致很多问题,比如:过多的时间和资源投入没有得到回报;过长的队列会隐含的问题和系统缺陷;过长的队列导致软件团队对客户的需求变更不能够做出及时响应;过多的精力投入到项目管理资源调配上等等。敏捷开发十分优雅地把排队理论应用到软件开发中,在很大程度上解决这些问题。排队理论告诉我们,我们更应该关注任务的完成周期(Cycle Time)而不是每个资源的利用率,也就是从任务进入系统到最终完成的整个周期,而不是过度关注每个资源的利用率。也就是说我们的目标应该是让任务平均完成周期(Cycle Time)尽量缩短,周期越短系统效率越高。但是如何缩短完成周期呢?

说到排队理论不能不提到一个重要的公式是Little定律:

任务完成周期(Cycle Time)= (正在同时处理的任务数) / (平均任务完成率)。

从这个公式中很容易看出,任务完成周期与同时处理的任务量呈正比,与平均任务完成率呈反比。 也就是说,如果希望缩短任务的完成周期,可以从两个方向着手:

  1. 减少同时处理的任务数;
  2. 提高单个任务的完成率。

 

减少系统中的排队现象一般有有四种策略:

  1. 提高系统的能力

更高的系统能力意味着整个系统能够用更短的时间完成任务,也就意味着更短的完成周期。主要有几种方案,

  • 加人,让一些有经验的人员或者临时雇佣一些顾问加入团队,承担一些任务。但是对一般的软件团队来说,这个方法不可行。
  • 想办法提高团队中每个人的战斗力,比如使用更好的工具,更快的硬件,尽量避免对团队的干扰,更多的培训,引入敏捷教练等等;
  • 提倡的培养”通用的专才”(Generalized Specialist)。在项目中培养共享代码所有权的意识,鼓励每个人去学习不熟悉的技术、架构以及技术。这种方式可以十分有效地在组织内减少瓶颈资源现象。当然这不是意味着每个人都可以胡来,具体需要采取一定的措施保证质量和进度,比如结对编程、测试驱动开发、代码评审等等。
  • image
  • 控制资源的利用率,不要让资源过载,过高的资源利用率会导致系统效率的急剧下降。联想一下高速公路,如果是80%负荷以上的话,车速就会变得很慢很慢。对人也是一样的,如果过多的加班,过多的任务,工作效率和质量都会显著下降。所以在敏捷开发中首先强调尽力而为,按照让团队自己去承诺,同时鼓励预留一些缓冲(Slack)
  • image image

2. 控制需求

具体有四种方式:

  • 控制同时开发的任务数量(控制WIP是精益和看板中的一个核心原则)。因为并发的任务越少,可以集中力量尽快完成最重要的任务。同时项目团队的投入就越少,风险也最低;
  • 减少每个任务的内容,也就是控制每个任务的粒度和复杂度。过于复杂的任务容易产生很多不确定性,不确定性会对队列产生比较大的影响。
  • 拒绝新的任务,如果发现项目团队已经过载就不要再布置新的任务。敏捷中的“昨天的天气Yesterday’s Weather”,就是根据团队的速率来决定下一个迭代的任务量。如果发现不能完成当前迭代的任务,会把低优先级的任务砍掉或者缩减。
  • 缩减任务的范围,用户故事有一个特性是“Neogtiable”,其实就是指在团队可以和Product Owner沟通,调整用户故事的范围,从而改变任务的工作量。绝大多数团队会觉得这一点很不可思议的,但这其实是敏捷项目团队与传统项目团队最大的不同之处之一。但是与成本和时间以及质量相比,任务范围是敏捷软件开发中唯一可以做出调整的因子。(参见下图,项目铁三角)
  • 重用,重用一些设计,重用一些开源工具和框架。通过使用这些已经证明可行的工具或者设计能够大大减少项目需要投入的成本,减少风险,同时使得项目团队更加关注于核心功能的开发。
  • image

3. 减少变化性

过多变化会给项目开发带来很多不确定因素,前期的不确定性会对后期的进度产生巨大的影响而且随着变化性的增加,影响程度会呈现非线性的增长,形成蝴蝶效应。项目中的变化性主要体现为两种:

  • 任务到来的不确定性,也就是说任务需求的到来并不是均衡的,即有波峰也有波谷,波峰的时候超过系统的负载因此造成很长的队列,波谷的时候资源闲置,处于等待状态。
  • 任务处理时间的不确定性,也就是任务的规模或者难度差异很大,导致完成任务所需要花费的时间差异很大。

对于项目开发团队来说,减小变化性的有效策略是采用小粒度的任务,这跟在交换网络中把大的信息切割成小的标准大小。信息包小粒度的任务会使得任务的到来更加均衡,同时使得每个任务处理时间也变得同一。敏捷开发团队不再是把一个大模块做完之后一起扔给测试团队,而是每实现一个用户故事立刻交给测试团队测试,从宏观角度也实现了需求、开发与测试的并行开发,与此同时小粒度的任务也更容易缩小任务规模之间的差异性,从而减少任务处理时间上的不确定性。当然如果不可避免的需要有任务粒度的偏差,那就可以考虑把小粒度的任务提前,把大粒度的任务放到流程的最后处理

4. 使用控制系统

具体策略有两种:

  • 鼓励并行开发,很多敏捷团队都会采用ATDD(验收测试驱动开发),测试人员可以在任务的初期就与Product Owner设计一些具体实例,通过实例来澄清需求,把它变得更加具体,可执行。另外敏捷鼓励迭代式开发,其实也就是采取迭代Iterative的方式,不断通过反馈、试验来对软件进行不断对需求、功能做出调整。从宏观上也是一种并行开发。
  • 分析队列通常使用Cumulative Flow Diagram。正如Small Batch与Large Batch两个图所示,图中填充部分表示的是投入的所有工作量。如果使用较大规模粒度的任务,往往需要等待所有任务都来临之后才会有任务完成,而采用小粒度,从一开始就会不断有任务完成。因此将任务的规模变小,即使其他一切条件都保持不变,投入的工作量都会有很明显的减少。
  • image image image

 

Share

One comment

Comments are closed.