即使你已经在正确的轨道上,但如果只是停止不前,也仍然会被淘汰出局。——Will Rogers(美国著名演员)
敏捷需要持续不断的学习和充电。正如上面引用的Will Rogers的话,逆水行舟,不进则退。那不仅是赛马场上的真理,它更适合我们当今的程序员。
软件开发行业是一个不停发展和永远变化的领域。虽然有一些概念一直有用,但还有很多知识很快就会过时。从事软件开发行业就像是在跑步机上,你必须一直跟上步伐稳步前进,否则就会摔倒出局。
谁会帮助你保持步伐前进呢?在一个企业化的社会中,只有一个人会为你负责——你自己。是否能跟上变化,完全取决于你自己。
许多新技术都基于现有的技术和思想。它们会加入一些新的东西,这些新东西是逐步加入的量。如果你跟踪技术变化,那么学习这些新东西对你来说就是了解这些增量变化。如果你不跟踪变化,技术变化就会显得很突然并且难以应付。这就好比少小离家老大回,你会发现变化很大,甚至有很多地方都不认识了。然而,居住在那里的人们,每天只看到小小的变化,所以非常适应。在第28页我们会介绍一些跟踪变化的方法。
给自己投资,让自己与时俱进,当然再好不过,但是也要努力对团队投资,这个目标怎么实现呢?你将从第31页学到实现这个目标的一些方法。
学习新的技术和新的开发方法很重要,同时你也要能摒弃陈旧和过时的开发方法。换句话说,你需要懂得丢弃。
当我们谈到变化这个话题的时候,要认识到你对问题的理解在整个项目期间也是在变化的。你曾经认为自己已经很明白的事情,现在也许并不是你想象中那样。你要对没有完全理解的某些疑问不懈地深入追踪下去,我们将从第37页开始讲述为什么要打破砂锅问到底,以及如何有效地提问。
最后,一个活力十足的敏捷开发团队需要有规律反复地做很多事情,一旦项目开始运作,你就要把握开发节奏,我们会在第40页介绍这种节奏感。
5 跟踪变化
“软件技术的变化如此之快,势不可挡,这是它的本性。继续用你熟悉的语言做你的老本行吧,你不可能跟上技术变化的脚步。”
赫拉克利特说过:“唯有变化是永恒的。”历史已经证明了这句真理,在当今快速发展的IT时代尤其如此。你从事的是一项充满激情且不停变化的工作。如果你毕业于计算机相关的专业,并觉得自己已经学完了所有知识,那你就大错特错了。
假设你是10多年前的1995年毕业的,那时,你掌握了哪些技术呢?可能你的C++还学得不错,你了解有一门新的语言叫Java,一种被称作是设计模式的思想开始引起大家的关注。一些人会谈论被称作因特网的东东。如果那个时候你就不再学习,而在2005年的时候重出江湖。再看看周围,就会发现变化巨大。就算是在一个相当狭小的技术领域,要学习那些新技术并达到熟练的程度,一年的时间也不够。
技术发展的步伐如此快速,简直让人们难以置信。就以Java为例,你掌握了Java语言及其一系列的最新特性。接着,你要掌握Swing、Servlet、JSP、Struts、Tapestry、JSF、JDBC、JDO、Hibernate、JMS、EJB、Lucene、Spring……还可以列举很多。如果你使用的是微软的技术,要掌握VB、Visual C++、MFC、COM、ATL、.NET、C#、VB.NET、ASP.NET、ADO.NET、WinForm、Enterprise Service、Biztalk……并且,不要忘记还有UML、Ruby、XML、DOM、SAX、JAXP、JDOM、XSL、Schema、SOAP、Web Service、SOA,同样还可以继续列举下去(我们将会用光所有的缩写字母)。
不幸的是,如果只是掌握了工作中需要的技术并不够。那样的工作也许几年之后就不再有了——它会被外包或者会过时,那么你也将会出局(1)。
假设你是Visual C++或者VB程序员,看到COM技术出现了。你花时间去学习它(虽然很痛苦),并且随时了解分布式对象计算的一切。当XML出现的时候,你花时间学习它。你深入研究ASP,熟知如何用它来开发Web应用。你虽然不是这些技术的专家,但也不是对它们一无所知。好奇心促使你去了解MVC是什么,设计模式是什么。你会使用一点Java,去试试那些让人兴奋的功能。
如果你跟上了这些新技术,接下来学习.NET技术就不再是大问题。你不需要一口气爬上10楼,而需要一直在攀登,所以最后看起来就像只要再上一二层。如果你对所有这些技术都一无所知,想要马上登上这10楼,肯定会让你喘不过气来。而且,这也会花很长时间,期间还会有更新的技术出现。
如何才能跟上技术变化的步伐呢?幸好,现今有很多方法和工具可以帮助我们继续充电。下面是一些建议。
迭代和增量式的学习。每天计划用一段时间来学习新技术,它不需要很长时间,但需要经常进行。记下那些你想学习的东西——当你听到一些不熟悉的术语或者短语时,简要地把它记录下来。然后在计划的时间中深入研究它。
了解最新行情。互联网上有大量关于学习新技术的资源。阅读社区讨论和邮件列表,可以了解其他人遇到的问题,以及他们发现的很酷的解决方案。选择一些公认的优秀技术博客,经常去读一读,以了解那些顶尖的博客作者们正在关注什么(最新的博客列表请参考pragmaticprogrammer.com)。
参加本地的用户组活动。Java、Ruby、Delphi、.NET、过程改进、面向对象设计、Linux、Mac,以及其他的各种技术在很多地区都会有用户组。听讲座,然后积极加入到问答环节中。
参加研讨会议。计算机大会在世界各地举行,许多知名的顾问或作者主持研讨会或者课程。这些聚会是向专家学习的最直接的好机会。
如饥似渴地阅读。找一些关于软件开发和非技术主题的好书(我们很乐意为你推荐),也可以是一些专业的期刊和商业杂志,甚至是一些大众媒体新闻(有趣的是在那里常常能看到老技术被吹捧为最新潮流)。
跟踪技术变化。你不需要精通所有技术,但需要清楚知道行业的动向,从而规划你的项目和职业生涯。
切身感受
你能嗅到将要流行的新技术,知道它们已经发布或投入使用。如果必须要把工作切换到一种新的技术领域,你能做到。
平衡的艺术
- 许多新想法从未变得羽翼丰满,成为有用的技术。即使是大型、热门和资金充裕的项目也会有同样的下场。你要正确把握自己投入的精力。
- 你不可能精通每一项技术,没有必要去做这样的尝试。只要你在某些方面成为专家,就能使用同样的方法,很容易地成为新领域的专家。
- 你要明白为什么需要这项新技术——它试图解决什么样的问题?它可以被用在什么地方?
- 避免在一时冲动的情况下,只是因为想学习而将应用切换到新的技术、框架或开发语言。在做决策之前,你必须评估新技术的优势。开发一个小的原型系统,是对付技术狂热者的一剂良药。
6 对团队投资
“不要和别人分享你的知识——自己留着。你是因为这些知识而成为团队中的佼佼者,只要自己聪明就可以了,不用管其他失败者。”
团队中的开发者们各有不同的能力、经验和技术。每个人都各有所长。不同才能和背景的人混在一起,是一个非常理想的学习环境。
在一个团队中,如果只是你个人技术很好还远远不够。如果其他团队成员的知识不够,团队也无法发挥其应有的作用:一个学习型的团队才是较好的团队。
当开发项目的时候,你需要使用一些术语或者隐喻来清晰地传达设计的概念和意图。如果团队中的大部分成员不熟悉这些,就很难进行高效地工作。再比如你参加了一个课程或者研讨班之后,所学的知识如果不用,往往就会忘记。所以,你需要和其他团队成员分享所学的知识,把这些知识引入团队中。
找出你或团队中的高手擅长的领域,帮助其他的团队成员在这些方面迎头赶上(这样做还有一个好处是,可以讨论如何将这些东西应用于自己的项目中)。
“午餐会议”是在团队中分享知识非常好的方式。在一周之中挑选一天,例如星期三(一般来说任何一天都可以,但最好不要是星期一和星期五)。事先计划午餐时聚集在一起,这样就不会担心和其他会议冲突,也不需要特别的申请。为了降低成本,就让大家自带午餐。
每周,要求团队中的一个人主持讲座。他会给大家介绍一些概念,演示工具,或者做团队感兴趣的任何一件事情。你可以挑一本书,给大家说说其中一些特别内容、项目或者实践。(2)无论什么主题都可以。
每个人都比你厉害吗?嗯,那太好了!
享有盛名的爵士吉他手Pat Methany说过这样一句话:“总是要成为你所在的那个乐队中最差的乐手。如果你是乐队中最好的乐手,就需要重新选择乐队了。我认为这也适用于乐队之外的其他事情。”
为什么是这样呢?如果你是团队中最好的队员,就没有动力继续提高自己。如果周围的人都比你厉害,你就会有很强的动力去追赶他们。你将会在这样的游戏中走向自己的顶峰。
从每周主持讲座的人开始,先让他讲15分钟,然后,进行开放式讨论,这样每个人都可以发表自己的意见,讨论这个主题对于项目的意义。讨论应该包括所能带来的益处,提供来自自己应用程序的示例,并准备好听取进一步的信息。
这些午餐会议非常有用。它促进了整个团队对这个行业的了解,你自己也可以从其他人身上学到很多东西。优秀的管理者会重用那些能提高其他团队成员价值的人,因此这些活动也直接有助于你的职业生涯。
提供你和团队学习的更好平台。通过午餐会议可以增进每个人的知识和技能,并帮助大家聚集在一起进行沟通交流。唤起人们对技术和技巧的激情,将会对项目大有裨益。
切身感受
这样做,会让每个人都觉得自己越来越聪明。整个团队都要了解新技术,并指出如何使用它,或者指出需要注意的缺陷。
平衡的艺术
- 读书小组逐章一起阅读一本书,会非常有用,但是要选好书。《7天用设计模式和UML精通……》也许不会是一本好书。
- 不是所有的讲座都能引人入胜,有些甚至显得不合时宜。不管怎么样,都要未雨绸缪;诺亚在建造方舟的时候,可并没有开始下雨,谁能料到后来洪水泛滥呢?
- 尽量让讲座走入团队中。如果午餐会议在礼堂中进行,有餐饮公司供饭,还要使用幻灯片,那么就会减少大家接触和讨论的机会。
- 坚持有计划有规律地举行讲座。持续、小步前进才是敏捷。稀少、间隔时间长的马拉松式会议非敏捷也。
- 如果一些团队成员因为吃午饭而缺席,用美食引诱他们。
- 不要局限于纯技术的图书和主题,相关的非技术主题(项目估算、沟通技巧等)也会对团队有帮助。
- 午餐会议不是设计会议。总之,你应专注讨论那些与应用相关的一般主题。具体的设计问题,最好是留到设计会议中去解决。
7 懂得丢弃
“那就是你一贯的工作方法,并且是有原因的。这个方法也很好地为你所用。开始你就掌握了这个方法,很明显它是最好的方法。真的,从那以后就不要再改变了。”
敏捷的根本之一就是拥抱变化。既然变化是永恒的,你有可能一直使用相同的技术和工具吗?
不,不可能。我们一直在本章说要学习新技术和新方法。但是记住,你也需要学会如何丢弃。
随着科技进步,曾经非常有用的东西往往会靠边站。它们不再有用了,它们还会降低你的效率。当Andy第一次编程的时候,内存占用是一个大问题。你通常无法在主存储器(大约48KB)中一次装载整个程序,所以必须把程序切分成块。当一个程序块交换进去的时候,其他一些程序块必须出来,并且你无法在一个块中调用另一个块中的函数。
正是这种实际约束,极大地影响了你的设计和编程技术。
想想在过去,面对处理器之外的循环操作,你必须花费很大精力去手工调整汇编语言的编译输出。可以想象,如果是使用JavaScript或者J2EE代码,你还需要这么干吗?
对于大多数的商业应用,技术已经有了巨大的变化,不再像过去那样,处处考虑内存占用、手动的重复占位及手工调整汇编语言。(3)但我们仍然看到很多开发者从未丢弃这些旧习惯。
Andy曾经看到过这样一段C语言代码:一个大的for循环,循环里面的代码一共输出了60页。那个作者“不相信”编译器的优化,所以决定自己手工实现循环体展开和其他一些技巧。我们只能祝愿维护那一大堆代码的人好运。
在过去,这段代码也许可以勉强接受。但是,现在绝对不可以了。电脑和CPU曾经非常昂贵,而现在它们就是日用品。现在,开发者的时间才是紧缺和昂贵的资源。
这样的转变在缓慢地进行着,但是人们也真正认清了这个事实。我们看到,需要耗费10人年开发的J2EE项目已经从辉煌走向下坡路。使用PHP,一个月的时间就可以完成,并能交付大部分的功能。像PHP这样的语言和Ruby on Rails这样的框架越来越受到关注(参见[TH05]),这表明了开发者已经意识到旧的技术再也行不通了。
但丢弃已经会的东西并不容易。很多团队在犹豫,是因为管理者拒绝用500美元购买一台构建机器(build machine),却宁愿花费好几万美元的人工费,让程序员花时间找出问题。而实际上,买一台构建机器就可以解决这些问题。如果购买机器需要花费500 000美元,那样做还情有可原,但现在早已时过境迁了。
在学习一门新技术的时候,多问问自己,是否把太多旧的态度和方法用在了新技术上。学习面向对象编程和学习面向过程编程是截然不同的。很容易会发现有人用C语言的方式编写Java代码,用VB的方式编写C#的代码(或者用Fortran的方式做任何事情)。这样,你辛苦地转向一门新的语言,却失去了期望获得的益处。
根深蒂固的习惯不可能轻易地就丢弃掉 Expensive mental models aren’t discarded lightly
打破旧习惯很难,更难的是自己还没有意识到这个问题。丢弃的第一步,就是要意识到你还在使用过时的方法,这也是最难的部分。另一个难点就是要做到真正地丢弃旧习惯。思维定式是经过多年摸爬滚打才构建成型的,已经根深蒂固,没有人可以很容易就丢弃它们。
这也不是说你真地要完全丢弃它们。前面那个内存重复占位的例子,只是在稍大缓存中用手工维护一组工件的特殊案例。尽管实现方式不同了,但以前的技术还在你的大脑中。你不可能撬开大脑,把这一段记忆神经剪掉。其实,根据具体情况还可以运用旧知识。如果环境合适,可以举一反三地灵活应用,但一定要保证不是习惯性地落入旧习惯。
应该力求尽可能完全转入新的开发环境。例如,学习一门新的编程语言时,应使用推荐的集成开发环境,而不是你过去开发时用的工具插件。用这个工具编写一个和过去完全不同类型的项目。转换的时候,完全不要使用过去的语言开发工具。只有更少被旧习惯牵绊,才更容易养成新习惯。
学习新的东西,丢弃旧的东西。在学习一门新技术的时候,要丢弃会阻止你前进的旧习惯。毕竟,汽车要比马车车厢强得多。
切身感受
新技术会让人感到有一点恐惧。你确实需要学习很多东西。已有的技能和习惯为你打下了很好的基础,但不能依赖它们。
平衡的艺术
- 沉舟侧畔千帆过,病树前头万木春。要果断丢弃旧习惯,一味遵循过时的旧习惯会危害你的职业生涯。
- 不是完全忘记旧的习惯,而是只在使用适当的技术时才使用它。
- 对于所使用的语言,要总结熟悉的语言特性,并且比较这些特性在新语言或新版本中有什么不同。
8 打破砂锅问到底
“接受别人给你的解释。别人告诉你问题出在了什么地方,你就去看什么地方。不需要再浪费时间去追根究底。”
前面谈到的一些习惯是关于如何提高你和团队的技术的。下面有一个习惯几乎总是有用,可以用于设计、调试以及理解需求。
假设,应用系统出了大问题,他们找你来修复它。但你不熟悉这个应用系统,所以他们会帮助你,告诉你问题一定是出在哪个特殊的模块中——你可以放心地忽略应用系统的其他地方。你必须很快地解决这个问题,因为跟你合作的这些人耐心也很有限。
当你受到那些压力的时候,也许会觉得受到了胁迫,不想去深入了解问题,而且别人告诉你的已经够深入了。然而,为了解决问题,你需要很好地了解系统的全局。你需要查看所有你认为和问题相关的部分——即便其他人觉得这并不相干。
观察一下医生是如何工作的。当你不舒服的时候,医生会问你各种各样的问题——你有什么习惯,你吃了什么东西,什么地方疼痛,你已经服过什么样的药等。人的身体非常复杂,会受到很多因素的影响。如果医生没有全面地了解状况,就很可能出现误诊。
例如,住在纽约市的一个病人患有高烧、皮疹、严重的头痛、眼睛后面疼痛,以及肌肉和关节疼痛,他也许是染上了流感或者麻疹。但是,通过全面的检查,医生发现这个倒霉的病人刚去南美洲度假回来。所以,这病也许并不是简单的流感,还有可能是在新大陆染上的热带传染病登革热。
在计算机世界中也很相似,很多问题都会影响你的应用系统。为了解决问题,你需要知道许多可能的影响因素。当找人询问任何相关的问题时,让他们耐心地回答你的问题,这是你的职责。
或者,假设你和资深的开发者一起工作。他们可能比你更了解这个系统。但他们也是人,有时他们也会忘记一些东西。你的问题甚至会帮助他们理清思路。你从一个新人角度提出的问题,给他们提供了一个新的视角,也许就帮助他们解决了一直令人困扰的问题。
“为什么”是一个非常好的问题。事实上,在一本流行的管理图书《第五项修炼》中,作者建议,在理解一个问题的时候,需要渐次地问5个以上的“为什么”。这听起来就像退回到了4岁,那时对一切都充满着好奇。它是很好的方式,进一步挖掘简单直白的答案,通过这个路线,设想就会更加接近事实真相。
在《第五项修炼》一书中就有这样的例子。咨询师访问一个制造设备工厂的经理,就用到了这样一些追根究底的分析。看到地板上有油渍的时候,经理的第一反应是命令工人把它打扫干净。但是,咨询师问:“为什么地板上会有油渍?”经理不熟悉整个流程,就会责备这是清洁队的疏忽。咨询师再次问道:“为什么地板上有油渍?”通过一系列渐次提出的“为什么”和许多不同部门员工的帮助,咨询师最后找到了真正的问题所在:采购政策表述不明确,导致大量采购了一批有缺陷的垫圈。
答案出来之后,经理和其他员工都十分震惊,他们对这事一无所知。由此发现了一个重大的隐患,避免了其他方面更大的损失。而咨询师所做的不过就是问了“为什么”。
“哎呀,只要每周重启一次系统,就没有问题了。”真的吗?为什么呀?“你必须依次执行3次构建才能完成构建。”真的吗?为什么呀?“我们的用户根本不想要那个功能。”真的吗?为什么呀?为什么呀?不停地问为什么。不能只满足于别人告诉你的表面现象。要不停地提问直到你明白问题的根源。
切身感受
这就好比是从矿石中采掘贵重的珠宝。你不停地筛选掉无关的物质,一次比一次深入,直到找到发光的宝石。你要能感觉到真正地理解了问题,而不是只知道表面的症状。
平衡的艺术
- 你可能会跑题,问了一些与主题无关的问题。就好比是,如果汽车启动不了,你问是不是轮胎出了问题,这是没有任何帮助的。问“为什么”,但是要问到点子上。
- 当你问“为什么”的时候,也许你会被反问:“为什么你问这个问题?”在提问之前,想好你提问的理由,这会有助于你问出恰当的问题。
- “这个,我不知道”是一个好的起点,应该由此进行更进一步的调查,而不应在此戛然结束。
9 把握开发节奏
“我们很长时间没有进行代码复审,所以这周会复审所有的代码。此外,我们也要做一个发布计划了,那就从星期二开始,用3周时间,做下一个发布计划。”
在许多不成功的项目中,基本上都是随意安排工作计划,没有任何的规律。那样的随机安排很难处理。你根本不知道明天将会发生什么,也不知道什么时候开始下一轮的全体“消防演习”。
但是,敏捷项目会有一个节奏和循环,让开发更加轻松。例如,Scrum约定了30天之内不应发生需求变化,这样确保团队有一个良性的开发节奏。这有助于防止一次计划太多的工作和一些过大的需求变更。
相反,很多敏捷实践必须一直进行,也就是说,它贯穿于项目的整个生命周期。有人说,上帝发明了时间,就是为了防止所有事情同时发生。因此我们需要更具远见,保持不同的开发节奏,这样敏捷项目的所有事情就不会突然同时发生,也不会随机发生,时间也不会不可预知。
我们先来看某个工作日的情况。你希望每天工作结束的时候,都能完成自己的工作,你手上没有遗留下任何重要的任务。当然,每天都能这样是不现实的。但是,你可以做到在每天下班离开公司前运行测试,并提交一天完成的代码。如果已经很晚了,并且你只是尝试性地编写了一些代码,那么也许最好应该删掉这些代码,第二天从头开始。
这个建议听起来十分极端,也许确实有一点。(4)但是如果你正在开发小块的任务,这种方式非常有助于你管理自己的时间:如果在你工作的时候没有一个固定的最终期限(例如一天的结束),就应该好好想想了。它会让你的工作有一个节奏,在每天下班的时候,提交所有的工作,开心地收工。这样,明天就能开始新的内容,解决下一系列难题。
敏捷开发者可以从多方面得到反馈:用户、团队成员和测试代码。这些反馈会帮助你驾驭项目。但是时间本身就是一个非常重要的反馈。
许多的敏捷技巧来源于时间盒——设定一个短时的期限,为任务设定不能延长的最终期限。你可以选择放弃其他方面的任务,但是最终期限是不变的。你可能不知道完成所有的任务需要多少个时间盒,但每个时间盒必须是短期的、有限的,并且要完成具体的目标。
例如,迭代一般是两周的时间。当时间到的时候,迭代就完成了。那部分是固定不变的,但是在一个具体的迭代中完成哪些功能是灵活的。换句话说,你不会改变时间,但是你可以改变功能。相似地,你会为设计讨论会设定一个时间盒,即到了指定的时间点,会议就结束,同时必须要做出最终的设计决策。
当你遇到艰难抉择的时候,固定的时间期限会促使你做决定。你不能在讨论或功能上浪费很多时间,这些时间可以用于具体的工作。时间盒会帮助你一直前进。
鲨鱼必须不停地向前游,否则就会死亡。在这方面,软件项目就像是鲨鱼,你需要不停地前进,同时要清楚自己的真实进度。
站立会议(习惯38,第148页)最好每天在固定的时间和地点举行,比如说上午10点左右。要养成这样的习惯,在那时就准备好一切参加站立会议。
最大的节拍就是迭代时间(习惯17,第69页),一般是1~4周的时间。不管你的一个迭代是多长,都应该坚持——确保每个迭代周期的时间相同很重要。运用有规律的开发节奏,会更容易达到目标,并确保项目不停地前进。
解决任务,在事情变得一团糟之前。保持事件之间稳定重复的间隔,更容易解决常见的重复任务。
切身感受
项目开发需要有一致和稳定的节奏。编辑,运行测试,代码复审,一致的迭代,然后发布。如果知道什么时候开始下一个节拍,跳舞就会更加容易。
平衡的艺术
- 在每天结束的时候,测试代码,提交代码,没有残留的代码。
- 不要搞得经常加班。
- 以固定、有规律的长度运行迭代(第69页,习惯17)。也许刚开始你要调整迭代的长度,找到团队最舒服可行的时间值,但之后就必须要坚持。
- 如果开发节奏过于密集,你会精疲力竭的。一般来说,当与其他团队(或组织)合作时,你需要减慢开发节奏。因此人们常说,互联网时代发展太快,有害健康。
- 有规律的开发节奏会暴露很多问题,让你有更多鼓起勇气的借口(第23页,习惯4)。
- 就像是减肥一样,一点点的成功也是一个很大的激励。小而可达到的目标会让每个人全速前进。庆祝每一次难忘的成功:共享美食和啤酒或者团队聚餐。
【注释】
- 参考My Job Went to India: 52 Ways to Save Your Job[Fow05]一书。新版改名为Passionate Programmer。
- Pragmatic公司的出版人Andy和Dave曾听不少人说,他们成立了读书小组,讨论和研究Pragmatic公司的图书。
- 这些技术现在仍然用于嵌入式系统领域的开发。
- Ron Jeffrey告诉我们:“我希望人们敢于经常这么做。”
下一节:没有任何计划在遇敌后还能继续执行。——Helmuth von Moltke(德国陆军元帅,1848—1916)