看板任务管理

作为一个开发团队的管理者,例如当你是一个团队的项目经理的时候,任务的完成情况通常是你最关心的内容之一,比如说分配的任务是否能够按时间完成,整个项目的进度是否尚在计划之中,团队内的人是不是都在高效地工作,大家有没有什么困难,这些是你经常会关注的问题。在软件开发团队中,任务的分配、跟踪和管理通常是这个团队管理者的一个重要的工作内容。

1 从问题谈起

我曾经碰到过一个项目经理,她管理着一个团队开发一个 web应用,团队里开发人员大概 10个左右,测试人员 3个,业务分析师 1个人。对于任务的管理她是这么做的。通常,她会将需求分析人员分析得到的需求给每个人分一些。然后每个人在领到任务之后会给她承诺一个大致的时间点。整个项目大致的交付计划用一个 excel表管理着,根据客户要求的交付时间点,并且考虑到一些需求之间的集成测试关系,定出了每个需求的大致交付时间点。只要每个开发人员承诺的时间点和期望的相差不大,她都可以接受,每个开发人员这样就知道自己应该在什么时间点交付什么东西。

一切本该很完美,但是不和谐的问题不断出现。最经常发生的事情就是大家在承诺的时间点快要到的时候不能按时交付,每次她询问进度的时候,会被告知还差一点就完成了。通常的说法是“底层部分已经做完了,或还差页面部分就可以搞定了”,然而实际情况是又过了相当的时间才真正完成。当然也不是没有按时交付的需求,但是她发现也许是大家经常加班,已经开始疲倦了,有时候明明很简单的可以提前完成的需求,大家还是到最后一刻才交付给测试。

也有的开发人员拿到自己的那一批需求之后,会批量工作,把若干个类似的需求的底层逻辑全部实现,然后再实现上层内容。她默认了这种做法,就像这位开发人员说的“这几个需求都差不多,只要底层做好了,基本上就都差不多完成了”。虽然这部分工作早点和其他人一起集成测试会比较好,但是他这样做也只能推后集成测试的时间点了。还好承诺给测试团队的交付时间点还在 1个月之后,只要 1个月之内能够完成这些需求就可以了。

还有一些其他的问题,比如有的新人经常碰到问题,然而出了问题并不会主动问其他人,而是在胡乱尝试中浪费了时间。组里还有个开发人员非常激进,经常花时间去重构代码,追求完美的架构设计,进度很让人担忧。组内的开发人员有时候还经常被其他项目的事情打扰,因为有几个人刚刚从上一个项目中调过来,上个项目的有些问题只有他们熟悉和有能力解决。她就不止一次发现,有一个开发人员经常在修复其他项目的 bug。

她会不定时地去询问每个开发人员的开发进度,当需求的计划交付时间点逼近的时候,这种检查会越来越频繁,开发人员感受到压力,有时候甚至需要加班来完成开发工作。然而尽管她花了很多精力去跟踪和检查每个需求的完成情况,还是有很多出乎期望的事情在不断发生。尽管她一直相信说,只要开发人员们能够完成任务,采用什么方式她是不干预的,而具体的时间也是由他们自己分配的。但是她渐渐感觉到,任务越来越不可控,计划通常无法按时完成,每天对大家的检查花了大部分时间,然而却不能揭示出真正的问题。

运转良好的项目都差不多,而问题项目的问题各有各的不同。尽管每个团队的问题可能不完全相同,但是当我们审视这些项目的运作和管理方式的时候,不难发现一些诸如多任务并行等共性的问题,这些问题给软件项目带来了各种各样的浪费。当一个团队采用瀑布开发模式的时候,开发阶段全部结束之后测试人员才会介入,开展测试活动,在一个通常很漫长的开发阶段内,各种开发活动中的浪费、估计的不准确,以及成员自己的拖沓、被打扰、问题阻塞等,都被掩盖住了。只要在最终时间点前能够全部开发完成,不管是前松后紧,还是加班熬夜,都已经成了项目开发的常态。项目经理只能看到交付的最终时间点,问题不能及时的暴露,而等到问题被暴露的时候,可以使用的调整手段也非常有限。

这样的一种团队生存状态在外部环境要求短交付周期,需求允许经常变化的情况下显示出了极度地不适应。市场环境的变化驱动了软件需求的变化,这种变化催生了缩短交付周期的诉求,较短的交付周期使得人们可以不必去预期过于长远的需求,具备根据市场的变化快速地制定和调整软件需求的能力。而当交付模型由几个月的瀑布模型转变为数周甚至更短的迭代模型的时候,我们在前面谈到的团队中的各种浪费、低效、半成品堆积等问题,就会急剧地爆发出来。

熟悉敏捷方法的读者可能都知道,敏捷方法包含一系列实践来帮助团队实现短周期快速交付,更好地响应需求变化。比如说 user story方法,将需求从用户价值的角度进行组织,避免将需求从功能模块角度划分。小粒度的用户故事可以在一两周的迭代内完成开发和测试(并行开发),从而可以缩短交付周期。问题是,在敏捷团队内,我们是如何有效管理大量小粒度 user story,同时避免上述项目管理中的问题呢?下面我们结合敏捷开发中的看板工具来看看敏捷团队是如何管理任务的。

2 可视化看板任务管理

看板源于精益生产实践,敏捷将其背后的可视化管理理念借鉴过来,经过一番改造,形成了有自己独特风格的可视化管理工具。曾有人总结过 scrum和 kanban的使用 [1] ,而很多时候,我们也将它叫做迭代状态墙。

先看看我们怎么样能用这个状态墙来管理迭代任务。说起来其实是一个很简单的东西。

通常一个迭代的状态墙上反映了某一个迭代的计划和任务进展情况。状态墙上按照一个迭代内团队的典型开发活动分成几栏,例如“待开发”、“开发中”、“待测试”、“测试中”、“测试完成”等。在一个迭代之初,我们会将计划在本迭代完成的故事卡放到“待开发”这一栏中。可视化状态墙的一个好处就是所有团队成员都可以实时地了解到本迭代的计划和进展情况。开发人员领取任务时,就将他领取的故事卡片从“待开发”移到“开发中”,同时贴上带有自己名字的小纸条。当他开发完成之后,就将故事卡片移到“待测试”一栏。我们的测试人员看到这一栏里有待测的故事卡时,就取下一张,移动到“测试中”,开始这个用户故事的测试,测试完成后,就将故事卡移动到“测试完成”一栏。如果测试人员发现了一个 bug,那么他可以用红颜色的卡片记下这个 bug,然后放到待开发这一栏中。在状态墙上,除了用户故事、 bug之外,还会有一些诸如重构、搭建测试环境这样的不直接产生业务价值的任务,这三类任务用不同颜色的卡片,放到状态墙上统一管理。

这样一个简单的工具,是如何帮助我们消除浪费、解决项目管理中的问题的?让我们逐条分析一下看看。

2.1 如何减少返工带来的浪费

返工是软件开发过程中的一大严重浪费。比如说开发人员开发完成的任务交给测试人员测试的时候,关键流程不能走通,阻碍了测试进程;交付给客户的东西被客户说 “这不是我想要的东西 ”;分析人员将还没分析透彻的任务交给开发人员,在最后验收的时候发现开发人员加入了自己的一些 “发挥 ”。这些都会造成返工。返工意味着没有一次性将事情做对,意味着流程中的上游没有交付高质量的工作,也可能意味着团队成员间的沟通出了问题。

在传统的瀑布流程中,我们往往是期望通过前期细致入微的工作来确保一个阶段的工作被高质量完成之后才移交到下一阶段。后来我们慢慢从失败的经验中学习到,这种方法在变化的需求环境下实在是太过脆弱,不仅不能如愿保证质量,而且会造成更大的浪费,交付周期也不能满足要求。于是我们引入了迭代式开发方法 [2] ,一个需求的分析、开发、测试、验收成了一个小粒度地更连续的过程,在这个小的交付循环中,看板帮助我们以更细节的粒度来管理一个任务每个阶段的工作质量。

通常我们是这么做的。当我们把一张故事卡从“待开发”移动到“开发中”时,这张卡片必须是已经分析完成的。也就是说,当开发人员准备真正开始开发这张故事卡之前,我们的需求分析师们必须保证这张卡片所包含的所有内容和细节已经被分析完成,不再有模棱两可的细节,不再留给开发人员过多的自我发挥和想象空间,而且这些细节必须和客户确认过,而不只是团队自己“设计”的结果。

这一道关看似很寻常,实际上很多项目会在这里出问题。很多时候开发人员开始开发的时候,需求还没有分析完成,很多细节尚须澄清确认,实现上的技术风险还没有被完全排除。也有的分析师善于给开发人员留有大量自我发挥空间,需求过于言简意赅。开发人员开始开发这样的需求时,要么做不下去,要么按照自己的理解做下去。做完了之后分析师一看发现不对,和我想的不一样,于是开发人员返工。最糟糕的情形莫过于最后被客户发现说,这不是我当初想要的东西。

由此可见,确保开发人员挪卡的时候,这张待开发的用户故事已经被真正分析完成,是我们准确实现用户需求的第一步。通过规定这一挪卡的前提,同时辅以用户故事的澄清(由分析师向开发人员澄清)或者反向澄清(由开发人员向分析师讲述自己的理解),可以很大程度上将返工减少到最低。

还有一种浪费发生在测试过程中。测试人员经常会发现,处于“待测试”状态中的一些故事卡,在测试的时候主要的流程都走不通,根本无法进一步展开测试,于是乎不得不将故事卡

打回到开发人员手中。而往往这个时候开发人员已经工作在另一个用户故事上了。要么他停下手中的任务解决测试的问题,要么让测试人员等到这些问题修复过后再测。无论哪种都是不好的选择。

这种问题的一个主要原因是因为开发人员声称他已经“开发完成”,将故事卡从“开发中”挪到“待测试”时,实际上自己并没有对这部分功能进行测试。或者是因为疏忽,或者是因为懒惰,或者是因为过于自信。通过在这个状态转换阶段引入用户故事初验,让分析师在挪卡之前先到开发人员机器上看看是否该故事卡包含的功能被实现了,可以很大程度上提升效率,减少浪费。若分析师在初验过程中发现了问题,那么开发人员马上能以最小的成本进行修复,而不用等到之后测试人员发现时再来修复。而且,分析师初验也提供了一个判断实现是否良好的反馈点,这是我们能够看到一个需求是否被实现并能够真正工作的最早的时间点。

2.2 如何避免多任务并行

多任务之间的频繁切换是一个常见的问题。表现在团队里的成员,特别是开发人员,会在不同的任务间切换。就像前面的故事中提到的,可能这一刻还在实现某一个需求,而下一刻马上就会被叫走去修复某一个遗留版本的缺陷。又或者该人手头被分配了多个任务,每个任务都在进行中,而没有一个处于完成状态。任务切换是导致效率降低的一个重要原因 [3] ,不同任务间的上下文的切换会导致频繁地将任务当前状态在头脑中“压栈”和“出栈”,这些操作会耗费时间。如果完成一个任务需要一个人一天时间,那么两天内这个人可以完成两个任务,但是如果他在第一天同时开始并行工作在这两个任务上,那么完成这两个任务会需要大于两天的时间。

大家可能已经注意到了,在前面的看板图中,处于“开发中”的所有任务卡片上都有一个小纸条,上面标记着正在这张卡片上工作的人的名字。如果说有两个人结对在一个卡片上工作,那么这张卡片上应该有两个名字。这一小小的实践可以帮助我们随时发现团队内某一时刻,是否每个人只工作在一个任务上。

如果这一简单的规则能够严格被遵循,那么当我们看到一个人的名字出现在多张卡片上的时候,我们就知道这个人此刻可能忙着在多个任务之间切换,而每一个任务都将不会在估计的时间点内完成。如果我们看到有人的名字没有出现在任何卡片上,那么他目前大概处于休息状态。团队内的每个人的名字都应该对应在一个小纸条上,如果你此刻工作在某个任务上,那么就将自己的名字贴到相应卡片上,如果此刻没有工作在该任务上,就将自己的名字移去。

我们在领取“待开发”状态栏中的卡片时,保证每次每人只领一张卡片,不要多领,完成了这张卡片之后,再回来领下一张。当一张卡片被认领之后,我们就会对这张卡片进行跟踪,在站会上谈论它的完成情况,谈论实现过程中碰到的问题。当它的进度和估计的可能偏差较大时,我们能够及时而不是在最后一刻察觉到,提供需要的帮助,确保它能够顺利完成。这样一种方式让我们能够将注意力集中到小粒度的需求(例如用户故事)上,更多地关注这些用户故事的流动速度。而当每个小的用户故事能够顺畅地流动起来时,整个项目的交付也得到了保障。

当然这一实践并不能自动保证团队内不再出现多任务并发、拖延、或者做和任务无关的其他事情等问题。可能有些人在做一个用户故事的过程中,突然中断去做了一些其他事情,但是

却没有及时在状态墙上更新自己的状态。重要的是团队要有实现交付目标的共同愿景,能够透明地暴露问题,并且善于利用状态墙来发现和改进自身的问题。对于不成熟的团队,这可能需要一个转变的周期。

如果一个团队的职责共享较好,代码被所有人集体拥有,每个人都被鼓励熟悉和工作在代码的不同部分,那么在这样的团队内便不太会出现把一大块任务事先就明确给某一个人的情况。相反,所有人的工作事先不具体确定,大家会更容易形成某一时刻只领取一张卡片的情况,避免同时工作在多个任务上。实际上,状态墙的使用也可以帮助团队走向职责共享之路,只需要在大家领取任务的时候有意地给人们分配一些之前没做过的内容,同时安排好有经验的人与其结对工作,一段时间之后,团队内的人便会逐渐体会到和之前只是专注在一个模块内不同的工作方式。

2.3 如何减少半成品库存,缩短交付周期

一个需求的交付周期 (lead time [4] )是从它被识别到最终交付给用户手中所耗费的时间。交付周期越短,意味着客户从提出想法到能够在软件中实际使用到这个点子的时间越短。从客户的角度来看,更短的交付周期意味着自己的软件能够对市场变化的更快地响应,因而获得更强的竞争力,同时也意味着能够更快地验证自己的想法。

任务管理的粒度太大会直接导致交付周期变长。最极端的情况是将属于某一模块的任务在一开始就全部分给负责这个模块的人,所有这个模块相关的修改都由他来实现。在一个按模块划分职责,每个人只负责自己具体模块的团队里,通常这个模块的负责人会实现这个模块的所有修改。不然,就是将一个可能需要做 2周到一个月的任务分给某个人。或者更好一点的情况是,单个任务本身不大,但是会将相关联的任务成批地分配给某个人。如果你的团队内也是采用大篇的“规格说明书”等 word文档来组织需求的,那么就要小心,这种问题很可能在团队内已经存在。整个团队没有小粒度频繁交付的概念,习惯了大批量长时间地交付方式。由于批量大,所以估计常常不准,而且时间跨度长,中间也会有更多地干扰因素出现,这些都导致任务不能在开始承诺的时间点交付。开发周期长同样导致测试活动的滞后,极端地滞后就演变为所有开发工作完成之后才能进行测试,这就是我们熟悉的瀑布模式。最终的影响就是需求的交付周期会很长。

传统团队的一个常见组织方式是按照功能模块划分团队成员,明确分离职责,这也会变相增长交付周期。这样的团队通常倾向于按照功能模块来组织半成品任务,而不是按照可以交付价值的完成品来组织任务。习惯按照功能模块来组织开发的团队通常会阶段性得“联调”,不同模块的人带着自己的代码合在一起调试,由于缺乏频繁地集成,这种联调活动的时间经常不可控。团队在大部分时间内通常只拥有一大堆半成品,后续的测试和验收活动没有办法进行,而只能等到团队在某一刻组装出一个完整的功能后才能测试,因此交付周期也会比较长。

因此,如果我们的需求都是按照软件的功能模块划分,而不是按照面向用户的价值来划分的,那么我们在交付用户价值这一目标上,一开始就走错了路。采用用户故事能够把需求以用户能够理解的价值来组织,这一点是我们缩短交付周期的一个重要基础。

我们的状态墙能够揭示需求的交付周期。让我们来看看这样几个场景。

如果我们的需求是按照软件的功能模块划分的,那么通常单个模块的编码完成往往不可测。例如有的团队喜欢将 web应用的上层页面部分和下层数据库逻辑部分划分到不同的模块组,一个用户的需求也会拦腰切成两截,一部分交给上层团队完成,一部分交给下层团队。单个团队的任务完成都不能开展这个需求的测试,于是这些任务就会堆积在“待测试”这一栏。

如果我们的需求很大,以至于开发人员要花费很长的时间(超过 1周)才能完成开发,那么这个需求会在“开发中”这一栏停留很久。大家可以猜到,当一个人同时进行多个任务时,这些任务也会比它们单个依次被开发时在“开发中”这一栏停留更久的时间。

任何一栏中的任务其实都是半成品,只有完成测试,交付到用户手中的需求才是完成品。状态墙上的每一栏都好比一个存放着各种零件的仓库,每一栏中的卡片越多,停留的越久,就说明当前半成品的库存越多,是该得到团队的认真关注的时候了。状态墙将每个阶段的半成品数量可视化呈现出来,让虚拟的数量通过卡片这种物理介质的数量得以呈现。

通过状态墙,我们可以计算出每一个需求的交付周期大概是多久。状态墙上一个用户故事从放到“待开发”这一栏,到它被移动到“完成”这一栏,这一个时间段是需求的整个交付周期的其中一段,也是很重要的一段。通过优化从“待开发”到“完成”的这一个过程,我们可以缩短需求的交付周期。通过比较需求的交付周期和客户对交付周期的要求,我们可以量化之间的差距,然后指导我们的改进。

在我们理解了状态墙是如何呈现一个需求的交付周期后,我们就不难理解瀑布方法是如何让交付周期变长的。在瀑布模型中,全部开发完成之后才会进行测试工作,相当于所有的任务卡片都堆积到“待测试”状态之后,才开始逐一测试。所有开发完成的半成品,都会留存在“待测试”这一仓库中,一直等到所有开发活动结束的那一刻。

当出现库存堆积的时候,就是我们需要改进的时候。如果“待测试”这一栏有太多的任务卡片,那么就说明我们的测试活动没有跟上。有可能是我们的测试环境出了问题,或者是我们的测试人员人力不足。如果太多的卡片位于“测试完成”状态,说明我们的发布和最终交付过程出了某些问题。如果“待开发”这一栏中任务过多,说明我们的计划有可能超出了当前团队的开发能力,或者说反映了开发人员的不足。也有一种情况,那就是“待开发”这一栏空了很久,这可能说明了另外一个问题,那就是我们的分析师的分析速度匹配不上团队的开发能力。一个良好的团队,必然是各种角色协调配合,并行工作,同时他们之间的任务衔接也能够比较流畅。

2.4 迭代产能的度量,计划及其他

团队在每个迭代所能完成的工作量,通常被成为迭代的 velocity(速度),是衡量团队每迭代产能的一个指标。这个指标能够帮助团队进行制定迭代计划。根据团队估计任务工作量的方法不同,迭代的 velocity的单位也可能不同(例如故事点数)。通常,我们只需要在迭代结束的时候,数一数状态墙上完成的任务工作量就可以了。

当我们经历了若干个迭代以后,通常团队的迭代速度会趋于稳定,我们在做下一个迭代的计划的时候,会参考以往迭代的数据。如果上个迭代完成了 15个点,那么下个迭代我们通常也

会计划 15个点左右的工作量,将这些卡片放到“待开发”这一栏中。也就是说,每个迭代结束时,我们都会对状态墙进行更新,将即将到来的迭代的卡片放到墙上,并且将一些处于半成品状态的卡片进行适当的调整。

前面提到,状态墙上可能由三种卡片,除了需求,还可能有 bug和技术任务。测试人员每次在迭代中测出一个 bug,就会将 bug写成卡片,放到“待开发”这一栏。当 bug不多的时候,团队可以在不太影响原有计划的情况消化掉这些 bug,确保软件的质量持续地得到保证。如果 bug太多,则需要做一些计划,将 bug分散到几个迭代里去消化。然而到这个时候,团队可能更需要及时反省一下为什么会出现这么多 bug的原因了。

另一类技术任务也需要和 bug以及需求卡片一起被考虑到迭代计划中去。通常技术任务包括诸如搭建持续集成环境、准备测试环境、重构这样的任务。它们虽然不直接给用户带来价值,但是却是保证软件质量、确保团队效率的重要因素。比如重构类的任务,对于工作在遗留系统上的团队来说可能是需要一直考虑的事情,为了保障新的需求的顺利实现,可能需要有计划地重构之前的一些遗留代码。

bug和技术任务耗费团队成员的时间资源,但是不直接产生用户价值。如果我们衡量团队每个迭代的总体生产能力,需要在计算迭代速度时考虑这三类任务。但是如果我们只考察团队每迭代交付的用户价值的量的大小,那么就不应该包含技术任务和 bug。当一个团队在迭代中花了过多的时间在技术任务上,或者修复 bug上,那么团队就需要回顾反省一下其中的原因,是否是团队的基础设施太差,或者是团队在开发时过于粗心导致太多的 bug,抑或是其他的一些原因。

3 总结

在本文中我们从项目管理中常常出现的一些问题着手,分析了其中的一些原因,然后介绍了如何采用状态墙(看板)来可视化任务管理。在敏捷项目中,状态墙作为一种有效的迭代任务管理工具,已经被广泛地使用。团队利用状态墙这样一种简单的工具,将迭代开发中的日常工作透明实时地跟踪管理起来,能够帮助团队及时发现问题,消除浪费,快速地交付用户价值。希望这些文字,能够对渴望尝试敏捷、改善任务管理和日常运作的团队带来一些帮助。


[1] http://www.infoq.com/minibooks/kanban-scrum-minibook

[2] http://en.wikipedia.org/wiki/Iterative and incremental development

[3] 参见 Lean Software Development: An Agile Toolkit by Mary Poppendieck, Tom Poppendieck第一章

[4] http://en.wikipedia.org/wiki/Lead time

Share

Tech Lead的三重人格

很多团队都有tech lead这个角色的存在,但同时很多团队对这个角色都缺乏明确的定义。大多数时候,团队只是指派其中经验最丰富、技术最精熟的开发者来担当tech lead。但除了“tech”的成分之外,这个角色还有“lead”的成分,这就决定了他不仅需要技术上的能力,还要眼观六路耳听八方,才能带领团队──至少是开发者们──取得成功。

Tech lead需要关注的事情可谓纷繁芜杂。把这些事情分门别类,我们可以看到,这个角色大致有三方面的职责:技术决策者、流程监督人、干扰过滤器。

技术决策者

从技术的角度,tech lead需要关注以下三个方面:架构设计、局部设计和关键技术点。

参与架构设计

系统的架构通常是在项目初期的quickstart阶段设计出来的。这个架构设计包含的都是高层面的内容,例如C/S或B/S的选择、开发平台、编程语言、数据迁移策略、集成点、部署结构等。

尽管架构师(architect)是架构设计的主要负责人,tech lead还是会参与设计过程,以获得对系统全局的清晰了解,并且尽早发现架构设计中不合理或者风险较高的部分。

主要关注点:

  • 选择什么平台和编程语言?
  • 需要和什么系统集成?需要使用哪些第三方软件或工具?
    给自己画一张集成架构图:先用虚线圈出为用户提供服务所需的整个系统范围,再用实线圈出将用主要编程工具(例如J2EE或者Ruby on Rails)开发的应用程序,两者之间的其他东西就是你需要集成的目标。找出集成点和集成方式。留住这张图并保持更新,你会经常用到它。
  • 如何部署?如何迁移现有数据?
    开发团队日常部署到什么环境?UAT(用户验收测试)和性能测试的环境由谁部署?生产环境由谁部署?部署的频度如何?开发和测试使用的数据集从何而来?数据迁移是部署过程的一部分吗?除了自动化部署脚本之外还需要什么额外的环节吗?
  • 团队的技能是否与项目需求匹配?

攻克技术难题

作为“tech”lead,解决技术上的难题、为团队扫清前进道路,自然是题中应有之义。由于具备对系统全局架构的了解,tech lead能够识别出项目中可能遇到的技术挑战,及时进行研究和实验,尽力使其不对开发工作造成阻碍。

主要关注点:

  • 集成点是否得到妥善处理?
    能成功集成吗?用于集成测试的环境到位了吗?出错的情况妥善处理了吗?
  • 如果技术栈中的某一部分出现问题怎么办?
    项目中用到的第三方组件有谁熟悉?如果是开源软件,相关的社群在哪里?如果是闭源软件,我们能得到其生产厂商的技术支持吗?

确定设计方案

敏捷项目中,大部分设计都是在项目过程中做出的,其中有些设计会对系统整体产生较大的影响,有时甚至会改变起初的架构设计。所以贯穿整个项目,tech lead需要保持对系统整体和细部的把握,选择适当的设计方案,或是通过重构让好的设计浮现出来。

主要关注点:

  • 代码中是否出现明显的bad smell?
    是否看到明显的大类、长方法或者重复代码?条件逻辑嵌套太深了吗?本应属于模型的逻辑在视图或者控制器里堆积了吗?是否应该考虑做一做对象健身操?(参见《ThoughtWorks文集》,第6章)
  • 局部设计是否会对系统造成明显的损害?
    这个设计会严重损害性能吗?它是一个安全漏洞吗?它是难以测试的吗?它损害了系统遵循的概念一致性吗?
  • 团队是否正在进行关于设计和重构的讨论?

要在局部设计上具备发言权,tech lead就不能脱离开发工作──不写代码的人是无权评价代码的。在讨论细部设计时,tech lead需要把握一个微妙的平衡:既不要过于民主而耗费太多时间,也不要过于集中而使团队成员失去学习和思考的机会。一个好的实践是:每天早上把所有开发者召集起来,用15~20分钟浏览前一天编写的所有代码,这样每个人都有机会在看到bad smell时指出。

流程监督人

为了保障开发工作顺畅进行,tech lead需要从以下三方面入手来保持对开发流程的关注:开发环境、持续集成和测试。

开发环境

Tech lead需要保障良好的开发实践得到贯彻,尤其是当团队中有较多缺乏经验的成员时这一点就更显重要。一家公司内部很可能有一些成熟的开发套路,这也使得每个tech lead的责任更重大:如果团队成员在一个项目中没有养成好习惯,受损害的不仅是这一个项目,还有整个公司的习惯套路。

主要关注点:

  • 如何使开发团队拥有统一的环境?
    IDE的设置和快捷键如何同步?shell设置和别名如何同步?数据库设置如何保持一致?需要将开发环境虚拟化吗?
  • 如何实现一段代码并提交?
    开发者从哪里获取验收条件?编写代码时应该遵循哪些惯例?功能完成之后是否需要邀请BA/QA快速确认?提交代码之前应该如何进行本地构建和测试?提交时的注释格式有什么要求?
    ThoughtWorks的很多Ruby on Rails项目都采用“rake commit”这个任务来提交代码。这个任务会从svn服务器更新代码、执行本地构建、运行测试、要求开发者输入符合格式的注释内容、然后提交修改内容。我们通常还会给这个命令指定一个shell别名“rc”,这样我们只需要敲三下键盘就可以开始一次标准的提交。
  • 如何结对编程?
    哪些任务需要结对?哪些任务可以不必结对?结对的轮换合理吗?是否有谁在某一个任务上做了太长时间?是否有谁对某一部分完全不了解?结对过程中大家都全心投入了吗?是否需要用特别的结对方法来引导经验较少的团队成员?需要开发者和QA结对吗?
    Tech lead同样需要与团队成员结对,有时是为了理解某一部分的实现,有时是为了指导和帮助队友。Tech lead应该始终牢记自己是开发团队的一份子,每天都应该尽量安排出时间参与结对;同时其他开发者也应该谅解tech lead还有其他职责,不要因此拒绝和他结对。

持续集成

每个人都需要对持续集成负责,有一个人需要负更多的责,这个人就是tech lead:他要清楚持续集成中每个阶段的用意,当集成失败时他要知道这意味着什么。关于持续集成的设计,我强烈推荐Dave Farley的文章“一键发布”(《ThoughtWorks》文集,第12章)。

主要关注点:

  • 持续集成环境和生产环境有多大差异?
  • 持续集成覆盖哪些阶段?
    项目各方的关注点在持续集成中都有体现吗?性能测试被覆盖到了吗?打包部署呢?拿到持续集成产出的安装包,我们一定有信心将它部署到生产环境吗?
  • 持续集成给开发团队快速而有用的反馈了吗?
    经常失败的是哪些阶段?随机失败的概率大吗?随机失败会掩盖真正的问题吗?从提交代码到走完所有集成阶段通常需要多长时间?需要使用更大规模的并行集成吗?(例如引入更多的Cruise Agent。)

测试

测试就是开发者要满足的目标。没有良好的测试,就等于没有良好的目标。作为tech lead,要关注不仅是单元测试,还包括功能测试和各种非功能性需求的测试;不仅是开发者编写的测试,还包括QA乃至客户的测试。当然,从技术的角度出发,tech lead更关注的还是自动化的测试。

主要关注点:

  • 团队如何实施TDD?
    测试的粒度和层面合理吗?是否有适当的系统测试?是否有滥用系统测试取代单元测试的倾向?修复bug时先用测试来描述bug了吗?集成点都有测试覆盖吗?数据迁移都有测试覆盖吗?
  • 功能测试/验收测试的质量和进度如何?
    QA和开发者如何借助功能测试沟通?如果功能测试由QA编写,能赶上开发的进度吗?测试代码的质量如何?如果由开发者编写,测试覆盖到所有验收条件了吗?QA能否理解和维护测试代码?是否需要安排QA和开发者结对编写功能测试?
  • 性能测试得到足够关注了吗?
    有清晰的性能需求吗?有性能测试描述这些需求吗?如何得到性能测试的结果?
    我的同事James Bull在“实用主义的性能测试”(《ThoughtWorks文集》,第14章)一文中对性能测试的做法有精彩的论述,此处不再赘述。

干扰过滤器

在大部分软件项目中,开发者的工作──细部设计和编程实现──都位于关键路径上:它们未必是最有价值的工作(尽管我个人坚持这样认为),但它们一定是最耗时间的工作。换句话说,开发者的时间是否充分用于开发,将决定项目能否按时交付。所以,tech lead的很大一部分责任就是过滤各种干扰,使开发者们全神贯注地编程。尽管项目经理和BA也起到这样的作用,但还是有很多编程之外的事需要“技术人员”来做。

与客户技术团队沟通

大多数定制开发项目都会涉及到客户方的技术团队:开发、测试、DBA、运维、支持,等等。光把系统做好还不够,你还得把做好的系统交到他们手上,项目才真算完成──“交到他们手上”这件事就得由tech lead来负责。

主要关注点:

  • 如何与客户的开发团队交换知识?
    有哪些惯例需要遵循?有哪些既有的工具可以利用?如果双方开发者同时开发,如何协作?如何结对编程?如果只需要在开发结束后移交产品,如何做知识传递?如何确保对方保持关注?如果双方不在同一地点,是否需要安排定期的电话会议或视频会议?
  • 如何与客户的支持团队协作?
    生产或UAT环境的服务器由谁管理?如何交付部署包?客户的测试人员如何进行测试?测试结果如何获取?
    运维团队在软件项目中常常被忽视,但他们对产品的成功上线至关重要。通过搭建和维护UAT/性能测试环境,可以尽早地让运维团队参与到项目之中,并且了解部署和日常管理的相关信息,从而使最终的上线变得相对容易。
  • 如何与客户的DBA协作?
    数据库迁移计划经过DBA复审了吗?DBA是否能获得系统运行时的数据库访问日志?如何与DBA讨论解决数据库相关的问题?
    一个好的实践是在每次部署到UAT环境之前将近期的数据库改变总结出来告知DBA,并请他持续关注UAT环境被使用时的数据库日志。如果DBA指出一些明显性能低下或者有其他问题的SQL,应该重视他的意见。

与BA/QA协作

团队内部的“干扰源”主要是BA和QA。BA和QA往往缺乏技术背景,如果他们经常用一些“愚蠢”的问题去打断开发者的工作,开发者们可能会觉得他们添乱多过帮忙。这时tech lead就得表现出更多的耐心,先过滤掉那些没有营养的问题,从而让开发者们觉得与BA/QA的沟通是有帮助的。

主要关注点:

  • Story的内容和工作量估计合理吗?
    Story涉及的功能实现起来有多困难?是否有更简单的方式来实现同样的目标?相关的风险大吗?
    理论上,工作量估算是由开发者来做的。但有两种原因使得tech lead需要代表开发者来做这件事:(1)找开发者做估算可能打断他们的工作节奏;(2)项目初期可能其他开发者不了解情况,甚至还没有加入项目。同样,如何尽量让所有开发者都感到自己的意见得到尊重,又不过多占用他们的时间,这也是需要平衡的。而代表开发者做估算的准确度也将直接影响tech lead在他们心里的地位。
  • QA的工作需要帮助吗?
    QA发现bug时会如何处理?他发现的bug经常是“误报”吗?需要帮助他编写自动化测试吗?需要帮助他做性能测试吗?

打杂

其他所有需要由“技术人员”来做的事,tech lead都应该有自己一肩挑的准备──例如查一下数据库里有哪些不符合业务规则的数据,生成一份CSV文件,小小改动一下界面,甚至倾听一下客户和项目经理的抱怨再给他们一点“技术性”的安慰,等等。

但这不表示你就总是应该把这些事一肩挑。Tech lead这个角色的微妙之处就在于:他仍然是“技术人员”,和所有的开发者一样。换句话说,tech lead能做的事,其他开发者也应该能做。所以,再一次地,你应该有一个平衡:把一部分杂事自己消化掉,不让它们干扰开发者的正常工作;另一部分杂事则分配给开发者去做,让他们感到自己除了编程之外还参与了项目的其他方面,同时也给自己挤出一点时间做其他更重要的事。

小结

在我所经历过的大部分项目里,tech lead都是个超级忙的家伙──看这篇文章就不难理解为什么。人们期望tech lead做的事很多,而且在项目的各个阶段还有所不同,一个人要肩负这样的期望确实不容易。

不过只要意识到“tech lead”只是一顶很多开发者都可以戴的帽子,随着项目的进展,你就可以慢慢地把更多的责任放在整个团队的肩上──只要不至于造成损害,于是自己也有了更多的时间来编程。最终你可能会得到一支这样的团队:其中每个开发者相当平均地扮演一部分tech lead的角色,各种任务随优先级被有效地处理。这时你就可以说,这个项目的tech lead确实做好了他的工作。

本文转自InfoQ: http://www.infoq.com/cn/articles/thoughtworks-practice-part8

Share

估算的目的

我第一次与敏捷软件开发的邂逅,是在极限编程刚刚兴起时,源自跟Kent Beck一起工作的经历。其中让我印象深刻的事情之一,就是我们做计划的方式。这里面包括一种估算方式,比起我之前见到过的其他方法,它既轻量,还更有效。这样过了十年,现在一些有经验的敏捷实践者,开始了一场关于估算是否值得甚至是否有害的争论。我想,为了回答这个问题,我们必须审视一下估算的目的。

通常的场景是这样的:

  • 开发者被要求给出对于即将开始的工作的估算。人们大多是乐观派,在没有压力的情况下(一般至少也会有点压力),这些估算通常会比较小。
  • 这些任务和估算会被转化成发布计划,然后用燃尽图跟踪。
  • 接着,人们就会按照这些计划,持续监控着团队为完成任务所投入的时间和资源。当实际消耗的时间和资源,超过当初的估算时,每个人都会变得失望。为了迎合当初的估算, 开发者被要求牺牲软件的质量,但这只会让事情变得更糟。

这种情形下,对估算的投入充其量就是一种浪费——因为“估算就是在干净的衬衫上猜测”。只有当估算被当做追逐更多特性的手段时,它才会变成实质上有害的行为。过分追逐特性是一种很糟糕的情形,人们只是始热衷于完成一个又一个特性,而不是追踪项目的真实结果。

估算还会设定期望值,既然估算通常会偏低,所以它们设定的期望值也多是不切实际的。任何时间上的增长,或者软件特性被砍掉,都会被视作是失败。出于对风险的逃避,这些失败的后果往往会被放大。

面对类似这样的情况,我们就很容易看到人们把愤怒对准了估算本身。这样也导致越来越多的人认为,任何沉迷于估算的人并不是真正的敏捷实践者。而批评敏捷的人则说,这意味着敏捷软件开发的本质就是,开发者很快动手开始做,却并不明确要做什么,而且承诺说,该做完的时候肯定会做完它,而且你肯定会喜欢它。

我并不同意估算是天生有害的活动。如果有人问我,估算是不是件糟糕的事情,我的答案会是一名标准咨询师的答案:“不一定”。而接下来的问题就会是“取决于什么”。为了回答这个问题,我们就不得不问,我们为什么要估算——因为我想说:“如果事情值得做好,就值得问清楚,我们到底为什么要做它”。

对于我来说,当你面临重大的决策时,估算就是有价值的。

我的第一个得益于估算决策的例子是:资源的分配。一般来说,组织大多拥有固定数目的钱和人,而且通常有太多值得做的事情。因此人们就面临选择:我们是做A还是B?面对这样的问题,了解A和B分别要涉及多少投入(以及成本)是有必要的。为了做出一个明智的决策,你需要有对成本和收益有个大致的了解。

另外一个例子是估算对协调的帮助。蓝色团队想在他们的网站上发布一个新的特性,但直到绿色团队创建新的服务提供给他们关键数据后才能发布。如果绿色团队估算他们会在两个月后才能完成新的服务,而蓝色团队估算需要一个月去能完成新的特性,那么蓝色团队就知道不值得现在就开始实现这个新特性。他们可以花费至少一个月时间,工作在其他可以早点发布的特性上。

所以任何时候当你想做估算时,你应当非常清楚哪一项决策需要依赖这个估算。如果你找不到这样一项决策,或者那个决策并不是那么重要,这就是一个信号:此时做估算是在浪费时间。当你找到这样一个决策时,那要知道问题的上下文是什么,为什么估算会很重要。同样还要搞清楚期望的精度和准确性。

同时也要明白,有时候为了做决策,可能会是其他替代的方案,而未必需要估算。也许任务A比起B要重要得多,以至于你都不需要一开始把你所有的空闲精力都放在B上。也许有办法让蓝色团队和绿色团队合作,更快地创建出服务来。

类似地,跟踪计划也应该由它如何影响决策来驱动。通常我的意见是,计划扮演的是基线角色,帮助评估变化——如果我们想要添加一个新的特性,我们应该如何把它放进既定的“五磅篮”里呢?估算可以帮我们理解这些取舍,并因此决定如何响应变化。在更大范围下,重新评估整个发布计划,可以帮助我们理解整个项目是否仍然充分有效利用了我们的能力。几年前,我们曾经有一个规模达一年之久的项目,在重估时发现还要多花几个月进去,之后我们取消了这个项目。我们把这视作成功,因为重新估算发现,项目会比我们最初期望的会花费更长时间——早点取消可以让客户把资源转移到更好的目标上。

但跟踪计划的同时,也要记住估算是有适用期限的。我曾经记得有一位经历颇丰的项目经理说过,计划和估算就像是生菜,刚过几天还很新鲜,过了一周有点枯萎了,几个月后就完全看不出来是什么了。

许多团队发现,估算提供了一种有用的机制,可以促使团队成员间彼此交流。估算会议可以帮助大家以不同的方式,对实现即将开始的故事、未来的架构方向和代码库中的设计问题,有更好的理解。在这种情况下,任何输出的估算数字可能都不重要。这样的对话可能以很多方式发生,但如果这些对话没有发生,就可以引入关于估算的讨论。相反地,如果你考虑停止估算,你需要确保估算时会发生的任何有效的对话,在其他地方还能够继续进行。

在任何敏捷相关的会议上,你都会听到很多团队在谈论,没有估算他们也可以工作得很有效。通常这是因为,他们以及他们的客户明白做估算并不会影响重大的决定。举个例子,一支小团队在和业务人员紧密协作。如果广阔的商业前景很乐意分配一些人到那个业务单元,那么就可以按照优先级开展工作;通常这得益于团队把工作拆分成足够小的单元。团队在敏捷流畅度模型中的等级,在这里起到非常重要的作用。在团队前进时,他们首先会纠缠于估算本身,然后开始会做很好的估算,最后达到不再需要估算的境界。

估算本身并无好坏之分。如果你不用估算就可以有效地工作,那就这么干。如果你需要一些估算,那就要确认你很清楚估算在决策时起到的作用。如果估算会影响到重大的决定,那就尽可能做出最好的估算。一定要小心那帮告诉你任何时候都要做估算,或者从来不需要估算的人。任何关于估算用法的争论,都要遵从于敏捷的原则,即针对你特定的上下文,决定你该采用的什么样的方法。

Share

我爱上的最难的一次IT面试

 

我把IT面试的最爱,献给了最难那次

转眼间,开发者、架构师、咨询师,我已在这些职业中游荡了超过30年,其中包括经营自己的咨询和软件定制研发公司的九年。总觉得是时候改变一下了。 有了这个决定后,我开始寻找高度匹配我的技能、志向和个性的公司,即使不能三个同时满足,那么至少也要满足其中两项!

在做了超过30年的开发者,架构师和咨询师后——当然这其中也包括经营自己的咨询和软件定制公司的9年——我觉得是时候改变一下了。有了这个决定后,我开始寻找与我的技能,、志向和个性高度匹配的公司,即使三者不能同时满足,至少也要达到其中的两项。

在接下来的日子里,我面试了很多公司,包括Borg、生存于市场缝隙需要不停做维护的小公司、非常无聊的咨询事务所、平庸的开发车间 、毫无建树的创业公司 、离岸外包公司,以及几个极度无趣的漫画公司。

只有ThoughtWorks脱颖而出。

为什么ThoughtWorks 与众不同

ThoughtWorks是与众不同的,但在我未深入面试流程前我都不能准确地描述这种不同。越到面试后期,我就越喜欢这个过程和这家公司,最后也明白了这种不同在于他们对人的重视,这种重视远远超出了地球上那些普通水平的敏捷公司和其他所有咨询公司号称的”以人为本”。TW是这样说的,也是这样做的,并且在他们的面试过程中很好的证明了这一点。

为什么大家都认为ThoughtWorks的面试“难”

在美国,ThoughtWorks的面试的难度是数一数二的,究竟是第一还是第二,取决于你所看的是哪一份调查或者哪一篇文章。比如他们有可能来自于:

  • Business Insider
  • Forbes
  • Glassdoor.com
  • Boston.com
  • Chicago Sun-Times

其实也完全取决于你自己的看法

网上都说ThoughtWorks的面试困难,其实这有一些误导。也许她只是看起来很难,因为大多数其他公司的面试都很片面,缺乏人文关怀,且有些肤浅,甚至还有一些会让你愤怒!

对我来说,ThoughtWorks的面试不是故意“那么难”,与其他公司相比,他她只是看起来比较“难”而已,其实他只是互动比较多,让双方互相了解得更彻底:

  • 电话面试考察我们的技术知识以及推理过程
  • 比较落地的编程作业; 以你自己的风格去完成一些核心问题

其中现场面试环节还包括:

  • 一起讨论问题(考察你如何思考)
  • 限时智力测验(考察你的智力水平)
  • 与语言无关的限时编程测试(看你是否掌握一定的基础知识)
  • 一个关于道德的深入讨论(看你是否坦率,豁达,善良)
  • 两个技术/架构/设计/咨询的讨论(考察你的想象力和反馈能力)
  • 一次结对编程(考察你如何工作,以及如何与其他小伙伴一起合作)

现场面试整整持续了7个小时左右,并且所有环节都由两个面试官一起进行。说实话,我很享受,因为我的确是非常享受做测试题以及和聪明人对话,如果不是为了赶时间到机场,我是真的很不想离开。

我为什么喜欢她

我参加过的其他公司的面试,他们会预先设定一个工作岗位,然后寻找适合这个岗位的特殊技术型人才。在这个过程中,有时候他们不惜把明明是方形的桩子(人才),钉进他们预先设定的圆形的洞(岗位)。有些公司甚至自己都不知道想要招聘什么。 而TW的英明之处在于,他们真的是试图在了解我,搞清楚我到底是怎样的一个人,我到底能做些什么,而不仅仅是走过场,照本宣科地一条条过招聘要求。TW的不同之处还在于,她也想让我去了解他们,明白他们到底是谁,他们在做的是什么,以及他们为什么要这样做。

与其看面试的时长,不如看面谈的质量

其实ThoughtWorks不是唯一一家面试环节很长的公司,例如,Borg的现场面试与TW的面试一样长,但它的长没有一丁点吸引力。 由于每个讨论都是一对一的,如果遇到一个不好的面试官,就很容易影响发挥。所以随着面试的进行我对她们的印象是一直在减分!面试结束后,我已经觉得非常的疲惫和厌倦。

然而,当ThoughtWorks的现场面试结束后,虽然我也觉得累,但更多的是对于刚刚经历的那场独特面试的激动和兴奋。

在飞机上我一直在回味刚刚接触的那些人,以及那些有趣的讨论。我在憧憬这家公司可能给我带来的成长和提升技能的机会,不仅仅是专业上的,还有非专业上个人魅力的提升越想越激动。虽然是午夜航班,但我毫无睡意。

与其说面试的是工作,不如说面试的是人

在面试过程中遇到的那些人们极大地增加了我的激情, 每个人都是那么的聪明、礼貌、有趣、真诚。他们让我感到被欢迎,被需要 — 这与之前的Borg以及其他公司形成了鲜明的对比。与我经历的其他面试相比,TW的面试更高效。

回到家后,TW对我又进行了一次面试,这次是两个高管对我的视频面试,目的是确保我就是他们想要的那类人,并向我确认是否对他们的岗位依然感兴趣。

当然!从过去到现在对他们我是一直充满着激情和兴趣的!  几天后,我接受了他们的offer。

现在,我已是一个ThoughtWorker。

虽然才入职短短几个月,但到目前为止TW和我的预期完全一致,甚至他们比我预想得还要活泼有趣、乐于助人。

是的,面试是困难的,但也是值得的。如今我已顺利通关,你要不要也来试一试?

译者语

ThoughtWorks是我一直喜欢的公司,在翻译此文时,我完全能体会作者的那份心情,让我不由自主地想起那次懵懂的校招经历,不管最终是否和TW在一起,都感谢她带给我的影响和成长。TW一直是我的初恋,还没有分手的初恋。
Share

也谈响应式编程

太长不读;

本文将会围绕reactive extension介绍reactive programming的起源,其要解决的问题。

编程范式的演进

最近几年,reactive programming这个词语的热度迅速提升,下面的 google trends的这个图表很能说明问题。

rp-trends

自从高级编程语言被发明以来,各种编程范式的编程语言层出不穷,命令式编程(如C)
面向对象编程(如Java,Ruby),函数式编程(如Clojure, Scala,Haskell)都曾经或者正在软件开发领域占有一席之地。

面向对象编程

上世纪九十年代前,命令式编程仍然在软件开发领域占有主导地位。随着软件规模的不断增大,面向对象编程以其封装性,可重用性受到开发者和组织的青睐。

进入多核时代

随着摩尔定律的失效,单核CPU的计算能力几乎达到了极限,CPU进入了多核时代,程序员转而通过并发编程,分布式系统来应对越来越复杂的计算任务。

然而并发编程并不是银弹,做为一种基于共享内存的并发编程,多线程编程有常见的死锁线程饥饿),race condition等问题,而且多线程bug的以其难以重现定位臭名昭著。

函数式编程的兴起

近年来逐渐火爆的functional programming以其提倡的:

  • 函数是编程语言的一等公民(function as first-class citizen)
  • 不可变量(immutable variable)
  • 无副作用的函数(no side-effect/reference transparency)
  • 可组合的函数(composable functions)

顺利地解决了因可变量mutabble variable被多个线程共享,修改等而导致可能的多线程的bug。

并发编程的痛点仍然存在

然而,functional programming就是现代的完美编程范式了么?远远不是。

即使使用了functional programming, 程序员总会需要处理异步任务或者事件,并且总有一些IO或者计算密集型的任务,这些任务可能还会阻塞其他活动线程,而且,处理异常,失败,线程任务之间的同步都比较困难而且容易出错。程序员需要不断地询问一个线程的运算结果(在Java中以Future<T>表示,T表示运算结果的类型)是否可用。我们来考虑一下下面两个例子:

有三个线程t1, t2, t3,他们的运算结果分别为f1, f2, f3
有一个线程t4依赖于这三个线程的运行结果,而且每个线程都有有可能执行失败。
我们该如何编写线程t4的代码?

GUI程序中一次拖动操作中光标的位置就可被表示为Future<List<Position>>, (使用Future是因为这些Position的值是在未来的时间点生成的)。

如果我们希望在第一个Position可用时(拖动时间的开始位置)就能够在这Position所对应的位置画点,而不是等所有的Position都可用是一次性把光标的运行轨迹画出来。即我们希望程序能够尽快对输入进行响应。

即程序要及时,非阻塞地对输入响应。

上面的两个例子就是reactive programming尝试解决的问题,而Reactive Extension做为这个问题的答案,应运而生了。

Reactive Extension

Reactive Extension 这个概念最早出现在.net社区的Rx.net,一个提供处理异步事件的程序库,其核心概念是Observable,表示有限或者无限多个现在或者将来到达的事件。Observable提供了onNextonErroronCompleted供开发者定制新元素到达,出现错误,或者流结束时的程序的行为。
并提供了List上类似的操作,如mapfilterreduce,大大降低了异步事件编程的复杂度。

因为这些概念是如此的强大,以至于很多编程语言,如javarubyjavascript很快就有了各自的reactvie extension

关于reactive extension的技术细节可以在我的这篇博客里找到。这个视频详细地介绍了为什么需要reactive extension,以及reactive extension的是如何被发明出来的。

Reactive Manifesto

Wikipedia上对reactive programming解释如下:

reactive programming is a programming paradigm oriented around data flows and the propagation of change.

举个例子,在命令式编程下,表达式a = b + c,a的值在这个表达式执行完毕之后就是确定的,即使bc的值发生变化,a的值也不会改变。然而在响应式编程的语境下,a的值与bc的值是绑定的,上述表达式其实建立的是abc之间的一种依赖,a的值会随bc的变化而变化。

我们称之为能够响应输入变化的事件(event)

然而现在来看,上述定义已经不能囊括reactive programming的含义了。随着软件系统的非功能需求要求越来越高,reactive已不仅局限于响应事件(event)的传递,也表示程序能够响应负载(load),系统运行时出现的错误(failure)

发布于2014年9月份的Reactive Manifesto以宣言的形式提供了能够满足这些需求的软件系统架构设计的指导原则。

Reactive Architecture

在笔者看来,reactive programming可以从语言和架构两种层面上来理解,近年来层出不穷的各种语言的reactive extention就是语言层面的代表,而在架构层面上,也有遵循了reactive manifesto的类库(如akka)出现,笔者暂且称之为reactive architecture

在后续的文章中,笔者将会带着大家理解一个reactive architecture是如何做到reactive的。

Share