前言
停下来,思考才是进步的本质
必须阅读大量的技术书籍,每天在Internet上不断地补充新知,以应付工作上的需要。长期的积累,虽然让我学习了许多技术,但是真正让我不断超越昨日自我的因素,并不光是这些单点的技术,而是多参考业界大师级人物的思想,以及更实际地看看我们同侪的思考,更重要的是,不时地停下来融合思考的结果。
你在做什么
做了许多年的开发,其实有很多人并不知道“自己在做什么”。《愚公移山》的故事里面,愚公为山所阻,苦于“出入之迂”,然后就决定“移山”。看起来伟大而风光的工程,可能只是拍拍脑袋的一时主意——如果只是觉得绕路太远,那么劈山开路岂不是更加经济。
愚公移山只是一种精神追求,而做工程却不是追求精神目标。我们的目标是完成工程,但是你现在环顾一下你的团队:有多少人的眼光是落在工程本身上的呢?
程序员正在调试代码,项目经理在忙着开会,市场经理在请客吃饭,老板可能还在来公司的路上。。。总之,你的身旁没有什么人关注工程本身。即便有一个人或几个人在像模像样地画着模型图,或者写着需求、分析与设计书,但是对于他们来说,这只是例行的工作,而不是出于工程本身的需要。
“做什么”作为一种状态或现象,通常是(阶段性)不变的,所以人们了解自己“在做什么”时多数只需要观察。简而言之,只需要自省,就可以了解自己的所作所为了。然后“为什么做”却相对更难于理解,因为这是“表象下的本质”,潜藏得很深;习以为常,便会根本上忘却“习”的来由。例如项目总监说要一份计划,你大概只需要拿一个以前做过的文档模板,很快就能写出一份项目计划案来。但在这个工程中,你已经忘掉了“项目计划案”真正存在的价值——写它的目的,并不是“完成工作”。
所以你需要认识“为什么做”。这其实并不是非常困难的。例如我在工程中经常问的问题是“可不可以不做”——哈哈,看起来我很偷懒似的。其实不然,因为接下来我就会从不同的人那里得到“非做不可”的种种理由。
编程的精义
编程的精义
仅仅就编程序来说,实在是一件很简单的事,甚至可以说是一种劳力活。两千年前的寓言,已经成就了一位工程名家:愚公。这位名家的身上,浓缩了项目组织者、团队经理、编程人员、技术分析师等众多角色的优秀素质。
从《汤问篇》中所述的愚公移山这一事件里,我们看到了:
原始需求的产生:“惩山北之塞,出入至迂”
也看到了项目沟通的基本方式:“聚室而谋曰”
然后,我们还看到愚公确定了这个项目的目标:“毕力平险,指通豫南,达于汉阴”
并通过研讨,择定了一个井然有序的、可以实现的技术方案:“扣石垦壤,箕畚运于渤海之尾”
在这个项目中,运用了三名技术人员和一名工程管理人员:“(愚公)率子孙荷但者三夫”
并获得了一名力量较弱,但满富工作激情的外协:“邻人京城氏之孀妻,有遗男,始龀,跳往助之”
基本上,这已经描述了“愚公移山”整个工程的概况。接下来,我们应该注意到愚公作为编程人员的基本素质。在与“河曲智叟”的对答中,他叙述了整个工程的编程实现:
“虽我之死,有子存焉”,这里描述了可能存在的分支结构,即“IF”条件判断;
“子又生孙,孙又生子;子子孙孙,无穷匮也”:这里描述了完成这个工程所必需的循环结构。
作为优秀的程序分析师,愚公论述了这个循环的可行性:由于“山不加增”,所以条件“山平”必将成立(“何苦而不平”),所以这不会是一个死循环。
在愚公的论述中,我们看到了编程的根本:顺序、分支和循环。庞大若“愚公移山”这样的工程,都是可以通过这样简单的编程来实现的。这,就是编程的精义了。
程序=算法+结构
编程的第一要务是先把事情分析清楚,把事件先后的逻辑关系和依赖关系搞清楚,然后再去写代码实现。一接到任务就开始Coding的程序员,通常就是加班最多的程序员。
记住:积极工作和勤于思考都要占时间。
第一个完成关于编程本质思考的人,提出了一个公式“程序=算法+结构”。这个公式的精彩之处,在于它没有任何的地方提及代码。甚至可以说,在这个公式里,代码是不存在的。存在的只是思想。
算法是对一个程序的逻辑实现的描述,而结构是逻辑实现所依附的数据实体。只要开发人员将这个程序的算法设计出来,并把结构描述出来,那么程序就定型了。剩下的事,简而言之,就是劳力活。
《数据结构》中,所有的算法描述中,有且仅有顺序、分支和循环这三种执行逻辑。简单如顺序表,复杂如树、图,它们的算法都是用这三种执行逻辑来描述的。
语言
当你熟悉了一门语言之后,你会发现,编程语言只有喜欢与不喜欢的问题,没有会不会的问题。任何一门语言,你都可以在两周内掌握并开始熟练编程。因为任何一门语言,它们的底层函数库都是那样地相似,它们的API都是那样地依赖于操作系统。A语言里有的,B语言里基本也都有。
通常,语言的差别主要表现在适用范围上。一些语言适合做数值处理,小数点后可以精确到原子级,而小数点前则可以表达到宇宙之无穷;另一种语言则适合做图形处理,它的底层函数库可以比其他语言快十倍或数十倍;还有一些语言则适合做网页,要用它来做一个通讯薄软件都将是史无前例的挑战。
成天讨论这门语言好,或者那门语言坏的人,甚至是可悲的。既悲其一叶障目,更悲其大愚若智的自得心态。
是懒人造就了方法
是懒人造就了方法
我们看到事物的进化。《列子•汤问篇》里的愚公要“碎石击壤”,而李冰就已经懂得“积薪烧之”了。
那么李冰为什么会用“烧”这种方法来碎石的呢?如果李冰也像愚公那样日复一日地督促着他的团队凿石开山,那他一定没有时间来学习、寻找或者观察;当然也不会发现“烧”这种方法可以加快工程进度,使得一大座山在短时间内就哗啦哗啦地“碎”掉了。
要知道李冰的团队可是成百上千人,要修堰筑坝,要“凿离堆”,当然还要吃喝拉撒睡。所以李冰如果忙起来的话,必然是“受命以来,夙夜忧叹”,必然食难下咽,睡无安枕。反之,李冰一定是个闲人,可以闲到没事去看火能不能把石头烧爆。
正是一个懒人造就了“烧石头”这个“碎石”方法。愚公太勤快了,但是越勤快,愚公将越没有机会找到更快的方法。人的精力终归是有极限的。提出新的“方法”,解决的将是影响做事成效的根本问题。愚公可以多吃点饭,多加点班,但突破不了人精力的极限。
一百万行代码是可以写在一个文件里的
按照一部分人的逻辑,一百万行代码其实是可以写在一个文件里的。不但可以,而且编译器、编辑器等也都是必须予以支持。这才是正统的软件开发。
勤快的愚公创造不了方法。对于要把“一百万行代码写到一个文件里”,并且查找一个函数要在编辑器里按5000次PageUp/PageDown键的勤快人来说,是不能指望他们创造出“单元文件(Unit)”这样的开发方法来的。
然而单元文件毕竟还是出现了。这个世界上,有勤快人就必然有懒人,有懒人也就必然有懒人的懒方法。有了单元文件,也就很快出现了一个新的概念:模块。把一个大模块分成小模块,再把小模块分成更细的小小模块,一个模块对应于一个单元。于是我们可以开始分工作了,一部分人写这几个单元的代码,另一部分则写那几个。
很好,源代码终于可以被分割开来了。结构编程的时代终于开始了,新方法从此取代了旧方法。而这一切应当归功于那个在按第5001次PageDown键时,突然崩溃的程序师。他发自内心地说:“不能让这一切继续下去了,我一定要把下一行代码写到第二个文件里去。我发誓,我要在编译器里加入一个Unit关键字”。
你桌上的书是乱的吗
你既然知道如何把书分类、整整齐齐地放在书桌上,那怎么没想过如何把所学的知识分类、归纳一下,整整齐齐地放在脑子里呢?
如果一个人学了一年的编程,他的脑袋里还是晕乎乎的,不知道从哪里开始,也不知道如何做程序。那想来只有一个原因:他学了。也把知识学进去了,就是不知道这些知识是干什么的。或者说,他不知道各种知识都可以用来做什么。
我的第一次思考:程序=算法+结构+方法
“绝对可以用面向过程的方法来实现任意复杂的系统。要知道,航天飞机也是在面向过程时代上的天。但是为了使一切变得不是那么复杂,还是出现了‘面向对象程序设计’的方法”
“面向过程是对‘流程’、‘结构’和‘编程方法’的高度概括。而面向对象本身只解决了‘结构’个‘编程方法’的问题,而并没有对‘流程’加以改造”
“对流程进一步概括的,是‘事件驱动’程序模型。但这个模型不是OO(面向对象)提出的,而是Windows的消息系统内置的。所以,现在很多人迷惑于‘对象’和‘事件’,试图通过OO来解决一切的想法原本就是很可笑的”
“OO里面,我觉得事件的概念是很牵强的,因为真正的对象之间是相互作用的,就好像作用力和反作用力,不会有个‘顺序’的延时”
“整个的‘事件’模型都是以‘记录’和‘消息’的方式来传递的。也就是说,事件模型停留在‘面向过程’编程时代使用的数据结构的层面上。因此,也就不难明白,使用或不使用OO都能写Windows程序”
“所以所谓的面向对象的事件还是‘顺序’的。所以我们经常要考虑一个事件发生后对其他过程的影响,所以面向对象在现在而言还是牵强的”
“所以我发觉面向对象的思维第一不可能彻底,第二只能用在总体分析层上。在很多时候,实质上我们只是把一个顺序的流程折叠成对象”
“程序=数据+算法——这个事面向过程时代的事”
“程序=数据+算法+方法——在OO时代,我们看到了事件驱动和模型驱动,所以出现了‘方法’问题”
“总体结构->面向对象,关系->数据结构,实现->算法”
所谓“面向过程开发”,其实是对“结构化程序设计”在代码阶段的一个习惯性的说法。而我忽略了这个阶段的“方法”的根本原因,是即使没有任何“方法”的存在,只需要“单元(Unit)”和“模块(Module)”的概念,在面向过程时代,一样可以可以做出任意大型的程序。在那个时代,“方法”问题并不会像鼻子一样凸显在每一个程序员的面前。
在面向过程开发中,“过程(Procedure)”是由CPU提供的,“单元(Unit)”则是编译器提供的(机制)。程序员无须(至少不是必须)再创造什么“方法”,就可以进行愚公式的开发工作了。
如果不出现面向对象的话,这样伟大的工程可能还要再干上一百年。。。
而与“面向对象”是否出现完全无关的一样东西,却因为“过程”和“单元”的出现而出现了。这就是“工程(Engineering)”。
团队缺乏的不只是管理
三个人的团队
团队至少是以三个人为规模的。首先一个人算不得团队,那是个体。两个人则互相支撑,二人互立并不算团队,因为没有监督。三个人便可以构成团队,这样便有了团队的一些基本特性:主从、监督和责任。
一个人的开发行为可以成功,这取决于个人努力。然而到了三个人的时候呢,就得选个领导了。
三板斧定了瓦岗寨的程咬金,功高技强,但不是将帅之才。
做管理起码要能承担责任,这是最基本的素质。
做项目=死亡游戏
从管理的角度来看,项目失败与否与项目经理的经验直接相关。项目的成功是由两个方面来评估的:项目完成质量;项目完成时间。
项目工期的问题不能解决,就不能保证项目成功。只有经验更加丰富,才更有可能逼近“合理的工期”。因此在这之前,项目经理面临的就是失败。这个失败可能不是由项目经理本身的能力所决定,或者也不是由团队成员的工作所决定,而是在一开始,那份给客户的项目协议就签错了。
因此,项目经理是需要时间来成熟的。他需要机会来承受错误,而不是一开始就享受成功。
做ISO质量体系的教训
Y公司终于在2001年发现管理跟不上了,于是开始引进ISO质量认证体系,希望通过这个体系来规范管理行为,提高产品质量和对外的竞争力。
他们做得非常认真,把全公司的人员都调动起来了。他们与每一个员工一起论证质量手册的编订;按照标准软件工程模型进行开发流程的重组;每一份流程相关的材料都约定了格式,并进行归档说明;每一个环节都设定了质量监督员来考核和回顾。。。
接下来,他们开始实施。
三个月后,他们发现了一个问题:所有环节的质量监督员是同一个人。这个人没有工程经验,于是他提出来的问题总是得不到工程负责人的确认——很显然,没有工程负责人愿意说自己这里存在问题:有问题就要改,就有可能中断或者重新来过。再者,这位质量监督员也没有管理权限,于是他即使确认了问题,也没有权利要求立即整改,工程负责人随时可以以进度为由搁置这份监督报告。
再两三个月后,他们发现一切如旧,好像工作没有因为《质量手册》的存在而发生什么变化,在手册上被改造的流程因为人力资源不充分而没有办法运作起来;绝大多数应该书写的材料因为时间不够而被“候补”。
改变最大的是综合部,这里多了一个虚设的机构用于分管ISO质量,综合部的经理也变成了分管质量的副总,但有没有因此而多拿一分钱。改变最少的是开发部,其表现为每个人的显示器顶上放了一本质量手册,用来挡住窗口射进来的阳光,以及落向显示器的灰尘。
两年之后,我们一群人来回顾这一次失败时,很多人都说是“体制的问题”,说是原有的公司转型到新的公司,不适合新的公司的管理体制及对管理的要求。
其实这并不十分正确。体制的内涵是分两个方面的,其一是“体”,即“体系”;其二是“制”,即“制度”。“ISO质量体系”所产生的那份手册只是“制度”。在这份制度的背后,所要求的是对旧有“体系”的改变——旧的公司转型到新的公司,不是搬来一本“管理制度”给每个员工读一遍就可以了的。
在这一转型期,第一要务是解决“体”——也就是“组织机构建设”的问题。如果把这个问题缩小到开发部门的工程环节,那就是“如何组织开发团队”。只有有了确定的团队模式,才能寻求相应的管理制度,并且才能把这样的制度实施在团队之上。
皮之不存,毛将焉附。没有确定的组织机构,又如何能指望做出来的管理制度“合用”呢?
谁动摇了你的制度
组织模式确定的同时,相应的制度也随之建立。很少有组织几年之后才来补制度的。
然而制度究竟决定了什么呢?我们先来看看,如果员工在工作中出了纰漏,那么:
“没有制度,你没有办法和依据来惩戒员工,因此是管理者的过失”
“有了制度而没有惩戒他,是执行者和监督者的过失”
“一而再、再而三地犯错,又一而再、再而三地被惩戒,那就是教而不改,就真正是员工的品性和素质问题了”
因此,先做制度总是好的。至少在选择做伏剑自刎的李离之前,你还有机会把黑锅仍到出问题的员工头上。
对于一个已经规范管理、体制健全的公司,不容许员工犯错是对的。即使是一次犯错,立即开除也说得过去。但还得是有前提的,这至少包括:
“员工已经接受过相关的培训,至少是员工规范和技术技能的学习”
“在该员工之前,相同的或者相关的错误没有被枉纵”
第一条是人性化的体现。中国人常说不知者不为过:员工不知道,管理者也没有给他知道的条件,那怎么能说是他的过错呢?如果是因为不知道而出了问题,那管理者首先应该自省才是。
第二条是公平性的体现。不管是针对谁,制度都是一样的,没有情面可讲的,常说的“特殊情况特殊处理”在制度面前行不通。规矩一旦被破坏就形同虚设,反而被员工当做笑柄,用来类比其他的制度。如此一来,整个制度也就离崩溃不远了。反过来,在已经被破坏了的制度面前,若再做杀鸡儆猴状,那猴子是被吓着了,不平声、埋怨声也就跟着出来了。
因此最好的方法是赶紧修订制度,而不是修理人。
所以,在更加普遍的情况中,动摇了制度的人往往不是犯错的员工,而是管理者自己。如果在制度面前,既做得到“人性化”,又做得到“公平性”,那么当管理者的便可以多做几次黑脸的包龙图,而脖子上的脑袋便可以比李离顶得长久一些。
“那我们就开始开发吧”
在一切开始之前、再之前的时间里,我还想知道一件事:你知道如何做工程吗?
很久很久以前,人们都是这样做的。拿到项目单子,然后“那我们就开始开发吧”。这样的事出现得很自然,因为积极的愚公们总是有挖山不止的欲望。所以他们一看到项目单子,第一个反应就是:那我们就开始开发吧。
组织的学问:角色
现在先考察一下你的公司,在整个系统里面,有没有这样的人:他既不归任何人管理,也不管理任何人。如果有,那么就早早把他开掉好了。
这样的人在组织机构中是一个盲点,或者空洞。按照我的观点来看,他在组织中不担任任何的角色,既然“不是角色”,那么当然要开掉。
但是,在你做这件事之前,确切地说在任何错误被归咎于员工之前,管理者应该先想想是不是自己的问题。
是的。你可能很快就发现问题出在了管理者那里。因为管理者没有确定组织机构模式,或者没有为组织中的成员进行角色定位和分工。如果这样,出现“既不能令,又不受命”的人就是必然的了。
同样的道理,在工程开始“做”之前就得先把“角色”确定好——可能部分角色是与既已存在的组织机构相关的,例如“部门经理”和“开发人员”;而有些就需要临时授命。
R模型:
开发团队中,与品质部门、文档和培训、客服部门、市场部门交流的,只有项目经理。
以下几点内容是需要注意的:
“如果项目针对直接客户,而且没有产品化的可能性(或必要性),那么可以将与市场(以及市场部门)相关的问题和角色先放在一边”
“已经存在于开发团队中的成员,不适合在品质部门中兼任角色”
“(R模型)项目经理应致力于减少团队中开发角色与其他部门的沟通,必要时开发经理应该站在开发人员之前进行部门间的交互”
“品质部门、文档和培训部门以及客服部门应该主要由专职人员构成,尽管开发人员可以(或者经常会)参与文档、培训和客服工作,但这也通常是他们最不能胜任的角色”
“这是中小型规模的公司和团队的参考组织机构模型,对大型团队并不适用”
在这个模型中,我们仍然看到了一个至少由三个人构成的团队。其中,在开发经理和开发人员之间,既存在主从关系,也存在协作关系。而项目经理,则在团队中处于领导者、组织者和团队保障者的地位。
如果非要精简到两个角色的团队模式,那么通常是开发经理兼任项目经理。因此这位开发经理一定要能清楚地区分这种双重角色的身份:在任何时候,明确自己是在进行“团队内协作”,还是“团队管理(和组织)”,还是在与“团队外交流”。
跟随蚂蚁,但不要栽进蚂蚁洞里
团队真的需要管理吗?
这经常是“运营”开发团队的管理者最容易给错答案的问题。这些管理者兢兢业业,试图细化每一个管理环节,将自己的意愿贯彻到。。。恩,CPU里去。
实际上,开发团队并不需要管理。或者说,在你还没有弄清楚状况之前,不要去管它。
开发经理如何面对一个并非由他亲自雇佣的成员组成的团队:
“与成员面谈,让他们签约受雇于你”
“或者,解聘他们”
“再或者,放弃这个职位”
“签约”这样的事,在大多数环境下是行不通的。协议并不能建立管理者与被管理者的信任,而只是确保了这种关系。
但是你应该相信我,在你接手这个团队之前,上一任经理也确保了这种关系。然而团队失败了,否则不会换做是你。
禀性难移,要改变一个人都难,何况是改变一个团队的既定习惯。
如果有一群开发人员像蚂蚁一样辛勤地工作着,那么,请先不要打扰他们。你应该跟随他们,看看他们是如何做的。发现规律,分析这个规律的价值,最后再尝试改变他们(的一些负面价值的规律)。
所以你要紧紧地跟随他们——除了一个地方。那地方是你去不得的,那就是蚂蚁洞。
显然,你不是开发者,你是管理人员。所以尽管你也是团队中的角色,但千万记得离蚂蚁洞远点。你在洞外张望,可以发现问题;你在洞内,就只有做“循规蹈矩”的蚂蚁。
管理者是那个可以在洞外放木棍的人。
“什么是增值税发票?”
现在你已经是足够细致地观察了你的团队,知道这个团队存在问题,你也知道这必须被改变。当然,你也知道这种改变并不是放一根木棍那么简单。
你已经确定了组织结构,确定了组织中的角色,还有了一个团队的人。所以作为项目经理,你需要先分工。
在分工之前,那个团队只能算是一个没有组织与合作的群体,所以英文中群是Group,而开发团队是Team。被优先考虑的是弹性分工。每一个人都被要求做一颗革命的螺丝钉,哪里需要哪里拧。所以弹性分工总是被放在企业节省人力资本的第一要务上。然而我们真的会做弹性分工吗?
蚂蚁的分工模式之一就是弹性分工。一只蚂蚁搬着食物往回走时,碰到下一只蚂蚁,会把食物交给它,自己再回头;碰到上游的蚂蚁时,将食物接过来,再交给下一只蚂蚁。蚂蚁要在哪个位置换手不一定,唯一固定的是起始点和目的地。
确定被“弹性分工”的员工需要可以快速地切换到新的角色。但首先要考察的并不是他是否“有能力”胜任这个角色:能力可以通过学习来增强,而角色的转换,则首先是思想的转换。
“什么是增值税发票?”意味着从技术到经营的角色转变。这个问题本身带来的并不是能力的提升,但如果我提不出这个问题,我将没有可能理解经营与市场。
尽管弹性分工非常有效,然而真正做弹性分工却并非易事。蚂蚁的角色转换是本能的。因而更应当留意团队成员“自激”式的角色转换,知道他是不是真的想(而不是需要)转变一下角色。
然而能提问“什么是增值税发票”的愚公毕竟不是太多,大多数时候他们在“箕畚运于渤海之尾”,如果实在闲得厉害,他们可能会去发明翅膀,而不是思考“什么是增值税发票?”
更好的选择是明确分工,而不是弹性分工。你应该明白,重要角色的更替通常是极具风险的,例如项目经理或者开发经理;频繁的开发人员的调度也会直接影响到工程的质量和进度。
如果所有人都在思考“什么是增值税发票”,那么你的组织机构将立即溃散。
因此,明确分工是你的管理职责。做管理≠做伯乐。
流于形式的沟通
用户不会用C,难道就会用UML吗
在前面提到的R模型中,开发人员最好不要直接面对客户。项目经理有这样一种优势:他可以不用了解C语言,也可以用一种非C的语言来与客户交流(比如说汉语)。
或者你更愿意开发人员尽早进入状态,那么,可以让开发人员以需求调研的身份出现在客户面前。但是,请注意这个人员的角色将变成“需求调研者”,如果他不能适应这种转变,那就别让他去——那会是灾难的开始。
要深入项目需求阶段的项目经理或者调研人员,被要求深谙项目所涉及的业务。但这往往是做不到的,因为我们是软件公司,而不是做这些(客户的)业务的公司。这时惯常的做法是聘请行业咨询公司(或者个人)来介入需求阶段,以协助了解和分析需求。
这些咨询专家总是很喜欢把事情搞得很复杂,所以他们会说这一切的过程有个专用名词,“恩。。。这叫需求建模。”他们很专业地说。
如果他们更加专业,他们会告诉你他们用的是UML。
到现在为止,你应该看到,咨询公司除了把问题搞得更加复杂之外,他们仍然需要面对最直接的问题:如何与客户交流?
他们的解决之道是建模语言,有什么差别吗?程序员不能要求客户会C,难道需求分析师们就能要求客户会UML吗?!
项目文档真的可以用甲骨文来写
在一些情况下,在项目中使用UML只是完全不懂的老板,以及什么都懂的博士的主意,而真实的场景中去做事的那些客户与项目成员,其实是未见得就能用好UML的。
如果你的项目面对的对象是商周文化的考古专家,以及你的项目组都由精通这种语言的成员构成,这时你就可以用甲骨文来做项目文档,以及画各种模型用例。
你要明白,要让考古学家看懂用例图,难度远大于看懂甲骨文。与其要求他们学一种语言,不如使用他们那个世界的通用语(当然,前提是你的项目组也懂得这种语言)。
盲人并非不知道如何走,只是他不能像常人一样描述他所知道的路。因此“问道于盲”是没有错误的,真正的错误是你睁着眼睛问。
我们需要在正常人与盲人之间建立一种沟通的方式,既然盲人不能睁开眼睛,那么你就闭上眼睛好了。
UML图在一些客户眼里无异于盲人的世界,如果需要向他们做需求调研,你只能使用一种这些客户能够理解和接受的方式,例如表格、流程图以及…更深入的交谈。
你要确认你的沟通方式是否有效,而不是去追求这种方式是不是UML,以及你用UML表达得是否正确。客户是因为他认为你理解了他们的需求,而在“需求确认书”上签字,而不是因为你的UML图画得是否精确。
沟通的三层障碍
沟通的第一层障碍,并不在于你要表达的内容,而在于你如何表达。换个说法就是“不知所云”。这种情况下,你需要组织语言、学会说话。
从叙述中揣度结果,是人们在交流沟通过程中潜在的意识和行为:如果两个人在努力地交流,那么他们都一定会无比细致地去分析对方的描述。因此,(注意!)他们事实上都会关注对方的措辞、语气、句法,或者分析表达的前后逻辑与关联。而这样做,通常有两个目的:
找到对方表达的潜在含义与目的;
找到对方叙述中的逻辑错误。
第一个是支持者的心态,第二个则是反对者的心态。然而你应该知道,这两种心态就是一个会议的全部内容。
所以你会发现,重要的人很少说话,而重要的会议所需要的发言也很少。这样的角色,或者这样的场合下的言论都是经过充分组织的。——只有这样的表达,才会更有效。
一句名言“对于两个聪明人来说,正确的结论通常只有一个,因此如果出现了争执,那么讨论的一定不是同一个问题”。
这句名言最关键之处,是在于它首先设定了“两个聪明人”为前提。然后实际交流中,事实上我们经常会主动地让这个前提不成立:我们通常会把对方当成白痴,试图说服对方支持你的“聪明观点”。
所以我们经常会读到一种文档,这种文档没有前提,没有概要,开始就说“我们如何做”或者“为什么我们要这样做”。你大概得在翻很多页后,才能找到一个结论:哦,原来那个家伙在说这件事。
通常,如果一件事正确,那它就是正确的。无论你分析的过程如何,结论也“不过如此”。所以你应该把结论放在文档的前面,把指导性的原则放在更前面,把事件的前因与目标以概要的形式放在最前面。一个聪明人只需要200字就可以说完的一件事,同样另一个聪明人也只需要这200字就能理解。
对于一件事来说,起因、目标、结论和原则都已经确定了,剩下来的过程控制还需要“聚室而谋曰”吗?——哦,如果是这样,愚公的团队每天的工作就只剩下开会了。
所以沟通的第二层障碍出现在跟聪明人的讨论中,让人觉得“不知所云”。这种情况下,你应当预设前提,并尽早阐述结论。
关于用甲骨文写文档或者说话,最初的设定是大家都懂得甲骨文,最终的要求是说(或写)清楚。但你可能已经发现这样的设定存在一个荒谬的前提:我们总能把一件事讨论清楚。
这个前提之所以“荒谬”,是因为它忽略了成本。如果一件事要足够长的时间才能讨论清楚,那么等它讨论清楚了,这件事本身也就失去了意义。讨论清楚事件A,与实施事件A之间的确是存在前后逻辑的,但如果“维持这个逻辑的成本”使得事件A不能被实施,那维持它的前提也就不存在了。
除了时间这种沟通成本之外,沟通消耗的人力成本也是关键。事件A需要两个人沟通来解决,与需要10个人(或整个团队)沟通来解决,所消耗的成本显然是不一样的——人多并不仅仅使“沟通变得更复杂”。所以,一个结论是需要在大多数人之间做出,还是只需要在一两个人之间做出,是在一开始就要被确定下来的。
用尽可能少的人、在尽可能短的时间内做出决策,这是降低沟通成本的关键。正是因为有了人和时间这些成本因素的约束,所以“我们讨论清楚再做”这个设定可能就会很荒谬。所以第三层障碍的主要表现是:不知缓急。解决之道,则是不要把沟通目标设定为“让对方认同”。
在我们的确没有办法把一件事情“讨论清楚”的时候,就是“旁观的人最重要”了。——作为管理者,应当去观察、理解和发现问题(或者由专人向你汇报)。你要尽量去听、去思考。因为作为整个角色,你总是有机会纠正问题的。
但是,不要急于去纠正——在一个会议上即使某种想法有问题,也绝不是在你发言的三分钟里就能纠正的,而是在最后你做出的决策里去纠正的。这种决策通常有两种:
给出明确的答案;
存而不论;
看起来,让你“给出明确的答案”是职责所在。反过来说,存而不论就似乎是在推卸责任了。但是可能在某些情况下,存而不论才是最好的决策。
项目经理不是理论家,所以并不是一定要把一件事理论清楚才能实作。论理是要以沟通成本(人力和时间)为代价的,也可能以牺牲事件本体来做代价。因此作为管理者,你应该“适时地终止讨论”。
沟通不过是手段,是工具之一种,而管理者的目标是项目本身。因此讨论不清楚就暂不清楚,让需要讨论的人(而不是整个团队)继续去讨论。于你而言、于项目而言、于整体而言,“有的‘异’无关宏旨,无碍大局,可以存而不论”。
最简沟通
在大多数的项目中,都存在着这样的问题。真正能满足极限编程所提出的“现场客户”的情形并不经常出现。即使能将程序员送到客户现场中去,沟通问题仍然是不可避免的。
因此有了“最简沟通”计划:
在一个月中,只能跟客户进行三次联系;
三次联系中,最多只能有一次面谈的机会;
一个月后,提交全部的需求调研报告、需求分析和关于该项目的远景规划。
我们开始在网络上查看相关软件系统的特征,以抽取客户所关注的内容;了解该客户的公司、经营理念、组织结构形式及工作模式;了解同类公司的成功经验和优秀的管理模式,以及客户的竞争对手在做什么和在关心什么。。
最后,我们开始综合以下两个方面的因素:
客户在公司层面的外在表现、内部机制和运营管理手段;
客户在项目中已经明确的需求和可能发生的需求,以及客户围绕其公司行为(和方向)所提出的需求。
这样就了解了客户项目中所有会产生需求的信息点。
我们开始设计提问,每一个提问涵盖尽可能多的信息点,尽可能地具有发散性,以便形成更多的推论和假设。
我们把这些做成项目概要,用E-mail提交给客户,并在第二天电话回访他。他以口头形式回复了这封E-mail,这让我们尽可能多地得到了项目在方向上的修正。
我们确定了项目的实际目标,以及远期的方向。接下来就是设计需求条目。
客户已经先期提供了一些关于项目的文档、报表和工作数据。因此基于这些数据的需求分析,将是下一个沟通前所进行的最艰苦的工作。项目组员被要求:
分析用户的每一个表格,以构建基础数据库;
分析每一条数据的含义以确定它的上下限,以及数据间的相关性;
从工作文档中去了解客户的组织机构及其相互关系,同时确定每一类使用该系统的角色;
从报表中了解客户关注的数据信息,以及被他们所忽略掉的数据信息。
我们从数百条需求条目中,整理出系统结构和模块,需求条目被映射到各个模块。我们很快就画出了模块间的相互关系图,并通过这个图分析了数据的交叉关系,设计了相应的数据索引,并增加了一些新的关系性数据。
对用户角色、原始数据和系统结构进行了梳理之后,我们花了很短的时间实现了第一个系统模型。当然,很多的功能项目都只是简单地show a dialog。。但我们优化了每一个操作流程,以保证不同的用户(角色)在使用时都尽可能流畅。
这一次的沟通我们使用了面对面的模式。我们很庆幸地得到了与这个系统的每一类用户(角色)接触的机会。而正好我们有一个模型,我们便让他们来操作并提出意见。这一次我们终于有了一份详尽的调研报告。
接下来的分析设计顺理成章。我们在一个月后完成了这个项目的需求分析报告,以及在这个分析上的一些框架型的设计。此外,还有一个被用户接受的原始模型。
应该清楚的是,保障每一次沟通的有效性都是最重要的事。沟通不是打电话或者请客户吃饭那么简单。你得到的每一次沟通机会,都是向客户了解更深层次需求的机会,因此最好在见到客户之前,你就已经设计了所有的问题和提问方式。
吃饭并不是有效的沟通。大多数时候,那将以醉酒收场。
为不存在的角色留下沟通的渠道
很多项目(尤其是产品计划)在负责人员离开后,就自然而然地死掉了。这一切的原因归咎于“没有History”。
维护旧项目比做新项目更难,许多人深有同感。然而这些“有同感”的人又何曾想过,自己在做“新项目”的时候,要为“项目维护”这种还不存在的角色,留下一个沟通、对话的渠道呢?
我把项目的History作为跟这种“不存在的角色”沟通的一种方式。History的丰富和准确为项目的后继开发、维护提供了可能。
历史记录(History)与注释(Comment)不是一回事。代码中的注释是为阅读代码而留备的,而History是为整个项目而记录的。一些参考的记录内容有:
需求阶段:与谁联系、联系方式、过程、结果以及由此引发的需求或变更;
设计阶段:如何进行设计、最初的构架、各个阶段的框架变化、因需求变更导致项目结构上的变化(有助于了解构架的可扩充性);
开发阶段:每一种技术选型的过程,每一种开发技巧的细节和相关文档,摘引的每一段代码、算法、开发包、组件库的出处和评测,程序单元的测试框架,每一个设计和构架变更所导致的影响;
测试阶段:还记得测试用例和测试报告吗?那是最好的History之一。
记得在每一笔记录后写下时间和你的名字,便于那些人能够再找到你并溯源到问题的源头。——当然,这得赶在你和古人一样“与天地共存”之前。
虽然大多数的版本管理工具也留下了每个阶段的印迹。但如果不明确要求组员写下详细的History,那么他们可能在每一次版本签入时都只写下两个字的备注“完成”。
流于形式的沟通
在很多时候,我所听到的沟通,都是一种形式。例如与客户吃饭或者打回访电话。
其实沟通是具有目的性的,如果在没有明确目的的情况下与客户沟通,那将是浪费客户和自己的时间。这种目的,可以是了解项目的讯息、挖掘潜在的项目。。。最末了,才是交流感情。
然而大多数情况下,它仅仅被看成是交流感情。这便成了形式,且往往是客户所讨厌的一种形式。
沟通问题不仅仅存在于你跟客户的交流之中,还存在于项目的各个角色之间。设计人员看不懂项目的分析报告,或者开发人员看不懂设计人员的方案,又或者测试人员看不懂开发的结果,等等,都是沟通问题。
UML的确是解决沟通问题的最佳手段之一。然而如果项目一开始就不能用它,那么强求的结果必然是痛苦的——要让UML在一个没有经过相关培训的团队及其各个角色之间用起来,几乎是不可能的事。即使用得起来,也存在经验问题。千万不要指望仅仅一个项目,就能让你的组员深刻地理解UML的思想。
也不要指望在每个项目中都能用它,如果你的客户能够理解并支持使用UML,那么这个项目就会有一个良好的UML使用环境。否则,开发环节中资料的不一致性,将会使得项目难以收场。
使用与不适用UML,其根本的问题在于沟通方式的选择。只要是行之有效的、能在各个项目角色间通用的,就是好的沟通方式。
在每一次回顾项目时都应该注意:流于形式的沟通,极有可能是你的项目被不断推翻和不断延迟的最直接原因。
失败的过程也是过程
做过程不是做工程
模型就是“样子”。人家拿出一个东西来说:这是模型。其言下之意就是要你按照这个样子来做。过程被描述为可重复的模型,实施的结果却可能演变成为相当尴尬的局面。
换而言之,无论是用RAD模型还是RUP模型来做工程,即使是亦步亦趋,也做不好工程。
如果工程可以那样做成的话,只需要有瀑布模型就足够了。因此“做过程”并不是做工程的精义。也不是目的。
做过场
每一个角色都把自己的环节当成一个“过场”,如同演戏一样,从A做到Z,就一切都完成了。当然,按照RUP的思想,是要从A到Z一遍又一遍地做下去的。然后,如果每一遍(或者用RUP的那个术语“迭代”)都只是“过场”的话,项目将只是一场无休止的演出而已。
实现,才是目的
很多人把问题的本质给忘掉了。从最开始,从我们编程开始,我们的目的就是实现一个东西。无论这个东西是小到称手的一个工具,还是大到千万的一个工程,我们的目标,都是要“实现”它。
工程只是一种实现的途径。最初做开发的前辈们,不用什么工程或者过程,也一样编出了程序,也一样解决了问题,也一样实现了目的。而现如今,我们讲工程了,讲过程了,讲方法了,却什么都再也做不出来了。
工程被当成了借口,掩盖了我们做事的真正目的:“实现”。因此,我们在一个项目中常常听到说“工程要这样做”,或者“工程要那样做”,而绝少听到“项目要求这样做”或者“客户的本意是那样的”。
这样的结果是:我们做完了工程(的每一个过程),却没有完成项目(的每一个“实现目标”)。
为工程而工程的人,都迷失在项目中了。就像开发人员迷失在一个技术的细节上一样。专注于RUP或者RAD之间区别的人,可以把每一个过程的流程图都画出来,却也被这每一个流程给捆绑得死死的,再也没有挣扎一下的力气。
过程不是死模型
试着跳出大师们的身影,再仔细地看一下那些所谓的“经典”过程,不过是瀑布模型的一再变形。瀑布模型描述了开发的主要环节,于是一群人把这些环节拧来拧去或者反复叠加,就成了RAD、螺旋、RUP,以及未知的、还没有被拧出来或者堆叠出来的X、Y、Z。
例如,如果你把V模型拉直了,还不就是瀑布模型吗?然而如果仅仅是这样看问题,那还只不过是看到了皮表上的东西(买椟还珠)。
我们应该去思考由瀑布模型到V模型这种变化的真实意图:V模型在每一个环节中都强调了测试(并提供了测试的依据),同时又在每一个环节都做到了对实现者和测试者的分离。由于测试者相对于实现者的关系是监督、考察和评审,因此测试者相当于在不断地做回顾和确认。
因此,V模型变得比其他模型更为实用。模型的左端是接受外包任务的团队或者公司,而右端是企业中有丰富经验的工程人员。这样既节省人力,又可以保障工程质量。
相对于瀑布模型,V模型有改变了什么吗?是的。源于实际的需要,它把测试(和评审)阶段抽取出来,于是就成了V模型。
你要知道,过程模型是在既有工程中总结出来的。也就是说,在某个模型有名字之前它就已经存在了,就已经被一些团队或者公司创生并使用了。
“刻鹄类鹜”与“画虎类狗”
意思是:雕刻天鹅不成,总还可以像只鸭子(鹄);若画虎不成反而像条狗,那就事与愿违,贻人笑柄了。
同样,以得失而论,在瀑布模型与RUP模型之间,学习前者不成,可思过程的本质;学习后者不成,可得文字的架子。——用不好RUP的人,总会说自己终归还有一堆文档模板可以抄,便是这个缘故。
过程理论中,如果懂得了所谓的模型原本都演化自那个简单的瀑布,那么文档是按XP写还是按RUP写,也就可以应时、应需、因地制宜、择善而从了。本质的东西若能理解得透,架子还不是随手搬来就可以用的吗?
越是简单的东西,往往越是接近于本质。
RUP中,真正精髓的东西,既不是那个R(Rational),那是人家的招牌;也不是那个U(Unified),那是人家的广告。而是那个P(Process),那才是实实在在的东西。你要明白,如果瀑布模型理论是Rational提出的,他们一样会把它叫RUP。
朱湘说:“画不成的老虎,真像狗;刻不成的鸿鹄,真像鹜吗?不然,不然。成功了便是虎同鹄,不成功时便都是怪物。”
工程不是做的,是组织的
我们总是在说“做工程”,好像工程就是面包馒头一样,有个模子,拿来照着一堆面按上一按,放在笼屉上蒸上一蒸,就可以“做”出来了。
经历过工程的人都知道,我们没有那个模子,而工程中的人员也不是那一堆面。
所以我们当然不能“做”工程,而是要“组织”工程。项目经理的工作,就是要去组织这个工程中的各个角色,使得分工明确,步调一致,共同地完成这个项目。
谁是解结的人
是谁的问题
有一个这样的问题:成功或失败的公司,也都一样有总经理,都装电脑,都在开会,都打广告。——请问为什么有的会倒闭?
在一个模式化的公司里,体制上最大的敌人其实是模式本身。然而在一般人的思维方式里,不模式化就不成其为公司。例如统一制服、统一上下班时间、统一计算机上的应用软件,等等。我们一方面看到了模式带来的规模化扩张,另一方面也看到了模式带来的臃肿与自闭。越来越多的人缺乏求实创新的意识,缺乏主动沟通的能力,渐而人浮于事,最后就将模式和现状关联在一起,得出一个结论:这个公司就是这个样子。
大多数人把一个公司的“这个样子”归结于文化现象。然而,你也知道没有一家公司不愿意有一种“良好的”文化氛围。接下来的问题是:为什么还是会有“那个样子”的企业文化?
大多数情况下,企业文化就是一种群体现象。群体现象本身除了长期的自我演进之外(例如人类的社会行为),另一种就是由管理者所引导的团队文化所扩散出来并进而产生影响(例如华为的床垫文化)的现象。——当然,我知道文化想象也是一种沉淀(如果你所在的公司是百年老店的话)。
没有特质的团队是会很快死掉的。
在通常情况下,一个团队的特质是管理者在团队生活和行为过程中逐渐形成的。特质的形成,是管理者的问题。他或者是主观地培养,或者是在不经意中形成,或者这根本就是管理者个人特质扩散开来的一种群体特征,但无论如何,维护有益于团队整体的特质,是管理者的责任。
正视你的成功
虽然发掘、彰显和维护这种特质是管理者的责任,但是并不是一个管理者来到一个团队大喊一声“我有特质”,于是团队就有特质了。一般情形下,管理者有个体特质,是管理者的问题,不是团队的问题。因此我们也注意到,很多人反对“空降兵”式的管理者。因为(大多数情况下)这些从天上掉下来的人,一开始就拿着自己的特质或以前团队的特质来“主动地”影响新的团队。他们最经常说的话是“我通常习惯这样这样”,或者是“我们以前怎样怎样”,又或者是“我原来所在的部门如何如何”。
成功的经验往往最不可信,因为一方面,成功者沉醉于成功的喜悦,并急于与人分享快乐与荣誉,而不关注这些成功的前提与背景;另一方面,听取这些经验的人则因为那些“既有的成功”而丧失了应有的警醒。
经验,是源于对过去的思考,而不是对过去的复制。面对那些在你面前说“我们曾经这样成功地做过”的空降者,不妨先把他们想象成一条条肺鱼。只有提得出质疑,才能换个角度去看到那些成功经验所依赖的背景,也才能看到某些成功背后的偶然的或者关联的因素。
每个走上管理角色的人,都无可置疑地拥有非常多的辉煌。对于这些,无论你是空降还是地面进攻,也许在你还没抵达这个团队的时候,大家都已经知道了。但你是来解决问题而不是来分享成功的。你的那些成功经验,未见得都是可以或应该与团队分享的。如果需要,对失败案例进行分析,并与团队中的成员分享可能要好得多。
千万不要把自己的经验直接拿到项目中来套。“我曾经做过”、“我这样想过”、“对这个问题我思考过了”,这些言论只是把问题的根苗填实在团队的缝隙里。
总得先做点儿什么吧
团队特质是如此重要,但看起来,它无论如何都会是较长远的事。管理者一开始就照搬某种模式,也不能立即着手去建立一种未知的团队特质,那么我们总得先做点儿什么吧?
使得,我们要找出一些必需的群体特性。它是最初的凝聚力,影响着一个群体的成效,是成功的基础(但不是特质)——这些基础的特性,是如此的必须,以至于管理者即使无法彰显个体特质或发掘团队特质,也必须先在群体中维护这些特性。基础特性如骨,团队特质如肉:有骨无肉不久,有肉无骨不立。
首先,你的团队无论如何都需要有一个远期的目标(然而我发现事实上很多管理者并不善于描述远景)。团队的远景与目标不一定非得是“特定项目的特定结果”,例如远景不见得是你现在正在做或者准备完成的项目。举一个例子来说,远景可以是“打造公司的精英团队”,或者“挖掘某项目技术在某某行业中的应用”这样的描述。前者以精神形象约束团队,后者以技术方向引导团队。远景的具体设定,取决于团队的结构、项目的特性和管理者个人的素养。
远景更多地侧重于方向的描述,而阶段性目标的确也是必需的。这至少有三个原因:
明确阶段性目标以便于团队实施和检测;
细化的设定目标更加灵活,便于修正;
阶段性成功能充分激励团队的士气。
但是无论是对大的远景,还是小的目标,在团队中并不需要每个人都予以密切关注。所以对目标进行阶段性设定与回顾,是使这些“并不时时关注方向的人”也能体会到方向感的最佳方法。阶段性的目标在微软的工程中被称为“里程碑”,可见这是一种卓有成效的、实践性很强的工程方法。然而有时在公司里很长时间,我都只知道为谁工作,而不知道工作的目标——更高层的管理者从来都没有告诉我“整个公司(或我所在的团队)未来的方向是什么”。
假想我们的团队已经排成队列,并设定了一个目标:向正南方跑10公里。然后呢开始描绘这10公里之外的风景。接下来,全队人马精神抖擞,蠢蠢欲动。
你难道打算现在就大喊一声“跑”吗?
不。如果整个团队现在就开始起跑,那么1秒钟后团队就溃散了。因为对于他们每个个体来说,你已经设定了“跑到终点的目标”,所以每个人都只是在想着跑到终点,团队自然就很快解体了——结果变成了“没有队列”。所以我们得再加一个限定:整个团队一起到达整个目标。
接下来的事情一定变得很有趣:我们的团队每个人都昂首挺胸,摆开双臂向“正南方”奔去。第一个人看见一堵墙,跳了过去;第二个人没看见,撞在那里了;第三个人紧接着踩着第二个人跳了过去,结果掉在了墙那边的坑里,正砸在第一个人的背上;第四个人。。。活脱脱地像极了一个“呆头鹅队列”。
看起来路并不怎么好走:脚下没坑,不等于前头没墙;反之亦然。因此你得加上第二个限定:无论如何,这个团队既要抬头看前面有没有墙,又要低头看脚下有没有坑。
接下来的事情就变得有趣而可笑了:每个人都上顾下盼,像一队企鹅一样地缓慢行进。
如果每个人都必须不断地调校方向与留心脚底才能跑到“正南方10公里”,那么“企鹅队列”是必然的结局。所以第二个限定应当被分解成这样:最前面的人去看有没有墙,其他人则关注脚下有没有坑——方向与远景不妨让大家都知道,但“保障方向”这件事,应该只交给头羊。
现在我们有了一个“起码像个样子”的团队。基本上来说,这个团队有三点特性:
方向和目标明确;
团结并分工协作;
能意识风险并有规避策略。
你不是团队的腿
最初看起来一切还好,然而更多的麻烦将会出在9公里之后的路段——或许这些苗头从5公里之后就出现了,只不过这次正应了“行百里者半九十”那句古话:在9公里的时候,有1/4的人苍白着脸告诉你“跑不动了”。
无论他如何陈述理由,产生这个结果的内在因素只可能有两个:
他根本不再对10公里之外的风景抱以期望,甚至认为那不过是望梅止渴的幻想;
他消耗了相当的体力,接近极限而无法再坚持。
如果“头羊”是技术经理,或者是团队中的某个“精神领袖”,那么(作为项目经理的)你就是教官。你的工作主体是:协调、督促、激励、监督和凝聚。——当然你还可以做些别的事,例如去操场外给大家买些冰水。然而有一件事你绝对不能做:试图帮那个说“跑不动了”的人跑下去。
你不是团队的腿。
大凡是从技术出身的管理人员,总会有愚公那种本能的“实现欲望”。如果一件事自己能做而别人不能或者做得不够好,那么他总是恨不得自己去做。的确,对于一些技术细节来说,你“也许”能立即着手去解决。但是,一方面你根本不可能通过“亲力亲为”解决掉“团队行进”的问题;而在另一方面,你至少为团队带来了下面这四重危险。
首先,你应该让团队的每一个人清楚:“我”必须跑到终点,否则“团队”到不了终点。这是每个个体的责任,没有人可以替代——这是培养责任心和树立价值观的事。假使你真能成为这个人的腿,“跑”到终点,那么这个团队的成员将会质疑于自己的价值和能力,也会忘却自己的责任。一个人如果在团队中没有价值,也没有责任,那么他离辞职也就不远了。
接下来,培养一个人最怕的是“教而不习”:你教他,他要么不学,要么不用。但是,事情的真相,不见得就是这个人“懒”到不学习,而是你过于勤快,让他失去了“习”的机会。所谓学习,就是让他在过程中看到问题,并了解到解决问题的方法,最后加以解决。
你现在应该注意到:如果你真的帮他跑到了终点,那么他将无法知道这些;或者即使“学”过这些知识,也无法将现在的疲劳与它联系起来。正是因为你愚公式的勤奋,使团队成员失去了“习”的机会。另一方面,事事亲力亲为虽然容易服众,却也容易滋长集体的惰性:团队成员如果只能把你、把项目、把公司当成学习观摩的对象和场所,自然于项目无益,于团队无益。然后,你还在愤愤不平:这些人怎么又懒又笨,什么事都要我动手。——如果团队在你面前只是愚公的集合,那么可能是你出了问题 :不会教习,或过于自负。
再接下来。于一个人而言,“成功”的激励远大于其他。一个人从来没有享受过登顶的乐趣,那么他一定不会喜欢登山的过程。而你帮他跑到终点,事实上也剥夺了他作为团队成员来分享成功的权利(虽然项目奖励可能不会少,然而这只是形式的,而非内心的所得)。让一个人总是去做“没有成就感”的工作,他必将渐而生厌,你也无异于自毁长城。
最后,你过于强调了个人的能力,这会助长团队的惰性。团队管理是促进整体行进的过程,因此基本上来说,你的行为事实上是在暗示其他的团队成员“你们也可以不跑到终点”。这种暗示的结果,是管理层变成了执行层。由此,原来的执行层变得效率低下,而管理层疲于奔命。你忽略了管理自身的价值,以及你作为管理者的工作内容,因而为整个的管理过程种下了恶因。
对于团队来说,“解决掉一个技术问题”,远比“团队的整体行进”次要,因此你不要冲在前面披荆斩棘——把这件事交给技术经理去做,或者教而习之,由成员自己去做。你首先要明确自己的责任是“整个团队的目标”。
如果你真是好的教官,如果你关注于“整体的目标”,那你就应该早早地发现整个团队或某个个体存在问题的“原因”,而不是等到有人倒下,才去解决“跑不动了”这种问题的“结果”。大多数管理者并不是因为能力不够而做不到这一点(哪怕这看起来好像是“未卜先知”的神术),而正是因为你过于陷于实施,无法履行你的监督职责——因为你不可能监督自己。
应该记住管理者的责任也包括“监督,发现问题并防止扩散”。因为要主动给自己留下时间和空间来发现问题,在问题出现之前定位它、分析它,并组织人力去解决它,而不是:
等到问题出现之后再去冲到前面;
然后在还没有清楚地意识到问题的根源时就试图解决之;
最后刚解决了表面问题或者侧面问题,又发信啊更多的问题挡在前面;
最后之最后,你垮掉,团队也垮掉。
记住“你不是团队的腿”是一个最好的起点。但是,这并不妨碍你成为团队的跑腿。如果需要,你不妨真的去买几杯冰水。你也不妨从这杯冰水开始,思考管理一个团队的方法与技巧。
三鼓而竭
“三鼓”这样的傻事大家都经常在做。例如老板请吃饭,几次下来大家都习以为常了:又如月奖、年奖、项目奖,到后来就都成形式了;再如开会痛说革命家史,员工心里说的是:“该的呀,谁叫你们创业呢”。凡如此例,多数败在这个“三”字至上。太多频繁的、一成不变的激励,其实是“鼓而鼓之,不复闻焉”;鼓得大家都听不见了,也就失去了激励应有的效果。
这还是外力的“鼓”(激励),大不了是让人觉得厌烦或者无视而已。我们下面来说另一种情况。
我知道有很多管理者习惯否定别人的想法,而不是肯定之。这个问题的根源,一般是由于管理者从技术出身,因而总是主观地认为自己“有更加绝妙的想法”。但是,不管你的想法是否真的“绝妙”,从管理的角度来说,这种“否定别人”的做法,其实是一个非常愚笨的主意。
这源起于不同角色“做事”的态度:管理者做事是不怕不做,怕一步错,步步错;而开发者做事,则不怕做多,不怕做错,最怕不做。这种差异,形象地说,就是“管理者是老绵羊,开发者是愣头青”。然而,如果老绵羊又正好是摔了一头包的愣头青,或者自己认为比别的愣头青更有思想的愣头青,那么他通常就会站在别人面前,说“你这样行不通”。
然而这样的管理者无形中忽略了两个问题:
如愤青一样,愣头青之所以“楞”,多是因为激情之故。然而少了激情,再正确的决策也难以有效实施;
“行不通”只是你对事情的评估,而不是实施过程中的观察。因此“行不通”三个字难于说服于人,也未必真就如此。
这两个问题,一个是说“请当如此”,另一是说“理当如此”。为什么这么说呢?我们先来看看这个愣头青在做这件事时的情绪因素:
首先,他与你讨论,就证明他积极地关注这件事,这比漠不关心、人浮于事要好;
其次,他能够“有想法”,这证明他已经主动地在事件过程中发现问题,比视而不见的人要敏锐;
接来下,他敢于向你“提出”想法,这证明他能够打破管理边界,向上层管理层主动沟通,这是团队中的良好品质;
再下来,他能够“主动”寻求解决问题的手段,这证明他能够独立思考,并且比别人更有主见。
一个人如果具有“积极、主动、敏锐、勇敢、主见”这些良好品质而不被认可,那么无疑是令人沮丧的。久而久之:
他会自我否定,并学会放弃,再也没有勇气提出任何东西,变得人浮于事;
你将继续听到更多的(似乎是无以穷尽的)意见,他勉力抗争直到你改变或者他离开。
第一种结果:你牺牲了一名优秀员工,而成就了你的自负。第二种结果:鱼死网破。
根本上说,“怎么做一件事”是一个人的态度问题、性格问题、品行问题。团队成员能有点想法,本身就是值得提倡的:想法成熟,则对工程进展有推动(如改进工程技术、方法);想法不成熟,善以用之,则可以对团队建设有推动(如进行团队教育、激励)。因此,万不可据“意见(或想法)”于千里,把团队“自下而上”沟通的道路给堵死了。——你在牺牲团队成员的同时,也失去了建设团队特质的机会,二者之任一,都是你作为管理者的失职。
现在开始,你不妨把这个愣头青看做愿意“贡献集体智慧”的表率,从他开始,为团队内部的积极沟通带个好头。至于接下来如何讨论:认同他、引导他,或者说服他,那才是“理”的问题。
态度可以认可,至于“想法好不好”是技术问题。你不宜急于表态,因为团队中还有“头羊”,还有“精神领袖”,实在不行,还有“聚室而谋曰”。(即使所有的讨论结果都倾向于对这名员工的否定,你任然可以给出一个机会来让这名员工去自我证明。这种机会可能只是几个小时或者一两天的技术探索。这种情况下,如果他能证明他的正确,那么他会感激这次机会;如果结论是他错了,那么,你无形间树立了自己的威信——这件事,只是说“不”,是做不到的。)
不做,其实是对积极性的一种抵消。我们知道愚公都有“实现的欲望”,好容易有天生的“士气”,一鼓再鼓之下,向管理层提出“想法”来了。管理者一句话就“打死”。连尝试的机会也没有,连知错而改,改而渐进的可能都不存在,从而空耗了人家的士气,久而久之,数鼓而竭,这个人也就没有新思,有新思也没有提出来的勇气,有勇气发成牢骚,却再也没有情绪去实施了。
然而,这不正是大多数公司无效率、无创新的根源吗?
先人后已
大多数的管理者总是要么在开会,要么在订计划,要么在做一些协调工作。。。表面看起来不是很忙,但着实繁杂。如果一个管理者是做技术出身的,那么他可能还需要有一些时间来深入技术,试图做一些或自己感兴趣的,或对团队有益的,或别人难以完成的工作。总之,我想说的是,如果你是管理者,那么你总是很忙。
让一个管理者向别人说“忙”,是一件很惬意的事。“有得忙”才证明重要,成天无事可做的人,存在的价值(起码看起来)也就小得多。所以多数管理者试图从一早到公司,就让自己显得“很忙”。然而,先不论这种状态背后的心理因素,管理者一定不要忘记在开始“忙”之前做一件事:驱动你的团队。这就是我所谓的“先人后已”。
很简单的算法:如果你忙一天,也就是一个人的工效;如果你的团队(例如20人)一天都在忙,那么会有20个人的工效。即使他们每个个体都不如你一样地能干,工薪也没有你高,但是只要能驱动整个团队,20个人的工效终归大于你,(日薪的)投入与产出比也终归是大于你的。因此从管理学上来说,推动团队比推动个人要经济得多。
你有没有留意,你早上到公司的时候,你的项目经理有没有来找你说点儿什么——或者你就是项目经理,那么你去找过团队中的成员吗——当然,我不是说问问“早上好”或者“昨晚的球赛看了没有”这样的闲话。如果他“先人后已”,在开始自己的工作之前就来招呼大家了:安排每个人的工作,或者解决某些人的问题,那么这会是美好的一天。然而如果他总是等到发现很多人无所事事时,再来找大家的茬儿,那么这个项目经理离离职也就不远了——当然,也有可能团队会面临解体,他的项目经理自然也做不成。
这个“让影像到别人的事先做”的思想,与“团队高于个人”的观念是一致的(只是后者听起来有点学究和政治,因此德育课老师也许曾经给你讲过这些,但你当时听起来总像是在唱高调)。然而有很多人、很多时候不能分辨一个问题是自己的问题,还是团队的问题,因此也不能正确地决策其先后。这种情况下,我只建议你装得自己很闲,或者希望忙里偷闲,问问自己:“如果这件事不做,会如何?那件事不做,又会如何?”找出影响面最大的一件,交给别的人(或者大家)去做,而自己做“不是太重要”的那件事就可以了。
更退一步地说,即使你什么也不做,也比整队人都停下来要强得多。
即便如此,也还有一种“先人后已”是你容易忽视的:奖励,也要先人后已。
管理者说:我们的工作量未见得多于程序员,而薪水可能比人家要高,并且重要的是,我们站在管理的前端,能得到的机会自然也就比别人要多。团队成员其实比我们付出得多,而得到的更少。因此,我们应该把荣誉真实地回馈给团队,而不是贪为己有。
例如对评选“优秀员工”,名单中没有自己的时候,有的管理者是“不在意”,有的人则认为“不错”。
“不与下谋利”或“让利于人”是管理者的团队意识的体现,“不在意”是一种无视或妥协,而“不错”则是一种主动的认可。做事时固然要“先人后已”,面对成功与荣誉时也要“先人后已”。前者得以完成团队建设的重任,后者则表达你对团队价值的认可。
自相矛盾
如果团队中没有“问题”,那么看起来就不需要有管理者了。
温伯格在《你的灯亮着吗?》中说“问题其实就是你期望的东西,和你体验的东西之间的差别。”简单的说就是:你认为这是个问题,它就是个问题。
这是个自证的逻辑。
乔丹举过一个例子:有个球员发誓第二天的比赛要打好,结果第一次投篮失败后,他就开始流露出迷惘,消极的念头一个又一个聚集起来。而乔丹则不会担心后面,还没投,干吗就担心投不中呢?
你怎么看“一个问题”呢?“这个问题”是不是问题,取决于你对问题的观察角度。换而言之,你所投入的关注是否正确:普通球员关注于眼前的得失,所以看到了失球的“问题”;乔丹则关注于比赛的得失,所以看到了得分的希望。
所谓矛盾,多数是自找的。
矛之所攻者,敌;盾之所御者,敌。你不拿矛、盾来攻御,却在这里互博,岂不是自己原本就把命题设错了?
命题设错了,就成了问题了。
很多团队都有这样那样的矛盾。例如员工与员工的、员工与老板的、进度与质量的、技术与市场的。。。你会发现,你总是在利益、正误等这样的问题之间权衡,这些选择带来了你的痛苦:也就是我们所说的矛盾。
换而言之,你的“认识”决定了问题,你的“选择”导致了矛盾。
之所以“矛盾”看起来也是一种“问题”,是因为矛盾通常是你无法取舍、无从选择的感觉——这种感觉来自于“你期望选得更正确,但你感觉你无法做到”。
“要想解决问题,要么改变期望,要么改变体验。”使得,你现在就可以“放下”,改变你的体验(的需求),从“不要认为这个矛盾是问题”开始,重新设定条件。例如:不要用矛来击盾,而是用矛、盾以击敌。如果,岂不是可以尺长寸短,尽可用之。
所以学会否定矛盾、消化矛盾,看到矛盾产生的内因、外因,转而借之用之,才是解脱的方法。
从编程到工程
语言只是工具
程序=算法+结构
=>方法(面向过程/OOP/MDA)
=>过程(RUP/XP)(模型与模型语言)
=>工程(需求管理)(过程管理)(配置管理)(文档化)
=>组织(管理、计划)
关注点
上图是EHM,Engineering Hierarchy Model,工程层状模型。
实现
关注于“(具体的)实现”
程序=算法+结构
方法(面向过程/OOP/MDA)
团队
关注于团队的问题
过程(RUP/XP)(模型与模型语言)
工程(需求管理)(过程管理)(配置管理)(文档化)
组织(管理、计划)
从角色的角度上来说:开发经理思考项目的实施方案和管理具体的开发行为,而项目经理则保障团队的稳定性和一致性。
程序
EHM模型图中,最内层是“程序”,这是编程的本源定义,也是原是的状态。愚公在数千年前就在用类同的行为做编程实践,而几十万年前的智人,也在循环与分支所构成的逻辑中打转。
方法
推动这种逻辑向前发展的,是“方法”和“方法论”的出现。长期的编程实践,自然的归演与总结,必须沉淀为某种(软件开发)方法,于是“过程”出现了,于是“对象”出现了,于是相关的方法论也就出现了。
这是实践的成果。方法不是某个人或者某个组织创造的。瓜熟而蒂落,实践积累达到一定的程度,微软不提出某个方法,IBM也会提出这个方法。即便他们都不提出,可能你自己已经再使用这个方法了。
方法并不神秘,因为它就是你今天正在做、从事的和实现的。正如“模式”是一种方法,而模式就是你昨天书写代码的那个行为。只不过,GoF归纳、抽取、提升了这些行为的内在规律。
你看不到你做事的行为,也就不能理解“模式”作为一种方法的价值。所以大师们众口一词:模式需要一定的编程经验才能理解。
同理,理解过程也需要编程经验,理解对象也需要编程经验,理解MDA(模型驱动架构)与SOA(面向服务的体系结构)还是需要编程经验。
——这可能就发生在你去回顾你的上一行代码编写的经过,或者上一个项目失败的经历的那一瞬息。经验来源于回顾、理解与分析,而不是你将要写的下一行代码。
过程
最狭义的工程,是描述“做什么”和“做到什么”。
也就是说,是对目标的描述和成果的检测。至于这个工程目标的实现,是“过程”和“方法”的事;而有效、快速地实现“过程”和“方法”所需的,就是“工具”。
过程伴随工程而出现,解决的是工程中“步调一致”的协作问题。
软件的不断增大是根本原因,项目的“复杂”可能要求不同知识领域的角色参与,而“庞大”则要求更多的(人力、技术与管理)资源。“团队”作为开发行为的模型,是软件规模和复杂度渐次累计的结果。
团队必将越来越庞大,因为(与工程对应的)软件必将越来越复杂。没有团队意识的软件公司在高度过程化、通晓方法论、拥有大量工具的集团军面前,必将一触即溃。
组织
在EHM模型中,工程关心的是“需求”、“配置”和“文档”等这样一些要素,那么这样的工程还是停留在技术层面的:关注的还是工程的实现细节,而非目标。从角色的角度来看,这是项目经理和技术经理所共同关注的那一部分。
作为那个解结的人,你应该知道这个EHM模型中的需求管理决定了你的阶段性目标,配置管理决定了你检测的方法,相关的文档化工作是沟通的渠道,以及协调团队矛盾的手段。“需求”、“配置”和“文档”等不仅仅是你每日一成不变的、模型化的工作步骤,而且也是解结的工具与方法,或者是你实施管理思想的道具。
此外,你(项目经理)还必须关注于人力资源、项目资金及多个项目之间的协调等。这些与工程本身并没有直接关系,而是“组织”方面的内容。
所以在工程环节中,“文档管理”和“配置管理”等中的那个词汇“管理”,是管理的具体技术和方法;而在“组织”这个环节中的这个“管理”,才是真正的管理学上的用词。
作为管理者,你可能绝大部分的工作是非技术性的。你必须更关注于对这个(或这些)工程的组织与计划。站在“组织者”这个角色上,你现在要考虑的内容可能会是:
为项目的各个阶段建立计划,并逐渐地细化计划的内容,以及确立项目过程中每一个环节、每一个计划阶段的优先级和复杂度;
确立项目或者产品阶段目标,成果的准确描述、定位,以及整个项目的质量目标及其评核办法;
对团队中的不同角色展开培训,以指导并协调角色间的工作,从而消除因为工作习惯的差异带来的影响;
为每一个人准备他所需要的资源,这不单单是一套shareware变成正式版或者把512MB内存变成2GB,还包括准确地评估他的工作量,以及决定是否为他增加一个(能协同工作的)副手;
决定在哪些环节上反复审核和回顾,而在哪些环节上采用较为宽松的方式以加快进度;
习惯于开会、组织更短而有效的回忆,以及建立激励机制,当然也不要忘记让每一个成员意识到这一项目的风险;
不要乐观。
即使你做好这一切,可能项目的结果任然不够理想。但是你应该知道,好的项目经理并不是不犯错误的人,而是以尽可能少的失败来获得成功的那个人。
无论是你的团队成员,还是你的老板,对重复的错误以及可预料的错误都是不会宽容的。——在一个团队中,失去了组员的信任比失去老板的信任更可怕。
所以回顾每一个项目,或者项目中的每一个阶段,以及每一个团队成员交流的细节,是你的日常工作。
BOSS
很多人认为BOSS是给自己发钱的那个人,这其实是错误的。发钱的决策通常是由以下三个角色来做出的:
部门/团队经理:你的直接上司,他是雇佣你的人,是他用薪金的多少来衡量你的价值,或者反之。
绩效经理:如果你的公司有这个角色的话,那么他总是盯着你的错误以及决定你薪水的扣除比例。
财务经理:有钱?没钱?没钱?有钱?。。。
BOSS并不决定你的薪水。
BOSS在公司中解决的是“经营”问题。这其实是在比“组织”更靠外侧的一层——在前面的图例中并没有给出,这也意味着“经营者”与“工程”基本没有关系。
在一个更大规模的组织机构里,你可以更直接地观察到“经营者”与“组织者”之间的差异。例如公司的大小股东是“经营者”,董事会通常是解决经营问题的地方;而总经理、执行经理及各个部门经理则是各级的“组织者”,经理办公会则是解决组织问题的地方。
你应该清楚,真正的BOSS是经营者。
这有助于你明确你被雇来的原因,你的工作是面向哪一个层面的,以及你或者你的上司有没有权限来决定一个项目是否应该立项,或者中止。
BOSS(经营者)决定了一个方向,组织者保证决策与这个方向是同步的,而工程是在这样的一个方向、决策的构架下的一个具体行为。
工程中没有BOSS。
上帝之手
基于某种数据结构的编程实践(的不断积累),决定了软件开发方法理论的产生。可以看出:方法,是对既有行为的归纳总结。因而实现方法总是最先出现的,而后才有分析和设计方法。
可以看到面向对象分析(OOA)、设计(OOD)与编程(OOP)的出现顺序,与它们在工程过程中的实作顺序正好相反,而与编程实践行为的顺序则正好相同。
为了实现更大规模的软件系统而有了团队组织模式,而团队的协作决定了过程模型的产生,在过程环节中的沟通问题导致了(模型化)语言的出现。
如同编程工具中的编译器和集成开发环境(IDE)一样,开发中的编程语言、过程中的建模语言都只是一种工具。
工具的产生仍旧是出于“(软件)实现”的需要。不可能从软件开发实践中产生出轮子和指南针,因为那不是“软件开发的本质需求”可以推动的。
软件工程的体系中,“实现”作为软件开发的本质需求和基本动因,如同上帝之手在推动这几十年来的软件工程理论体系的形成。
工具
方法
过程
实现对象(基本动因)
你看得到工具的本质吗
利器何以为先
铁比铜坚硬。在春秋战国时期,燕国的铁剑,锋刃部分已经达到了今天高碳钢的硬度。但是,从兵马俑坑中出土的四万件兵器中,几乎全由青铜铸成。大家都知道:秦国用武力统一了中国。
是铁剑砍不动铜剑?当然不是。
从史料和实物中,可以发现:秦军的青铜剑比其他国家的更长。产生这种需求的原因,可能与一众实战技法有关系:以相同的力量,刺比砍更致命,刺死砍伤。
高明的剑士是不会用剑去砍的,剑刃多数拿来削苹果,真正有效的是剑尖。因而长的剑可以更容易刺击到敌人。
无缘无故地产生一种更加“费工费料”的兵器,在战争史上绝无可能的。因此秦军应当有相当的实战技法,来发挥这种长剑的优势以击敌。这种技法,与剑本身是铜是铁无关,与剑刃是锋利或钝拙也无关。技法产生了“长剑”的需求,进而把长剑的优势发挥得淋漓精致。最终 ,铸剑技术不敌燕、楚的秦国,却灭了燕、楚。
由此可见,使用工具的方法,比工具本身更关键。所以“欲善其事,先利其器”这样的言论,未见得是全对的。
神乎其技又有什么用呢
然而,非但最坚利的剑不出在秦国,连最高明的击剑技艺也不出在秦国。
先秦历史中,最有名的剑术家当数在越国论剑的越女等等。
翻遍先秦史书,你会发现这种奇怪的现象:无有死士是秦的,无有铸剑名家是秦的,也没有什么技法通神的大剑师是在秦国的。
在例如卖油翁的故事,回顾一下,卖油翁的技法再高,也无过于将油从更小的钱孔中注进去。他永远不会想到两件事:
油其实只需要装到壶里,从不从钱孔中注进去根本不重要;
如果买油者只是因为欣赏他倒油的技艺而买油,那么他就根本不需要卖油,厅众之下献艺即可获利了。
秦无剑技而一统天下,宋有康肃而痛失半壁!不知用法,不知用处,如同那习得屠龙之术者,神乎其技又有什么用呢?
工具的本质
真正让秦国强大起来的,并不是工具或者技法,而是在近三百年的战国中期才开始的商鞅变法。
秦国并不看重剑的材质,以及过于复杂的、艺术化的制剑方法。秦国关注于剑的长短特性、青铜工艺的成熟度,以及弓弩部件的“构件化”,本质上则是基于他们对“战争全局”的理解:如果只是个人喜好的玩物,而不是大多数人能得到的兵器,对战争有何益呢?
再来看看越女的剑技,与秦国的战术之间的区别。越女之技,未论及剑刺于何处,剑行于何方,无招式方法,是一种理论、思想。而秦国的战法则简单快捷,就是:快速奔袭,一剑刺敌,枭首而进。
工具的使用,一旦上升到“技艺”、“方法论”的高度,就难于理解掌握了。如果战士们都要花数十年来悟剑,那么还没等它悟成,国也就灭了。因此,秦国不看重“同时舞弄七把剑”这样的技艺,而注重能否以剑尖快速地刺杀敌人这样的技术。实在是秦国的用兵者,深知实战技法是一,论道传艺是一,不可概而论之。
如同工程与编程,单以编程而论,讲究技法之精妙,追求细节与枝节是可以的;但对于工程来说,能让团队理解、统一执行、迅速有效的实战技法,才是真实所需的。就像战争一样,团队化的工程中,技法的优劣并不是关键。关键在于某种技法是否能为团队带来整体的成效,而不在于某个人是否喜欢,或者深谙于此。如同陈康肃公,有当世无二之技,不能用于“群战”,也是无益。
秦国把战争当成数百年的工程,因此并不仅仅关注工具与技法。事实上,秦国是典型的以法治国的国家,因此与战争相关的所有活动,例如军令如何传达(兵符制度)、兵器如何补充(兵役制度)、士气如何激励(军工爵制)、后勤如何保障(耕战制度),等等,都有法令规范,都可以付诸实施并检测成效,进而在工程的整个团队(军队)中推而广之。
在这其中,兵器只是作为一种征战的工具,在秦军中起着相当重要的作用。但秦国并不迷信兵器,而是把兵器作为工具取而用之,并透析剑、弩等武器的本质,了解具体特性的成因与功用,进而规范成方法技术(而非技法技巧)。这些构成了秦军的军事基础,成为战争——这个浩大工程的组成部分。
工具之于工程,本质在于关注并发挥有益于工程全局的那些特性。一人一技,一器一物,又岂能是工程的要义?因此,我们最终看到拥有利器巧技的六国都不在了,最后只剩下了一个强秦统一了天了。
惟手熟尔
很多的高手,对于工具的本质并不是了解的。他写程序快,只是记忆中读过的、写过的代码多于别人;他思考问题比别人细致,只是因为他有过比别人更多的错误;他能带领项目团队,只是因为他经历过足够多的项目团队。
这样的人可以算是能人:有能力的人。但未必真有见识,真有才略。
我们看到:卖油翁一生卖油,临老了只得了四个字“惟手熟尔”。一个人的经验与技术,如果到了“手熟”的程度,便也就进无可进了。
浸淫于技法越深,便越容易忘记使用这种技法的最初目标和应用场合——就如同陈尧咨仅仅把射箭看成技艺,而看不到它作为战场武器的本质;亦如同卖油翁一味演练技法之高妙,而不考虑卖油才是目的,而技法只是表面。
鲁班带了个坏头
传统上,我们习惯于把工匠分成两类:器匠和技匠。前者“工而制具”,注重对新工具的发明创造;后者“工而制艺”,注重对工具更娴熟的、有创建的运用。两种方法都可以提高效率或提升品质。
鲁班给工匠们带了个坏头,他的成就掩盖了工程的诸多真相,使工匠们将视线停留在工具的构造之上。人们将具有这种品质的工匠称为“良匠”。
“称为良匠”因此就成了工匠们的目标。但这个目标中却没有“完成工程”。从本质上来说:他们更关注于“使自己称为良匠”的工具与技法。
鲁班这种典型的“工匠思想”,总结下来有三个问题:
以良匠之名为目标,而不是以做工程为目标;
以工具之利为恃仗,却不关注工具用在哪里;
以技法之巧为较量,却不知技法应为团队所用。
现在来看,这不都是大多数软件开发人员(和技术人员)的问题吗?
工匠思想
软件开发圈子中,持有这种“工匠思想”的鲁班门生历来不缺。只不过大多数人把这种“工匠思想”的来源看成“八九十年代的个人英雄主义”。他们认为这种思想是一种现象的延伸,而不认为是一种“开发人员的本质特征”。
鲁班的虚名,给工匠们设定了用以安身立命的目标:成为良匠。我尽管要说,这是一个坏的表率;但也要说,这的确是好的品质。
不同的工程角色的确应当有他自己的关注点。这个角色能考虑到别人想不到的问题,固然不错;但如果他格尽职守,只关注自己的那一部分,也是本分。
在EHM图中,工程体系的第一个关注点是“实现”。也就是说,你可以是“关注于自己能否成为良匠”的工匠,但是作为工程角色,你起码应该关注于“如何实现”。放在项目中,具体的要求其实就是:一项技术是以完成工程需求为目的的,而不是以彰显个人技术为目标的。
对于管理者来说,重要的并不是“让大家都关注工程的每一个方面”(这事实上也做不到)。工程管理者应当认识到开发人员的“工匠思想”的本质,并加以善用。如同我们前面说的,你认为工匠思想“是个问题”,它才是问题。
某些开发人员都是编程高手、技术尖子,因此一些管理者想“发挥他们更大的作用”。于是将它们提上高位,许以“经理”、“副总”这样的职务和职责。但这些人要么工作不得力,要么工作不开心。最终工作没有做好,员工也没有得到激励,反倒破坏了组织结构。
在很多公司看来,“当官”可能是对员工的最大激励。然而身处官场的人又如何能理解技术人员的思想呢?其实很多的开发人员,无非是追求更宽松的工作环境、更好的学术研究氛围。换而言之,他们根底上就是关注于工具与技法的。
如果公司不能利用这些“本质特性”,非要设定他们的“仕途”。那与以矛击盾有什么区别呢?——我们说过,大多数矛盾都是自找的。
公司应当给出员工“在技术方向上的发展路线”。很多大公司在这一点上其实做得不错。他们把技术职级与管理职务分开,使得技术人员可能通过技术提升来得到与管理者相近同的薪酬。但事实上,管理者整体的薪酬总是高于技术群体的,因此薪酬的激励终归有限。对于开发人员来说,吸引他的是无限的发展空间。
“必先是匠人,之后才会是艺人,再之后才会是艺术家。程序员就是程序员,如果不静下心来做代码,好高骛远则终将一无所成。”
“志存高远而脚踏实地,此实地者,源码也。”
在每一个开发人员的心中,其实都有一条“成为良匠”的道路的。然而在我看来,匠人、艺人、艺术家是唯一可行之道。技术容不得取巧,只能点滴积累。所以程序员的“工匠思想”,落到可实践的方法上,就是代码。他要么顺着代码铺就的道路,亦步亦趋地成为良匠大师;要门就看透工具的本质,把关注点转移到“团队”的圈子里去。
我们应该看到,“静下心来做代码”是开发人员的良好品质。因此,作为开发人员,我们不应当妄自菲薄;作为管理人员,我们更应该善而用之。
化而用之,融通与融同
一个人能到举一反三、闻一知十,是因为他能把知识融化汇合,因此得到全面的理解并升华。所以融通的前提,就是消化。化而用之是融通的结果和状态。
开发人员必然会产生对开发环境、语言等的依赖。
在使用工具的表面上越来越规范了,并没有真正地解决“工具之用”的问题。
习惯性思维是开发人员的通病。
语言间的差异越来越小,而至于此间被开发界争论不休的“编译语言好,还是解释语言好”,或者诸如“C#语言好,还是Python好”之类的争论,我都只一笑置之。
工具之用,到了融通地步,也就无所谓“选择哪个工具”了。但是所谓融通,是基于对工具背后思想的了解。如果不了解OOP,那么Delphi、Java与C#每一座都是高山大壑;反之,则可举一反三,触类旁通了。
在OOP之后,我面临的另一个障碍是“Interface(接口)”。在Delphi中,Interface的作用与价值,被OOP掩蔽得很深,再加上Delphi开发COM、Web Services等项目有自身的劣势,因此我最初理解Interface的时候,几乎茫无头绪。这一切,是直到我开始了解UML时,才醒悟的。
因为我发现UML并不需要做CODE(现在看起来这句话真的很好笑)。而“做不做CODE”,其实就是Interface与OOP的本质区别。例如UML中的接口,并不表明它的后面一定是类,或者一定是某个特定的类的实现。但类的设计,却可能与某个确定的对象实体相关,设置会因不同的编程语言、开发环境而不同。
之所以很多开发人员不喜欢Interface,实在是因为它与具体的“实现”距离得远了一点。而正是因为这“远了一点”,就使得很多开发人员跳不出语言的窠臼,理解不到Interface对于设计的意义。
我开始了解Interface之后,才真正地有了“软件设计”的观念。而一旦有了软件设计的观念,“实现”的过程,就变得越来越不重要。
在一个(可以被实现的)设计面前,用什么工具去实现及实现的具体过程,其实是非常无趣的。我曾经有一段时间把这种无趣称为“痛苦”。直到我放下“有趣”与“无趣”的衡量,把“实现”看成是一个项目或工程所必需的结果时,才发现我触及了软件开发的本质,我才感叹:语言只是工具。
从那以后,我再也不津津乐道于某种工具或者语言。
真正做工程的人,只是简单地说:不平,刨之;不直,斗之。至于刨和斗是不是某个思想家、理论家或实践家来发明的,与用不用它,没有关系。
然而,大多数人会谨守“不平,刨之;不直,斗之”的原则,不会赞同你把工具拿来“换个方式用”。是的,这并不是合理的做法。但在我如今看来,这个工具的“样子”是不是“刨”或“斗”都不再重要,只要能完成所需要做的事就行了。
更“可笑”的是,我甚至会用PowerPoint来替代Delphi写代码。。。
“写代码”并不是解决问题的唯一方式。如同PowerPoint和Visio一样可以帮助你完成软件原型。所谓“融同”,大抵如此。“融通”与“融同”的区别在于:前者是以一通十,有运用变化的能力;后者则知工具之大同,信手而得,随心而用。
——无所谓是什么,只在乎它能不能用。一个工具无比强悍,但你可能只用它来输入几行代码。那么你输入这几行代码就可以了,关注它那些强悍的功能干什么呢?如果你不再关注它那些强悍的功能,那么它与一个记事本又有什么不同呢?
融通是基于对“使用工具的方法、理论”的了解;而融同,则是对“这个工具存在的本质价值”的认识。所以在我看来,UML不过是工具,RUP也不过是工具。工程实践中,用或者不用UML、RUP等,仅取决于工程本身的需要,而不是取决于喜好,也不取决于现实中的大公司与外来布道者的鼓吹。
于某时某事,适用的就是最好的。前提是你要有看明白这些工具实质的能力。只要能够分辨出所需的部分并适度地用在你的工程中,就可以了,何必把它看做救世良药,一味传道布道做信徒状呢?
融通而后融同,化而用之是对工具本质价值的尊重而非轻视。反过来说,迷信工具者,便如同食而不化者,总觉腹胀如鼓了。
南橘北枳
秦朝之后的剑技已经发展到非常高的境界,但是从西汉开始,主战兵器反倒变成了刀。一方面,因为剑的习练相对难些,刀则沉稳简练,更适合集团性战斗;另一方面,在汉之后,中原的主要敌人是北方游牧名族,骑兵交战中以砍为主,很少有刺的动作。
由此可见,没有一成不变的理论,也没有一成不变的因果。如同南橘北枳,换个场景,连事物的本质都发生了变化,更何况乎工具的形状和功用呢?
在《你的灯还亮着吗?》书中,温伯格看来,是“每种解决方案都会带来新的问题”,但在我看来,则是“变化带来了新的需求”。
因此,工具“被如何设计”的本质,就是为了应对“不停变化的需求”。而被重新设计的工具,又产生了新的“用法”。所以追根溯源,工匠们的思想,就都被禁锢在这生生不息的“变化的需求”中了。工具也因为这个工程而变得越来越复杂,似有万般功用。
然而对于确定的项目来讲,只有对这个项目有用的那些“功能”,才是这个工具的价值之所在。所以,识见到工具“设计”所满足的那些“确定的需求”,进而明确工具与项目的关系,才是解脱之法。
现实中的软件工程
大公司手中的算盘
大公司们在标准、理论、语言上的争来夺去,未必全然出于“软件实现”的考虑。对统一理论、统一工具、统一过程的企图,其最终目的是在整个软件工程体系中的全面胜出。
思考项目成本的经理
思考如下的问题:
项目的管理到底是组织管理还是成本管理?
项目的计划到底是组织规划还是成本计划?
简单地说:项目管理要不要考虑成本问题?
现在,让我们从一个细节跳出来,来看看我们的角色。这个细节就是:如何完成今天的工作。
正如前面所说,如果你是一个软件公司里的项目经理,你今天的工作可能是写一份项目计划案,或者听测试部的报告,又或者是安排会议来听取和分析一个新的产品需求。然后,我要说的是:这是细节。
细节就是你使用的Project2003,或者你正在公司内部署和推广的CleadCase。如果它们正好是你今天要完成的工作,或者是你明天要用来工作的工具,那么,作为项目经理的你,现在就要立即跳出来。
理想状况下,“软件工程=过程+方法+工具”。然而工程成功的真正关键,并不在于你把你的团队“组织”得有多好。即使在团队中他们都表现得有条不紊,你一样会面临失败。
蚂蚁的团队总是被本能地组织得非常好。然而如果一个蚂蚁的群体中有了流行疾病,蚂蚁在死去,而新生蚂蚁不能跟上其死亡的速度,那么很快,这个团队就崩溃了。
这是因为蚂蚁用于维护团队运作的“资本”在流失。如果资本没有了,就没了运作,团队的存在就没有了必要性和可能性。
项目就死亡了。
埋头于画甘特图的项目经理犯下了与挖山不止的愚公类同的错误:忽略了成本。
如果愚公真的可以成功,那么可能是300年之后。然而如果一个工程要300年才能做成,那么在做成之前,客户就选择了放弃。
如果有机会,项目经理可以选择向另一家公司购买一个产品来卖给客户,从“为客户开发”变成“为客户定制”,以及“为客户服务”。这样在没有任何开发成本的前提下完成了工程。与另一个同样极端的例子相比,你会发现它与第五章中那个“做过场”的项目全然不同。后者是做完了工程(的全部过程),却没有做成工程。而现在这个项目经理却做成了工程,但是在许多的过程环节上,他根本就没有开始。
然而现在,除了跃跃欲试的技术经理之外,没有人会不满意这个结果。
技术经理最常说的话是:我们可以开发出来;开发人员最常说的话是:我可以开发出来;愚公最常说的话是:何苦而不平?
还记得那句话吗?——不要栽进蚂蚁洞里!
愚公如果停下来,思考的问题可能是碎石的“方法”。而项目经理从细节中跳出来,思考的问题就应当是完成工程的“方法”。评价这个方法的好坏的标准只有一个:节约成本。
记住以下教训:
不计成本的项目计划不会得到经营者的支持;
毫无目的地消耗成本是项目中的慢性毒药;
最致命的风险是成本的枯竭(我经常注意到的成本因素包括时间、人力、资金和客户成本。而大多数情况下,人们不会把客户的数量及耐心当做(客户)成本来计算。而在我的项目规划中,这是成本)。
审视AOP
开发方法是基于一种数据结构的编程实践的结果。很显然,OOP所基于的数据结构是对象(Object),而AOP所基于的数据结构就是切面(Aspect)。落足到开发工具的实现上,Delphi将Object表现为一组有(继承)关系的“记录”。相对应地,Java则用类(Class)来实现Aspect。
Aspect在定义时没有确定的对象模块,Aspect本身只是对一个“对象模块群体”的观察视角,因此它更易于表现成接口——只有描述而没有实现。
在Object一层的抽象上,Object关注于“有继承关系的考察对象”的个体特征;而在Aspect一层的抽象上,Aspect关注于“有相似需求的考察对象”的群体特征。其相似性在群体中表现得越广泛,则AOP的优势也就越明显。
到现在为止,我们弄清了AOP作为“思想、方法、工具”的一些基本知识,以及它的应用范围:至少你要明白,它是用来考察对象(而不是设计对象)的思想方法。
所以接下来AOP的三个概念我们就明白了:
指示(Advice)/拦截器(Interceptor):考察这些对象以“达到什么样的目的”(即需求);
引导(Introduction):在目标上实现这些需求时,目标所需要表现出来的公共特性,引导特性可能需要配合编译器来实现;
元数据(Metadata):如果需要,为既有对象实体再补充一些参考数据。
确切地说,切分点(Pointcut)并不是AOP编程方法所需要的概念,而是AOP作为一个框架去实现时所需要的一个工具:一组辨识Aspects和Objects的索引。
现在你已经会用Aspect的思想来编程了,而无论它是用Java来实现的,还是用C#、Delphp,乃至于FORTRAN或COBOL来实现的。其实如同这里所表现的那样,学习任何一种新的编程方法,你需要做的仅仅只是回到工程最核心的那个环节:程序=算法+结构+方法。
审视MDA/MDD
MDA(Model Driven Architecture)也是一个方法论层面上的名词。它讨论的是“创建出机器可读和高度抽象的模型”的方法。受MDA影响的开发活动被称为MDD(Model Driven Development)。
与MDD在同一个层面上的概念是:TDD、FDD、BDD、R-TDD、CDD、RDD。。。
我不厌其烦地罗列这些名词,只想告诉读者一个事实:什么都可以“驱动开发”。
如果你仍旧不能明白为什么会有这么多神秘力量所“驱动着的开发”,那么你就干脆去厨房找个平底锅烧点热油,然后敲下一个鸡蛋,很快,你就会体会悟到“以蛋黄驱动开发”的真谛了。
抛开实现的技术细节不论,在工程中,“以什么驱动开发”其实是一个过程问题。而你应该明白,过程的选择(或制定)取决于你的工程需要,以及它在相关应用领域的适用性、过程工具的充备性和这个过程理论的完善程度,而不是大公司们的鼓吹。
审视AP和XP
XP是一种AP。也就是说,“极限(Extreme)”是达到“敏捷(Agile)”的一种途径,或者说“极限”的词义就是“极端敏捷”。我当然知道我这样解释XP与AP会被人骂成白痴。但我的确试图用最直接的眼光来看问题,并理解它——如果一个问题被理解得过于直接而“失去了技术的乐趣”,那可能在这个“问题”本身之上,就覆盖了大量的“技术尘土”,这才是使你看不到它的本相的根源。
如今业界一说“敏捷”,便会立即讨论它具体的方法论、过程理论和工程工具,或者干错把它的典型范例“极限编程(XP)”拿来讨论。所以看起来,在敏捷的旗帜下有着异常丰富的实现:众多的工程组织和团队都在说“我很敏捷”。
然而在我看来,这些都不过是“技术尘土”。因为真正的问题是:“敏捷”是什么呢?
开发人员多数有一种极端主义思想:好的要最好,精的要最精,全的要最全。无数人为了类似于“写出最精巧的程序”这样的目标而奋斗。而“敏捷”,看起来也就是这样的一个“目标”。
如果把“敏捷”作为目标,那么目标的具体衡量就是“敏捷性”的量值。而“敏捷性”的定义却没有编程中的数据类型那样精确。例如你可以问“这个数据类型占几个字节”,却不能问“你有多敏捷”。
衡量“敏捷性”的是一份宣言:“敏捷软件开发宣言(Manifesto for Agile Software Development)”。这份宣言尽管没有提供量器,却设定了衡量的对象。例如宣言说在开发小组中最有效率也最有效果的信息传达方式是“面对面的交谈”,所以你的团队是“面对面的交谈”,还是“书写一份文档”就成为“是否敏捷”的一个标志。但“交谈达到的效果”却没有衡量的依据。
事实上,“写文档”起码可以用页数和小组中签出文档的频度来衡量文档的价值(尽管不准确),但“交谈”的效果却无法衡量。“敏捷宣言”概而言之地说“这样就有了敏捷性”,其实是取巧的方法。
所以“敏捷软件开发宣言”根本并不能。也不打算让你去“衡量敏捷性”。因为连“衡量”这件事,在“敏捷者”们看来也是没有什么价值的——你最好直接与小组成员花点时间去解说并协助他们实现技术原型,而不是去“做一份漂亮的文档”。在“敏捷者”们来说,他们就认为前者是“敏捷的”、“有效的”,根本就不需要像下面这样去衡量:
文档页数是否满足公司规范;
文档规格是否符合RUP的标准;
文档是否被团队的所有成员签出。
——试图去衡量它,就已经使“事情变得不那么敏捷”了。
在“敏捷者”们看来,“(在实施中)发现问题比(在文档中)预测问题更实际”,因此“敏捷”起码看起来有点“经验主义”。也正如Scott W•Ambler在讨论“敏捷数据”时所提出的他对“成为敏捷软件开发人员”三个关键见解:
你不必非要做一个超人;
敏捷性其实只是一个思维集;
成为一名博学型的专家。
第一条就是强调沟通:找别人解决问题比自己解决问题来得迅速。第二条则说明敏捷的根源时学会思维而不是立即着手解决问题。第三条说明“知道更多”则更容易找到解决问题的方法,因此比“精通”重要。可见,Scott的三条见解都是围绕“如何解决问题”而提出的“敏捷方法”。
这些敏捷方法的核心之一,就是“寻找更有经验的成员来解决问题”或“使自己变得更有经验”。
类似的“解决问题的敏捷方法”还有《超限战》这本书。其中的一个例子是:打赢战争的方法,可以使兵力的对抗,也可以是非军事的行为(如恐怖活动、贩毒、破坏环境、传播电脑病毒,等等)。这根本上来说是围绕“取得胜利”这个核心问题提出的“敏捷方法”。
巧合的是,这两者所面临的争议也是类同的。因为“敏捷”更多的时候是一种“有驳传统”的理念。例如“敏捷软件开发宣言”陈述其价值观时,第一条就说“人和交互重于过程和工具”。这在本质上就是对传统工程方法学的挑战。因为“传统”:工程=(面向工程目标的)工具+方法+过程。
——当然,敏捷宣言还是为传统工程理论家们留了点面子。敏捷宣言在否定传统之余,也不忘记说过程和工具等“也具有价值”。
无论我们打算用怎样挑衅的词汇来对立“敏捷”与“传统”,我们也要看到二者的本质。“敏捷”所表达的其实是对工程目标的尊重,是对人的创造性和主动性的尊重。而另一方面,“传统工程”所代表的则是规范和规模化。
如同我在讨论“工具本质”时所提到的一样,无论多敏捷,如果具体的方法不能应用于“团队化的工程”,那敏捷本身就失去了工程价值。因此,为了应对“规模化”这个目标,敏捷宣言基于的前提是:工程团队认可敏捷的价值,遵循敏捷提出的价值观和基本原则。
敏捷宣言试图通过成员对共同契约的遵守来解决“规模化”的问题;而传统工程则通过制度、规范和确定的方法与工具来达到这个目的。从这一点上来看,这是“人治”与“法治”的区别,也是“敏捷方法是难以应用于大型工程的‘轻量性’开发方法”这样的观点的根源。从这个角度来讲,“敏捷”也是与团队文化相关的一种方法:如果你的团队原本就有它维护自己“规模化”的方法,那么敏捷宣言可能反而是一种破坏。
因此,AP以及它的核心思想“敏捷软件开发宣言”,是以实现、实施、实践为主要手段,以体现人本为主要内涵的行为准则。主要表达为:
一种人本化的、共有的团队特性与气质;
一种契约型的团队组织结构和领导风格;
一些以“解决问题”为中心的思想方法。
XP实质上是使团队遵循这些“行为准则”的一些“形式化的方法”。当然,XP在对一些工程要素的权衡上,也给出了建议和实践成果。但这并不是具体的过程理论,也没有逾越或颠覆瀑布模型。
“敏捷(Agile)”,其根本的思想就是用最快捷、有效的方法完成工程。因此,你可以把在(包括瀑布模型在内的)任何过程模型上、基于上述表达进行的开发实践都叫做“敏捷过程”。
具体工程
预言——《人月神话》及其地位
其实我们知道并没有预言未来的人,大多数时候是两种情形导致的假象:
他做出了正确的判断;
你主观地跟从了他对未来的设定。
后者是危险的。大师们预言了未来也就改变了未来,即便未来未必“应当”如同他所预言的那样。
我们应该清楚:现象之存在与是否被发现无关。例如苹果从树上掉到地上是现象,你看见这个现象也并不体现你的伟大,你四处大叫“苹果掉地上了”会被人当成疯子。而牛顿没有被人(因此)看成疯子的原因是:现象不过引起了他的注意,而探究到“本质”才是关键。
错误的命题——对《人月神话》的反思
从本质上来说,Brooks在《人月神话》中只是讨论了大型工程的实施,以及相应规模下的团队建设。
为什么“敏捷”之初颇受争议?为什么敏捷对一些中小型的团队显得有效和可实施?为什么当这些争议被摆在眼前的成功平息之后,传统工程的理论家们却不忘恨恨地评上一句:那是一种不能(或难以)应用于大型工程的方法呢?!
因为如果大家都很“敏捷”,都只做比这些大型工程“小那么一点点”的工程,那么传统工程的专家们就失业了。反过来,只有把工程做大,大到“敏捷”失去了意义,而“庞大”变成了实质的时候,传统工程就可以为认为任何失败找到借口:看啊,Brooks就说过“没有银弹”嘛。
如果我们真正理智地讨论“有或者没有银弹”,那么应该先反过来看看“人狼”的本质。因为本质是人狼对银不免疫,所以我们才能找到银弹并杀了它。如果人狼根本就杀不死,那么不要说金弹、银弹,就是核弹也没用——因为它杀不死。
我们来看看Brooks所谓的人狼,也就是“软件活动的根本任务”。首先,Brooks认为我们并没有足够的精力来放到“软件活动的根本任务”这一目标之上。他的论证过程如下:
根本任务的目标:抽象软件构成的复杂概念结构了;
次要任务的目标:表达抽象实体,在一定范围内映射成计算机的执行逻辑;
我们多数时候再关注次要目标,例如写程序和开发“写程序用的”程序;
我们写再多的程序与再强的“写程序用的”程序,都不会触及根本任务。
在这些论证中,Brooks还细述了这个人狼——软件活动的根本任务——的具体特征:复杂度、一致性、可变性和不可见性。即:
系统具有极端的复杂性;
有不可丢弃的历史包袱;
可能存在需求的持续变更;
需要用确定的抽象方法描述(复杂系统的)不同侧面。
随后,Brooks还对可能采取的措施作出分析:我们探索目标的方法,分散了达到目标的力量。我们在通向目标的路线上越是努力,那么我们的力量就被分散得越快。次要目标是达到主要目标所必需的,但次要目标上话费越多的精力,就越无法接近主要目标。
在否认你可能选择的手法,并未目标——人狼——加上重铠厚甲之后,Brooks最后设定了他对“解”——银弹的终极限制:HI,小子,你得拿个足够简洁(例如小刀?)的武器去单挑(独立的解决方案?)。
在偏执与自大充斥的软件行业中,引燃激情的,往往正是这种挑衅的口吻。于是整个工程界欢欣雀跃,一致以找出那枚银弹为己任。每个在这个方向上努力不已的人都没有看到,Brooks声明过:构建独立小型程序的数据不适用于编程系统产品。
大师的意思是:因为不能通过“做更多的小型程序”来得到做大型系统的经验/数据,所以无论何时,只要面对大型工程,你的经验值就立即归零(或者极低)。显然,(连白痴都知道)毫无经验值地直接面对终极大BOSS,结果一定是失败。又由于所有面对这些大BOSS的都(无可置疑地)失败,因此我们也就不可能有成功。
显然这是一个法宝:如果你违背这个逻辑而又获得了成功,那么这种成功可以立即被归结于“你在做一个小型程序”。
放心吧,没有人能杀得死Brooks的人狼的,也不可能找得到这样的银弹。因为Brooks的人狼原本就是杀不死的,他甚至连“给熟睡的人狼胸口一刀”这样偶然性的机会也没有为你留下。任何时候,你杀死了一头看起来有点像人狼的怪物,Brooks都可以轻描淡写地说:OH,小子,你看错了,那并不是人狼。
具体工程以及工程的具体化
两种具体工程视角下的话题:
a1:自研发产品;
a2:客户投资的项目;
b1:短期效益的市场探针;
b2:战略方向上的一项长远计划;
c1:一个小型而称手的工具;
c2:一个大型的可持续平台;
这个对比中,a1的需求基本可控,a2就得面对客户或业务规则的变化;b1不需要背上历史包袱,甚至不用考虑架构一致性,而b2就必须做好设计并面临长期用户需求的沉淀;c1可能一两个人就完成任务,c2就必须组织大型团队。。。我们如果要找一个方案来适应这所有的“软件开发活动”,那么它只可能是弹性的。而弹性并自由伸缩的一个方案必然带来学习和运用上的困难,因此你又得投入人力来学习使用,并在实施中持续监控它。——于是,你的人力和时间成本又增加了。
不要去相信“它适合与所有的工程”这种商业推广的鬼话。那绝对是赤裸裸的欺骗。你要看住你的口袋,因为你可能在消耗你的资源(时间、人力与金钱)去适应一种方法。这一过程可能的表现是,你:
一方面要花销资源去组织、实践和推动这些工程方法;
另一方面在这种规模下的工程可能根本没有资源去推动它们。
所以你必然面临失败。如果你:
增加资源去推动,那么成本可能大于项目利润;
你的老板会不乐意而直接中止这个项目。
所以你还是失败的。
所以问题出在你启动这个工程的最早阶段:你认清目标并决定用什么方法来驱动整个工程。你的选择涉及项目的各方面因素,而不是昨天从某个培训中听到的什么奇怪方法。作为合格的项目经理(和工程决策者),你必须要洞悉各种工程方法的应用环境、代价,也必须清楚所在团队或公司的规模与实力,同时还要了解团队的优点与弱点。只有充分评估这些因素,你才可能决策在具体的工程项目中应用的方法,或尝试之。
但是我们总是会遇到无比庞大的项目,这绝不是“只做做小项目”就可以解决得了的问题。然而我认为Brooks的假设过于学术,因为我们找不出一个理由来证明:需要一种纯粹的、独立的和并不那么复杂的方法来实施一个工程。对于一个具体的、哪怕是无比庞大的项目来说,这种学术的纯粹和完美也不是必需的。在这个具体的工程项目来说,完成它是必要的,而寻找完美方法,只是在完成这个项目之后进行总结时的一种附带价值。
换而言之,即使我们承认Brooks所说的“软件活动的根本任务”需要一种完美的、类似于银弹的解决方案,我们也不得不承认对于具体的工程项目来说,“表达抽象实体,在一定范围内映射成计算机的执行逻辑”——亦即是“实现”才是根本任务。
我们看到了分歧。而我认为对这个分歧的合理解释是:在广义工程与狭义工程——或言之具体工程中,主要目标与次要目标正好是倒置的。首先,我对《人月神话》中所说的“广义工程”的定义是:
面向“软件活动的根本任务”;
程序实现的过程无助于求解根本任务。
我看到,一旦我们坚持存在一个“绝对正确的解法”,任何实际问题都会延伸出枝节,蔓布于这个“绝对正确的解法”的墙篱之外。正是我们对广义工程及其成效的迷信,影响了我们的决策、尝试与实践。这就是现状。
而我对狭义工程的定义是:
面向“具体工程活动的需求”:实现;
求解“根本任务”只是将“实现”作为一个过程或结果的探索活动或附加价值。
我看到,我们总是在做事的过程中忘却了目标,正是我们追求广义工程的解,才阻碍了我们对(看起来相对狭义的)具体工程的实现。所以对于这个狭义的工程来说,“实现”才是它得以存在的根本价值。如果这项目标不能被达成,那么这个“具体工程活动”既不可能实施,也不可能为所谓的广义工程产生任何价值。
当我们否定Brooks对“工程本质”的设定后,我们可以看到走出迷局的一丝光明。首先,我们可以扔掉许多沉重的包袱:
我们不必承诺可变性或兼容性,或以确定的抽象方法向不同角色描述系统,或具体解决方案必须面临未知的极端环境(复杂性)。
我们不必要求以某种形式上美观或逻辑上严谨的方式来展示系统或目标。我们只需要找到最切实的手段来展示与实现目标。
我们不必保障解决方案的纯粹。我们尽可以在实施中选择各种复合方案,或者已经证明(或表面看来)并不完美的方案——前提是,你知道这个方案自身的问题与面临的问题域。
这样,我们将有可能重新审视我们的工程环境,并将某个工程“具体化”——无论它已经“进化”到多么庞大复杂。在谈论任何将工程“具体化”的方法与手段之前,我必须首先提及的基本观念包括:
确认工程的本质需求是实现。任何时候,记住“实现”是第一要务,应将对假象或理论设想的探索放在下一个版本,应远离空想。
第一要务是确定具体工程的具体目标。任何时候,请确保这些目标是可叙述的、可回顾的、可表现为具体软件产品(或其特性)的。
而在具体实施中,我们要保持灵活和切实的实践观念:
坚持:决策的前提与背景不变,决策不变;
置疑:任何看起来完美的东西都一定有问题;
开放:接受任何观点,知其所用。
控制规模
我认为,在所有实践活动中最重要但也最难保障的就是:控制规模。
例如一款软件:ACDSee,从ver4.0开始,ACDSee有了PowerPack版本,便也由此导致启动速度大幅度变慢、运行消耗的资源急剧上升,而读取图像的速度则开始变慢。
纵观ACDSee的发展史,你会发现它犯了两个主要错误:一是软件越来越大、越复杂;二是越来越不像一个“看图片”的软件。这两个错误,都主要是从“PowerPack”这个定义开始的——亦即是说,ACDSee人为地想要将一个软件产品“变大”,而忽略了:
用户想不想这个产品变得更大?
这个产品本身是不是应该更大?
更大了之后,这个产品是个什么?
ACDSee不甘于做一个“浏览图片的软件”,于是最后(它的高版本)变成了一个“连图片都不能浏览的软件”。回顾它的两个主要错误,其实就是个“控制规模”的问题。所谓规模,分成规、模两个方面,前者是边界,后者是形态。ACDSee既未能控制产品的边界,也未能保障产品的形态。所以现在,庞大而又四不像是它必然的结果。
出于本能,以及考量角色重要性的必需,我们的管理者大多数情况下喜欢管理一个“更大的部门”。与此类似,我们的项目经理也有这样的欲望。对于分工越来越明细的部门来说,“人多”(至少看起来)是必要的,但对于一个目标明确的项目团队来说,多一个“计划外”的人员就意味着离失败前进了一步。
好在,这个问题再《人月神话》中讨论过,Brooks说:“向进度落后的项目中增加人手,只会使进度更加落后。”这就是“除去了神话色彩的人月”。除了Brooks所讨论的几个方面之外,我们也可以从“控制规模”上来讨论这个话题。增加了“计划外”的人手,也就意味着项目团队的规模增大了;首先团队人数的边界在扩大,其次是新的人手对旧的团队组织结构也是冲击,导致其形态变化的风险也在增加。
同样与“人数”相关的,还涉及一种产品分类的方法:特定用户对象的产品,或通用产品。在我的工程实践中,习惯于将前者称为“(特定企业或角色的)项目”,而后者则称为“(面向领域或行业的,或泛义的计算机用户的)产品”。大多数情况下,我们能分清楚项目于产品的区别。但不幸的是,大量的“项目”存在“产品化”的可能。例如说为某个公司定制的OA就经常会“产品化”为一个通用的OA系统,又例如为某个公司定制的组织结构管理模块,最终要求被产品化为一个通用权限管理软件。
从原有的较少用户,变成面向更大范围的用户群,这未尝不可。但是举例来说,用于局域网或广域网的sniffer(嗅探器)工具没有本质的不同,然而无论从结构设计到技术实现,都是完全不一样的。所以从量变而至质变,是一个严重的问题,应该关注于这一过程发生的必要性以及时机,如果从第一个版本——就是你向“较少用户”提供那个定制项目——的时候开始就背负上这种“将来会变得完全不同”的责任,那么这个规模一开始就失控了。对于这个项目来说,既是边界出了问题,也是形态出了问题,因为项目原本没有这样的需要。
从这个角度来看,我们其实是要尽力避免“搭车”的需求和项目的。因为“搭车”的项目需要消耗很多的资源,例如提供分析数据、平台、培训,以及——你可能需要努力地——做到更好。
做“更多”的事情,以及把事情做到“更好”,等等,这些都是项目边界的失控。随着搭车项目带来的“环境变化”影响了你的决策能力,例如仅仅是为了表现出哪怕一丁点的责任心,你就会错误地将一个原本不需要通用的模块设计成为“能让搭车项目通用的”。类似于次,搭车者渐渐地影响了你的设计,又渐渐地,一个新的四不像就如同ADCSee一样地出现了。
相信我,一旦有项目搭车,那么它将成为你扔不掉的包袱,你将无端地承受更多的责任、眼光或声音。与其如此,不如早点说“不”。所以当你听到“我们可以顺便做个什么软件出来”这样的话的时候,你就要小心了。你要毫不犹豫地反对、拒绝,乃至于罢工。
但是,总有这样的需要——我们有很多项目是连带的,或类似的,或有公共性质的。这种情况下,你应试图说服你的老板:两个项目相加,带来的复杂性不是简单的“合并人手”就可以解决的。一方面更多的人手意味着管理成本的增加;另一方面,更大规模的项目,失败的风险也就越大。
隔离问题域
中国是个讲究“大一统”的国家,但这个“一统”不过是个结果,问题是“这个过程是如何的?”我常说人们只看到做事的结果,而看不到做事的过程,工程的积弊多源于这里。回顾秦始皇统一天下的过程,对六国征伐时:
秦国首先甄别权重,认为韩国处于秦国东进的首冲地位,提出从南边的“(强)楚”和北边的“(强)赵”中间切入,夺取韩国以使两国难以联合,从而避免了战争的规模化增长,完成了首次战略布局;
接下来,秦国分析其他各国实力,先弱后强,所以灭赵、魏、楚;
其三,秦国知道伐远必先安近,先平定周边,然后再征讨其他的国家,所以最后灭燕、齐。
由此可见,治乱的法子就是先分门别类:知轻重、强弱、远近。秦国在不同的阶段用不同的分类法,确定战略重点和对策方法,从而分治六国、平定天下。
“分类法”其实也是思维方法的问题。从思维法的角度来看,广义工程考虑的是对工程问题的“统治”,而具体工程则考虑的是“分治”。统而治之,寻求一个不变的方法固然是有可能的,但往往因循求旧,用就发在来治新病,新病未治了,又更添新病。而这就是软件工程界的现状。
所谓分治,关键就在于隔离问题域:
找到造成混乱的问题之间的关系,以及分类出无关的问题;
把问题放到界面上去讨论,而不是放在里面去讨论。
这些就是EHM图在“关注点”上面的主要努力。关注点约定了两个“域”之间的主要问题界面。(例如“实现”和“团队”这两个域来说有共同的关注界面)
它们共同关注的界面是在“方法”和“过程”之间,这意味着应着力寻求“过程模型”与“开发方法”的匹配。但,团队管理中不应该关心具体实现者对“程序=算法+结构”的实现,实现者也不必过多地关注具体的过程以及工程管理问题。
这并不是说“程序员不需要了解工程”。例如最内环的实现者能有良好的过程、工程意识,是相当重要的事;能参与到配置管理、文档管理中,也并无不妥。我的意思仅是在工作量多寡与职责权重上,他们不宜承担过多,也不必强求太多的“人人必知必会”。
当你开始对问题域进行“隔离”之后,你会发现最内层的一部分实现者可能立即变成了“工程白痴”——他们对所谓“工程”不闻不问,你讲什么他们都不懂。但是,难道你需要他们都变成“工程专家”之后,才开始工程吗?或者说,整个团队都要有工程实施能力,这个项目才有指望成功吗?
要知道,我们对不同“域”中的角色要求不同,“人人必知必会”那是可望而不可得的。所以,现在我看到一些团队中,人人都被组织起来学习“如何做工程”的时候,我就觉得味道很不对了——应该有一些简单的、不逾工程之钜的规则,能让他们在“正常的蚂蚁活动之余”遵循以下,整个工程就能得以推进,这就很好了。每个人都架构师,或每个人都是UML之父,这样的团队根本就不存在,这样的团队也没法工作——既然如此,那么我们为什么要做类似的培训呢?
所以,在一个项目中:
把问题分解在EHM图的不同层中,用不同的角色去解决;
将“域”间关联密切的问题,放在关注点界面上,由相关的角色去解决。
这样一来,我们看到项目经理只面临两个关键问题需要协调,即在“实现”与“团队”之间的界面上,以及“团队”与“经营”之间的界面上的问题。这两个问题简单的叙述是:
团队适用哪种具体的过程、方法?或基于具体情况,应做怎样的调整?
团队为怎样的目标而负责?或基于具体情况,应做怎样的调整?
项目经理的工作,好像就变得越来越轻松了。
这样是不是太简单了
事实上,的确是这样简单。上面两个问题,根底里还是说的“方向”和“方法”的问题,如果一个项目经理能把“我们要用什么方法,向着什么样的目标前进”这样的一件事情说清楚,那么项目也就成功了一半。大多数的团队(以及部门、组织等)的破裂,就是始自于这两个问题没有弄清楚。
但如果问题真的是这么简单,那么为什么我们总做不好?排除上面这些因素,为什么仍然会有那么多出问题的工程呢?首先,我们要注意到一个事实:上面所说的方向、方法,在整个项目的工程活动中真的是一成不变吗?现实的状况往往不是,往往我们会面临方向和方法的变化。更确切地说,常见的工程问题其实都是由“不能及时应对这种变化”而导致的。需要注意的是,我们不是在讨论工程面临的具体需求的变化,而是在讨论团队(或组织)面临的方向和方法的变化。这种变化要么是方法做走了样,或者因为团队内部发生了变化(例如主程序员离职,或者公司的组织结构变化,或者换了一个领导)而导致旧方法不能实施。另一方面,也可能因为方向性的变更带来了资源、目标等的变化。对于这些,我们不能及时应变,于是项目就做死了。
这些其实是同一类问题,归结起来:团队不是死物,方向与方法也不是死物,我们自己做成了死脑筋。
接下来,我们再跳出来看看整个问题的全貌。我在这里要追问的是:工程问题的源起与归结是什么?我们究竟应该如何看待工程问题?
我们已经在EHM图上,从内向外地层层追溯,最终追溯到了“组织”问题。我们此前有过结论:工程不是做的,是组织的。但我们接下来又置疑:如果所谓的“组织”只是明确分工、隔离问题域这些的话,那么“这样是不是太简单了?”
所谓“组织的问题”,根本上就是“人的问题”。在得到这一结论的前后,我正好读到《人件》这本书,它与《人月神话》讨论着相同的问题,却又站在不同的角度之上。正是这两种角度的区别,让我清晰地认识到:怎么看“人”,是两种工程理念、两种工程实作方法的核心区别。这一切,正如同敏捷工程与传统工程的核心区别,就是从一句“尊重人的价值”开始的一样。
你怎么看待工作中的“人”,决定了你如何组织你的组织,又决定了你此后如何管理这个组织。如果你认为这些“人”与某种确定的方法所要求的“人”相符——比如说能力的、观念的,以及思考背景的等——那么你的确可以将它们组织成合适这种方法的团队,进而将“人”的问题消弭在无形之间。
所以,方法与组织形式是相关的,组织形式与被组织的人是相关的,被组织的人与这些人的背景、文化又是相关的。写这个段落时,我正在看《观止——微软创建NT和未来的夺命狂奔》这本书,而我所想到的是:我们不可能有同样的“人”,来做相同的这件事情。我们只可能用“不同样的人”、“不同样的组织形式”,以及“不同样的方法”,来做“同样伟大的事情”。
成功不能被复制,关键在于“它所处的背景”不能被复制。这种“背景因素”既包括那件事的时代背景,还包括成就那件事的人们的历史背景、文化背景,以及——个性。
现在看起来,问题是不是又被我弄得太复杂了?我是不是在说“没有可能找到相同的方法来做工程”呢?不是,我只是在强调,你得找到适合你的团队的“人”的组织形式,并且明确这种组织形式不是一成不变的。
或者我们反过来,现在、当前,就围绕着某种组织形式去培养这些“人”。而这,不就是所谓企业文化正在做的么?我只在这里提出两点:一是显而易见的,在文化建设见到成效之前,组织和人都还有很长的路要走;二是组织要变化的,而一个公司却总是希望人力相对稳定,所以要让人适应组织的变化,这仍然要通过文化、教育来达到。
现在,我们已经把问题推到了“企业与人”的层面,而事实是:企业不是一天两天的事,人也不是一天两天的事,组织也不是一天两天的事。。。没有现成的东西“拿来就用”,这一切就又开始变得复杂了。
郑人的履
有个寓言:某个郑国人打算去买鞋,先量了量脚,然后到市场上去逛了一圈回来,却没买到鞋。问他,他说:我把量绳忘到家里了。问他的人又说:那你用脚试穿,不是一样可以买到鞋子吗?他说:我宁可相信那根量绳,也不相信我的脚。
当我们把一本本的书推荐到读者的面前,或者放在公司的书橱里的时候,那些教条就变成了一根根的量绳。尤其是在这些量绳被冠以“XX标准”的名头之后,我们再也不愿意相信自己的脚。我们宁可相信是我们“用错了方法”,也不愿意相信我们跟别人拥有着“不同的脚”。
要知道,对于不了解自己的求道者来说,就不是“问道于盲”的问题了,而根本就是“盲人问道”的问题。所以郑人买不到鞋,既
可能是他过于依赖量绳,也
可能是市场上根本没有合适的鞋,还
可能是他根本不知道市场上有没有合适他的鞋。
那些认为“不应该重复发明轮子”的人,同样也认为我们没有必要掌握“做双鞋子”的方法。唯一剩下的可选项就变成了:我们深信能“制造出”与别人相同的脚来——尽管我们可能连自己的脚是什么样子也没有看清楚。而这种“制造”的法子古人也发明过,是谓“削足适履”。
一部分人知道我们仍然还有选择:我们可以相信自己的脚,以及相信自己能做双鞋子。由于对于脚来说,别人的起点甚至比我们还低:他不了解我的脚。于是这其中的一部分人便关起门来做自己的鞋子,尽管他最终得到了草鞋,但终归好过没有鞋子。
郑人故事里的工程的现状就是这个样子了:穿好鞋的跑在前面,跟着是穿草鞋的、削了足的,以及边跑边削着足的。再后面还有光着脚丫的,在笑话着别人的脚上在起泡、流血,其实自己的脚上也起着泡、流着血。
对于建设和维护一个组织来说,不可避免地需要相当漫长而又多变的过程。对此唯一的法子就是一边适应,一边奔跑。适应的法子,要么是削足,要么是做鞋。做鞋不见得就要关着门,关键是要清醒面对门外的种种诱惑;削足也不见得就不是法子,需要权衡的是它与做鞋之间的成本。对于不同的企业、组织来说,成本是不一样的——但首先我们得相信自己的脚,这是成本的基本要素。所以,看起来我们还是有一些法子来处理上面的(企业的)组织与人的“适履”问题的。但是你得相信我,这无论如何都是一个长期跨度的事,问题只是被转移着地方,痛处不一样,但都是痛。
在所有的疼痛中,我唯一看到的相同的东西是:在具体工程的实践中,面对变化,灵活地调适组织、工程、方法与人。而后,反思。
是思考还是思想
软件工程三个要素的价值
思考问题的方法可以是由点及面的,也可以是统揽全局的。换成业界最常用的词汇,就是“自上而下”还是“自下而上”的区别。
“牛屎图”中描述的工具、方法与过程也被称为软件工程的三个要素。在本书中它们被分解开来思考,这并不是要孤立在三个层面——它们实际上是相互作用的。
例如“过程”问题,就既有实施过程的工具,也有相关的过程方法理论。我虽然说方法是“基于一种数据结构的编程实践的结果”,但这实在是一种非常狭义的定义。这个定义在过程的开发环节上是有效地(或者说是对“开发方法”的定义)。然而“需求”、“设计”、“测试”等其他环节也有各自的方法论,即使站在具体环节之外,过程本身也有方法论的问题,这还不包括管理方法等在内。
由于方法在过程环节及过程总体层面上具有贯通性,因此保证“方法(或其行为)”的实施的“工具”也会出现在过程的各个环节和层面上。这样一来,我们得到的软件工程模型将不是经典的、层状的“牛屎图”,而可能像太极图一样由阴阳交汇而生万物。
为了不使读者认为我已经入了道家理论的歧途,这样的一幅图还是交由你自己去画吧。只不过你应该清楚,即使画出了太极图的软件工程模型,你所见到的仍旧是工程的细部环节。就如同以管窥豹一般,斑是斑,豹是豹。
若你能把每一个“管见”拼合起来,你得到的才是“豹”,而不是“斑”。所以尽管本书割裂了软件工程的各个要素,并从每个孤立的层面来审视,但实质上,你应该回归到软件工程的本体上来思考问题,而不是仅关注于每一个局部的要素。
工程的整体问题仍旧是“实现”。
其实RUP是一个杂物箱
我或许总是在批评RUP,但是我不得不承认它是对前人在软件过程思想方面的高度包容。
请注意我用“包容”这个词,而不是按照语言习惯那样用“概括”。因为如果是“高度概括”,那你应该把目光投向瀑布模型,而RUP其实就像一个杂物箱一样“包容”了全部的已知理论。
你可以把RUP定制成其他任何模型所表述的过程形态——RUP本身的特质决定了这一点——因而它也如同一个杂物箱一样放满了各种稀奇古怪的东西。你可能从这个杂物箱里面拿出了一把剪刀,或一只苍蝇怕,或者是一根钓竿。。。
喂,等等。面对“软件开发”这样的一个需求,钓竿能有什么作用呢?在你扔掉它之前,请转换一下你的思维:钓竿可能带给你的团队以精神上的激励。如果你能意识到这一点,那么它将立即转化为生产力:把钓竿挂在开发部的墙上。
RUP能不能被用起来,将取决于你刚才那个挑挑拣拣的行为,以及现在你在拿到钓竿后的辨识能力与组织能力。
UML与甲骨文之间的异同
在你真的打算用甲骨文来写项目文档之前,请先明确UML与甲骨文之间的异同。
在本本书里,他们都被作为沟通的工具。因此目标是沟通,而不是“选用工具”这件事本身。更进一步的推论是:即使你因为个人喜好而选择了甲骨文,也不要试图在结绳记事的原始人面前去用它。
UML与甲骨文都是符号文字,都具有象形含义。然而这并不表明UML符号本身能表达那么丰富的含义。如果要像甲骨文一样用几代人、上千册的论著去解释它,那么UML图的价值也就只剩下象征性的意义了。
出于沟通的必要,这种语言的象征意义在一个图中应当被表述得足够准确和详细,乃至针对于不同的阅读者来说都能提供充足的信息。然而,一方面UML的规范中没有提供一个标准来衡量“怎样的UML图是描述充分的”;另一方面,UML作为一个语言,也无法直接在某个环境或场景中被语法检错和调试。
所以在工程中使用UML图,应该有相应的文字来描述它。而且这种描述与图之间的对应关系要持续地维护下去。如果这种关系松散了、断裂了,那么下一个阅读UML图的人所面对的,将是无异于甲骨文出土时的困境。
好在做UML图的那个工程设计人员(在辞世之前)还有机会为这些古怪符号写下规约。
经营者离开发者很远,反之亦然
使我第一次意识到EHM模型反映了角色所关注的不同视角的人,是我的老板。
事实上,他是一个完全不懂软件技术的老板。在EHM模型中,他所处于的位置在最右端,而开发者在最左端,在二者之间没有相同的关注界面(关注点)。EHM真实地反映了“老板不懂技术”的合理性,同样也真实地反映了“开发者转型为老板”的道路将是相当漫长与艰难的。
于是,项目经理这个中间角色就有了一种使命:协调经营者与开发者之间的沟通。
例如招来一名开发高手,对于公司的运作并不会有深入的影响(当然如果你招来了Anders Hejlsberg就另当别论)。因此,我甚至不需要与BOSS讨论这名高手的来历及作用。同样,与一个技术分析人员讨论一个产品的技术价值与市场价值之间的差异,以及市场运作方式与技术实现手段的无关性,也是毫无必要的。
你要理解这种根源:角色的关注层面完全不同。
矛盾:实现目标与保障质量
在需求阶段我们就会面临“目标”的问题。然而(在大多数时候),与此相反的是我们会在项目交付和试用时才碰到客户在质量上的投诉。
需求人员会把所有的责任归咎到开发人员,而开发人员又不停地埋怨需求的不清不楚,或者变更的没完没了。又如果正巧需求和开发都是同一个人或者小组来做的,那么他们便会开始埋怨客户的苛刻及工期的紧张。
总之一件事,没有人会跳出来说:我们原本就错了。然而事实上问题可能真的出在源头:我们把目标定错了。
我们看到,在项目的平衡三角(时间、资源和功能)中讨论的是目标问题,而并不讨论质量问题。也就是说,经典教材中总是关注:如何更快地完成项目,并减少资源占用,以及实现更多的功能。然而,即使平衡了这种关系,项目的结果仍可能产生一个天生的残障。
因为目标可能在平衡中确定,但质量却要在过程中控制。即使在时间、资源和功能三者中取得了平衡,即使客户、项目组和公司同样满意于这个平衡“目标”。它仍然有可能是“不能实施”的。
如果原定的目标(的整体)本身就过大,那么无论如何平衡这三者之间的关系,其结果仍旧保障不了质量。
问题是:又有谁愿意在最初签订协议的时候,就降低或者放弃协议的标的呢?
枝节与细节
刚才说到目标和质量的问题时,提及“平衡时间、资源和功能三者的关系”。这其实是一个实施过程中的细节。或者说,它是一个具体的方法,而不是目的。
所以我们通常所说的细节,其实对实施方法的一些有限量的描绘。比如“软件工艺”这个概念本身的提出,就是考究“细节问题”的。从这个角度上来说,我并不反对“细节决定成败”这样的观点。但请注意一个前提:这是技术或方法的细部。
我其实在前面的行文中一再地混用了“细节”与“枝节”这两个词。枝节是事实发展的次要的分支,它不涉及行为本身,也不是对行为本身的考量。因此我在前面的文字中说到“跳出细节”,其实本意是“跳出枝节”——细节只是做到何种程度的问题,而并不是关不关注(或做不做)的问题。
大多数情况下,管理人员有责任去审核、评估其他成员的工作成果。这个时候可以讨论“细节决定成败”这样的问题,因为这决定了产品的最终质量,而质量是工程的目标之一。
而在另一些情况下,例如管理人员做事件的决策的时候,就必须要学会忽略枝节问题。
混淆这两个名词的使用,其根本原因在于一大部分读者并不能区分“细节”与“枝节”。从惯于“实作”的程序员一路走来的工程人员,很难分清自己什么时候是在“工作”,而什么时候又是在“决策”。
因此我只好用最笨的方法提示管理者:别管它是细节还是枝节,只要你感到你的脚趾已经沾上了泥渣,就快点回头。
用脚趾去感觉,有时比用头脑去思考来得有效。
细解“法”与“式”
软件工程学科中的很多思想与其他传统的工程学科既有的思想、方法和理论有紧密的关系。所以甚至有些团建工程角色被推荐去阅读类似于《建筑的永恒之道》这样的书。据说,模式先驱Ward Cunningham 和Kent Beck就是首先从Christopher Alexander建筑学模式中吸取了灵感,从而开创了“设计模式”这样的软件工程方法。
《营造法式》原序中说:“(工程需要)按时聚集工役,做出屋檐似翼的宫室。然而工匠的手,虽然很巧也难免做走了样。主管工程的官,也不能兼通各工种。”由此看来,《营造法式》中所解决的问题,与我们今天的软件工程中所遇到的问题如出一辙:
工程管理者不能兼通各个工种;
不同的开发人员对设计和制作的理解不尽相同。
那么《营造法式》如何解决上述两个问题的呢?
这就回到了“法式”这个词的含义上来了。法式两字,是宋代官方文件的常用词,“法”指律令、条例,“式”指定式、方法。所以《营造法式》颁行的初衷,是希望能够有办法将工程中所用的元素:
“按类分别排出,以条例规章作为依据”;
“按照条文画成图样,对将来的工作有所补助”。
这两点即是所谓的“法”与“式”。
然而这些与软件工程实践究竟有什么关系呢?
如果我们看到,“模式”相当于是建筑中预制的工件,那么我们将各个工程角色在模式方法下的实作形成制度;把实现一个模式的代码量、人工量约定度量;把如何构架模式、如何度量模式的质量(完成度和可用性)确立规范。。。我们也可以得到软件工程的“法式”——至少,这在表面上看起来是无限美好的。而且事实上,这些工件、制度、度量和规范正是软件工程界多年来孜孜以求的东西。
相对于《营造法式》,我们的软件工程实践类数学专著仍然非常粗糙,未必能像“法式”那样值得趋从跟随。当然我们也不应当因噎废食,妄论优劣。因此对于“某某模式”与“某某模型”之类,我的态度仍然是“与式不同,比类增减”。
灵活的软件工程
“知律而变”可以概括我在诗词格律方面的主要观点。而这其中的“律”字,若解释作“规律”,那么便是可以用于软件工程中的了。“道”是规律,如果明“道”,则可以变化无穷,这样做软件工程才是活的。就如同今天我们难于填词一样,不明道,则不明智,不明智则无所以为。因而在软件工程实施中不可避免地会盲目与停滞。
“知律”的另一层意思,是在于“知道原理”。明白“为什么要这样”或者“为什么不是那样”。这在软件开发中是常见的问题,大多数人不知就里地使用着技巧和方法,而一旦出了问题,则归咎于这些技巧和方法的不好。而真正的问题在于,这些人(我们通常叫做Copy&Paster)并不知道这些技巧、技术和方法的原理,因而不知道变通,也不知道回避错误。
所以死读一本《软件工程》的人不会做真正的软件工程。
附图
EHM(软件工程层状模型)
“牛屎图”