代码整洁之道:程序员的职业素养

978-7-115-43415-9
作者: 【美】Robert C. Martin(罗伯特 C. 马丁)
译者: 余晟章显洲
编辑: 杨海玲

图书目录:

详情

本书是编程大师“Bob 大叔”40 余年编程生涯的心得体会的总结,讲解要成为真正专业的程序员需要具备什么样的态度,需要遵循什么样的原则,需要采取什么样的行动。作者以自己以及身边的同事走过的弯路、犯过的错误为例,意在为后来者引路,助其职业生涯迈上更高台阶。

图书摘要

版权信息

书名:代码整洁之道:程序员的职业素养

ISBN:978-7-115-43415-9

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

本书是编程大师“Bob 大叔”40余年编程生涯的心得体会的总结,讲解要成为真正专业的程序员需要具备什么样的态度,需要遵循什么样的原则,需要采取什么样的行动。作者以自己以及身边的同事走过的弯路、犯过的错误为例,意在为后来者引路,助其职业生涯迈上更高台阶。

本书适合所有程序员阅读,也可供所有想成为具备职业素养的职场人士参考。


Authorized translation from the English language edition, entitled CLEAN CODER, THE: A CODE OF CONDUCT FOR PROFESSIONAL PROGRAMMERS, 1st Edition, ISBN: 0137081073 by MARTIN, ROBERT C., published by Pearson Education, Inc, Copyright © 2011 by Pearson Education Inc.

All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc.

CHINESE SIMPLIFIED language edition published by POSTS AND TELECOMMUNICATIONS PRESS Copyright © 2016.

本书中文简体字版由Pearson Education Asia Ltd.授权人民邮电出版社独家出版。未经出版者书面许可,不得以任何方式复制或抄袭本书内容。

本书封面贴有Pearson Education(培生教育出版集团)激光防伪标签,无标签者不得销售。

版权所有,侵权必究。


1986年至2000年期间,我在Teradyne公司工作时,和同事Jim Newkirk成了密切合作的搭档。我们两人都醉心于编程,醉心于追求整洁代码,花了很多时间尝试各种不同的编程风格,把玩各种设计技术。我们还在一起构思各种商业设想。最终,我们一起创办了Object Mentor公司。在和Jim共事的过程中,我从他身上学到了很多东西。其中最重要的,是他对于职业道德的态度,这一点也是我一直努力效仿的。Jim是极为专业的。我以曾与他共事合作而深感自豪,视他为良师益友。


我在招聘中经常会问:“在你过去的工作中,遭遇过哪些印象深刻的困难,最后是怎么解决的?”依我的经验,简历写得再漂亮的人,如果这个问题答不好,大都可以直接忽略。为什么会有这种结论?因为我们需要招聘的不是“经历丰富”的人,而是“有职业素养”的人。你遇到的问题可能很容易也可能很难,但我看重的并不是问题的难度,而是解决问题的方式、步骤以及反思的程度。恢复误删数据,对很多人来说这是非常简单的任务。我更感兴趣的是怎样分析问题,找了怎样的资料,采取了怎样的步骤,此后做了哪些措施来避免这种错误再次出现。在我看来,与问题本身的难度相比,解决问题的方式、步骤以及反思的程度,才能体现出一个人的职业素养。

是的,上面我两次提到了“职业素养”。相比起“专业主义”“职业化”等说法,我更喜欢用它来翻译Professionalism,因为素养强调的并不是天赋的神秘,也不是技艺的高深,而是持续积淀的结晶:一方面,它体现了能力和素质;另一方面,它又强调了持续的积累和养成。作为职业开发人员,基本技能不够熟练,当然谈不上职业素养。但是仅仅能迅速地编写代码,却不关心代码背后的意义,不能迅速判断、解决程序运行中的各种问题,不能自信满满地为自己交付的程序承担责任,同样是与职业素养绝缘的——许多所谓的“高手”,正是缺乏职业素养的典型。

当然,这只是我对于“职业素养”的理解。由个体经验总结的“职业素养”,多有一鳞半爪的嫌疑,所以即便你认同上面的观点,也难免感觉“只见树木,不见森林”。其实真正的“职业素养”绝不限于上述几方面,而是要广阔得多,深刻得多。要想一窥技术人员“职业素养”的全貌,已经有很多现成的资料可以参考,本书就是其中的佼佼者。

作为一本技术类书籍,本书中有相当的内容是介绍纯技艺的方面,比如测试驱动开发等,自认已经算“职业开发人员”的人,大概对此并不感冒(不过,我仍然建议你认真看看)。但其他的内容,绝对值得你感冒,比如:什么情况下应该对业务部门说“是”,说“是”意味着什么。如果你没有想过这些问题,或者没有明确的答案,不妨看看Bob大叔是怎么说的:

(说“是”时)你对自己将会做某件事做了清晰的事实陈述,而且还明确说明了完成期限。那不是指别人,而是指你自己。你陈述的是自己会去执行的一项行动,而且,你不是“可能”去做,或是“可能做到”,而是“会”做到。

就我所见,技术人员往往太容易说“是”,总是在没有明确目标和期限的情况下,就草率给出了确认的答复,却不将其视为自己的承诺。屡见不鲜的项目延期,有相当原因就是在这种不负责任的情况下说“是”所致。但是我们想想,似乎没有哪一个正经行业,会把不能完成任务的人视为“有职业素养的人”,软件行业也不能例外。

如果你觉得自己已经足够负责,懂得“是”背后所蕴含的意义和责任,也不过如此,我们不妨更进一步,看看关于说“否”。在第2章,Bob大叔介绍了两个项目搞砸的经过。他并没有像常见的所谓专家那样故作聪明地指出实施过程中出现了哪些问题,导致了失败,而是一针见血地指出:这两个项目之所以会搞砸,因为开发人员没有坚决抵制各种不专业的需求(比如一些无关紧要但成本巨大的需求),抵制各种不专业的行为(比如为了赶工期而降低对程序质量的要求),最终只好喝下自己酿出的苦酒。对此,Bob大叔总结道:

有时候,获取正确决策的唯一途径,便是勇敢无畏地说出“不”字……我们要明白,委屈专业原则以求全,并不是问题的解决之道。舍弃这些原则,只会制造出更多的麻烦……

对我来说,这段话堪称振聋发聩。而且,这种思维,这种视角,其实是许多技术人员所不屑或者不愿面对的——最初我也这么认为,但尝试在工作中主动说了几次“不”之后,我逐渐发现:花三分的力气去抵制无理的需求,可以节省十分甚至二十分的开发时间;相反,自欺欺人地说服自己凑合接受了无理需求,往往会非常被动乃至无法脱身,到最后,项目就落得著名的IBM OS/360操作系统的下场,越挣扎,巨兽在泥潭中就陷得越深。

要学习这样的道理,当然也可以参加培训班,听取授课或者阅读讲义,但那未免太显正经而缺乏亲和力。Bob大叔的特别之处在于,他总是可以通过浅显易懂的故事,清晰而敏锐地揭示问题的核心所在。其中许多故事正是他自己亲身经历的,阅读过程中常会会心一笑,因为遇到了开发人员都懂的妙趣,比如费尽全力也是徒劳,无法让其他人理解“编辑程序的程序”。笑过之后,又会明白许多道理——无法让其他人理解“编辑程序的程序”并不是真正的原因,真正的原因是:“客户……对功能的设想,其实经不起电脑前真刀真枪的考验……问题在于,东西画在纸上与真正做出来是不一样的。业务方看到真正的运行情况时就会意识到,自己想要的根本不是这样。一看到已经满足的需求,关于到底要什么,他们就会冒出更好的想法——通常并不是他们当时看到的样子……真正的解决办法,是约定共同认可的验收测试标准,并在开发过程中保持沟通。”以我的经验来看,这一点是说得非常对的。我曾经尝试在与业务部门确定目标原型之后,要求对方指派对接人在IT部坐班,负责协商、跟进整个开发流程,确认每一点修改。这样既保证最终结果符合业务部门的需求,又提高了开发人员的工作效率,综合来看成效非常显著。

类似的例子还有很多,在阅读这本书时,我经常会惋惜:如果早一点读到这本书,或许我之前就不会犯这样那样的错误,就能更早更好地积累自己的职业素养。况且能有妙趣横生的书讲述看似枯燥的“职业素养”,对读者来说,又是一种幸运。德国作家托玛斯•曼曾经津津乐道于“斜躺在沙发上整天阅读叔本华”的美妙感觉,那是因为叔本华的文笔优美、流畅,可以把哲学变为惬意的享受。作为同时读过叔本华和Bob大叔的人,我想说,斜躺在沙发上整天阅读《程序员的职业素养》,认识和了解开发人员的职业素养,同样是相当惬意的享受。

余晟

广东,2012/7/18


“师者,所以传道授业解惑也。”Robert C. Martin,软件开发社区中亲切地称他为Bob大叔,正是这样一位明师。

2003年,他的《敏捷软件开发:原则、模式与实践》(下称ASD)在国内上市。我那时进入软件开发行业刚刚一两年,这本书真可谓是及时雨。在精读全书和细心对照书中案例练习后,我感觉自己在面向对象设计方面的功力有了比较明显的提升。那时因工作环境所限,身边没有能够手把手给予技术辅导的导师,因此,那时在我心中Bob大叔无疑就是一盏指路明灯。后来在网上找到了不少Bob大叔的演讲PPT,沿着链接,又找到了Object Mentor公司其他一些软件开发专家的演讲PPT和博客,我如饥似渴地阅读揣摩。现在回头想来,正是在这个阶段我开始建立起“编程技艺”的视角。

时间过得很快,转眼就到了2010年,不觉中我已在软件开发的多个领域工作了近10年。2010年,Bob大叔的《代码整洁之道》一上市,我马上给自己和项目团队订了好几本。在为ASD所写的序中,Bob大叔写道:“最好的软件开发人员都知道一个秘密:美的东西比丑的东西创建起来更廉价,也更快捷。构建、维护一个美的软件系统所花费的时间、金钱都要少于丑的系统。……美的系统是灵活、易于理解的,构建、维护它们就是一种快乐。”如果说ASD中更多的是OO设计思想和模式精髓的阐述,那么在《代码整洁之道》中,Bob大叔提供了更为详尽的微距视角,涉及“命名”“函数”“代码格式”“异常处理”“单元测试”等编码主题,巨细靡遗地向软件工匠们极力传授整洁编码的艺术,进一步向软件开发社区慷慨分享了他在探索“软件之美”旅途中的参证心得。

但是,细心的读者可以发现,在前述两本书中Bob大叔阐述的主体还是软件编码技术本身,作为一门技艺而言,止步于具体技术或曰“术”的层面,应该还未算得完整。后来,在YouTube、SlideShare和Object Mentor等站点上,我看见Bob大叔有不少演讲趋向于聚焦在编程主体即软件开发者自身行为模式和特质层面上,就猜到他不久应该就会有此方面的新著推出。Bob大叔就是Bob大叔,在探索和分享软件技艺的路上,他内心怀有对软件开发社区发展责无旁贷的使命感。果不其然,他将这些体悟浓缩在又一本新著上,这本书便是读者手上的这本《代码整洁之道:程序员的职业素养》。

本书阐述的是Bob大叔关于软件技艺主体的沉思,这些沉思并非是纯粹形而上的思辨推演,而是他对自身编程生涯的深刻反思和经验沉淀。在这本书中,Bob大叔并非是以高人一等的凌人盛气(事实上,他应该有这样的资格)大行说教,而是毫不掩饰自己在职业生涯中曾犯下的各种错误和不堪往事,以这些案例为载体,现身说法,娓娓道来使自己得以转变和提升的种种“机锋”,并留有意味深长的空间,供读者自己结合自身状况进一步体悟提炼,而非给出硬邦邦的一堆结论。这是何等的胸怀、格局和智慧!

按照传统的太极阴阳思维来看,如果说ASD和《代码整洁之道》中的内容是硬性的、技术性的、显性的,故而可以归为“阳”的范畴,那么本书中的“专业主义”“技艺之道”便是软性的、哲学性的、隐性的,故而可以归为“阴”的范畴。“孤阴不生,独阳不长”,《老子》说“万物负阴而抱阳,充气以为和”。Bob大叔这三本书为何都选择星云图片作为封面呢?我忽有顿悟。

严肃地选择以软件开发为自身职业方向的软件工程师(我更喜欢称为“软件工匠”)们,如果你同我一样,此前感觉颇为受益于Bob大叔的谆谆教诲,那么请不要错过本书。将本书和ASD、《代码整洁之道》并列案头,三书互为参照,一并静心细读、揣摩体悟、时时对照、检验调整,做到负阴抱阳、知行合一,相信定能渐入佳境。

本书本该早日完成翻译面市,但因我个人方面的一些原因,翻译进度耽搁时日颇多,使我内心极为惴惴不安,这点必须向各位读者,尤其是Bob大叔的粉丝和在从事软件开发过程中遇到困顿境地的读者们,深深致歉!

感谢人民邮电出版社的各位编辑对我的信任、宽容和指导。我对人民邮电出版社在技术专著引入和传播事业上的孜孜以求与坚持不懈的精神十分敬佩!

感谢蔡煜兄(@larrycaiyu)对几章译稿的前期试读,并提出了不少改善的地方。(我在2010年上海ScrumGathering会议上结识蔡煜,此后从他的博客和微博上受益不小。)

感谢余晟兄作为审校者为本书付出的辛勤汗水,你的修订和润色使本书的正确性、可读性有了本质性的提升。如果没有你,我不知道自己是否有勇气将译稿交付出版。在进度滞后的情况下,你又慷慨接受我的邀请成为合译者,在繁忙的工作之余拨冗翻译了本书的第6、7、9、10章,使得本书得以早日和中文读者见面。你是我遇见的专业人士的典范,我从你身上学到许多东西。谢谢!(但人非圣贤,如书中难免存有错讹之处,那是我的责任。)

最后,必须感谢支持我完成艰苦翻译工作的家人,包括我的父母、爱妻Jenny和胞妹Agnes以及小儿多多。占用了很多本该属于你们的周末时间,我心中深感愧疚,但你们总是很宽容地表示理解,这又使我感觉欠你们更多。

最后,祝读者能够开卷有益,相信作为作者的Bob大叔、引进者的人民邮电出版社和译者的我们,定然感到十二分的欣慰。

章显洲

杭州,2012/7/30


你选了这本书,那么我不妨认为你是一名软件工程师。很好,我也是。既然如此,我得和你谈谈,我为什么会读这本书。

事情是这样的:不久以前,在不远的地方。来,背景、灯光、摄像、演员,一切就绪,那我就开讲了……

几年前,我在一家中等规模的公司工作,公司销售的是政府严格管制的产品。这类公司的样子你肯定想象得出:办公场所位于一幢三层小楼里,我们坐的是格子间,总监级以上人物则可以拥有私人办公室;把相关人员召集到会议室里开个会,可能得花一周左右的时间。

我们所在的市场竞争非常激烈。这时,政府放开了一个新产品。

突然间我们拥有了一批全新的潜在客户,我们所要做的就是让他们购买我们的产品。这意味着必须在某个截止日期前向联邦政府提出申请,在另一个截止日期前通过评估审计,并在第三个截止日期前完成交付。

管理层一遍又一遍地向我们强调这些截止日期的重要性。如果延期一次,政府就会把我们列进当年的黑名单。如果客户们没有在第一时间和我们签约,他们无一例外会选择其他供应商。如果拿不到订单,我们就彻底出局了。

在这种环境下,有些人会抱怨,有些人则会说:“艰难困苦,玉汝于成。”

我那时是从开发部门晋升上来负责技术方面工作的项目经理。我的职责是确保网站按期上线,这样潜在客户便可以从网站上下载资料,其中最重要的资料是注册表单。负责业务方面的项目经理是我的搭档,我叫他Joe。Joe的工作职责是销售、做市场推广和分析非技术性需求。这位老兄平素也挺喜欢拿“艰难困苦,玉汝于成”这样的调调说事。

如果你在美国公司工作过,肯定知道指责、过失追究和工作厌恶症都是司空见惯的。不过在我们公司里,Joe和我有个十分有效的办法来解决这类问题。

我们这对搭档有点儿像蝙蝠侠与罗宾,任务就是要把事情搞定。我每天都会和技术团队会面;我们每一天都会调整计划,找到关键路径,扫除在关键路径上所有可能出现的障碍。如果有人需要什么软件,我们就去弄来。如果有人一边抱怨“天哪,我该吃午饭了”,一边说自己更“喜欢”配置防火墙,我们就会给他带午餐。如果有人想去搞定配置问题,但手上还有其他更重要的事项要去处理,Joe和我便会去找他的主管协调。

如果不行,就去找经理。

再不行,就去找总监。

总之,肯定会把事情搞定。

如果说我们常常大动肝火、踢翻椅子,以大吼大叫的方式来沟通,这可能有点儿夸张了,但我们确实使尽了浑身解数来搞定遇到的每件事情,还想出了一些新办法。让我一直自豪的是,我们并没有违背职业道德,没有为达目的不择手段。

我认为自己是团队的一员,而非凌驾于团队之上、只会中途插进去写一句SQL语句或做点儿结对编程写一两句代码的那种人。当时,我也是如此看待Joe的,认为他也是团队成员之一,而不是凌驾于团队上,置身事外。

后来我才明白,Joe自己并不是这么看的。对我来说,这是令人很郁闷的一天。

那是个星期五下午的一点钟,下周一一早,网站就要按计划上线了。

完工了。*DONE*。每个系统都已就绪,我们已经准备好了。我把整个技术团队召集在一起,召开最后一次Scrum会议,准备上线。与会的不只是技术团队,还有市场营销、产品负责人这些业务人员。

我们感到十分自豪。这真是个美妙的时刻。

这时,Joe进来了。

他大致是这样说的:“有些坏消息。法务还没准备好注册表单,因此网站还不能启用。”

这没什么大不了的。在整个项目过程中,我们时常受阻,不是因为这样的事就是因为那样的事,但是,对付这些障碍,我们的“蝙蝠侠与罗宾”这招却屡试不爽。我对此已有对策:“好的,伙计,我们再试试老办法。法务在三楼,对吧?”

气氛不太对头。

Joe并没有同意我的提议,而是反问:“Matt,你是什么意思?”

我说:“你知道的。我们的经典配合。我们现在谈论的就只是四个PDF文件,对不对?这些PDF文件已经准备好,就差法务批准下就可以了,是不是?我们只要在他们旁边盯牢他们,应该就可以把这件事情搞定的!”

Joe不同意,他回答说:“我们下周只需迟些时候上线网站就可以。没什么大不了的。”

你可能已经猜到了后续的交谈,大致像下面这样。

Matt:“但是为什么呢?他们只需要几个小时就可以搞定的。”

Joe:“几个小时可能不够。”

Matt:“但是他们整个周末都可以处理啊。时间很充裕。就这么办吧!”

Joe:“Matt,这些法务都是专业人士。我们不能逼迫他们,没理由要求他们为了我们这个小小的项目而牺牲个人时间。”

Matt:(暂停)“……Joe……那你对过去这四个月来我们对技术团队所做的事情又做何感想呢?”

Joe:“没错,但是这些法务可是专业人士。”

冷场。

深呼吸。

Joe刚才说什么来着?

那时,我认为把“专业人士”这个词用在技术人员身上最贴切不过。

但现在仔细回想一下,我对此已经不那么确定了。

让我们换一个视角,再来看看“蝙蝠侠与罗宾”技术。我认为我是在鼓励团队努力呈现他们的最佳状态,但我怀疑Joe是在和我们玩博弈,他暗地里认为技术人员是站在他的对立面的。想想看:不然又有什么必要到处巡视,在依赖别人做事的同时,又常常闹出踢翻椅子大动干戈这样的事呢?

为什么我们不能去询问团队成员项目什么时候可以完工,在获得确切回答之后就相信这个回答,也不必因此受煎熬?

当然可以,作为专业人士,我们确实应该做到这一点……但我们确实还做不到。Joe并不信任我们,只有对技术团队进行微观管理才能让他安心。而与此同时,出于某种原因,他确实能够信任法务团队,也并没有要对他们进行微观管理的想法。

这一切说明了什么问题?

法务团队肯定以某种方式展现了他们的专业精神,而技术团队尚未做到这点。

这些团队肯定以某种方式让Joe信服,他们并不需要保姆一直跟在身边,他们彼此间不是在玩博弈游戏,他们应该被视为值得敬重的合作伙伴。

不,我不认为这和那些挂在墙上的花哨证书,或是他们在学校里多待了些年头有什么关系。尽管这些年来,学校里可能已经开了不少社交培训课程,里面涉及不少与如何表现得更专业相关的内容。

自从多年前的那一天之后,我一直在想,技术人员需要如何改变才能被视为专业人士呢?

哦,我已经有了一些体会。我已经用博客记录了一些想法,也看了很多相关的内容,我设法以此改善自己的工作和生活状况,同时也能帮助其他人有所提升,但我还不知道有人在这方面有什么写作计划,把如何成为软件专业人士的全部秘诀和盘托出。

直到后来,有一天,我意外地获得审阅一本书的初稿的机会;这本书,正是你现在手中拿着的这本。

这本书将会由浅入深、详细讲解该如何展现自己,如何以专业人士的方式与人交流协作。没有陈词滥调,也非寻章摘句纸上谈兵之作,里面阐述的都是具体的行动方法和要诀。

其中的某些案例中,作者可谓用心良苦,字字诤言。

一些例子中有对话录和总结,甚至还针对别人“无视你”的情形专门提供了相关的行动建议。

嘿,看,Joe又来了,我们回到了早前那一幕。

Joe和我,我们又回到BigCo,把那个网站大项目重新做一次。

只不过这次,请想象一下,这次的做法有一点点不同。

这次,技术人员不再找借口拖延,而是勇担重任;不再推卸估算工作或置身事外让其他人来做计划(然后对计划抱怨不休),而是真正做到了自组织,并做出了郑重承诺。

现在想象一下,大家能够真正紧密协作起来了。当程序员因为运维方面的问题受阻时,他们会打电话给系统管理员,之后,系统管理员就会马上着手清除障碍。

Joe也不必大动干戈才能推进解决14321号问题;他可以看到DBA正在勤奋工作,而不是在网上冲浪。同样,他从技术人员那里拿到的估算结果看起来非常一致,他不会感觉项目在技术人员那里的优先级是无足轻重的。以往所用的试图操控进度的所有招数手段,现在都派不上用场了,技术人员现在不会说“我们尽力而为吧”,而会代之以“这是我们的承诺;如果你想调整目标,请随时联系我们”。

过了一段时间,我想Joe就会认同技术团队同样也是专业人士。是的,确实如此。

那么,想要从技术人员晋升为专业人士,该经历哪些步骤呢?本书将为你悉数讲解。

祝你迈上职业生涯更高的一个台阶。我想你肯定会喜欢这本书的。

Matthew Heusser

软件过程博物学家


封面所用的这张惊艳图片(图片来源于NASA 和Hubble Heritage 团队),很容易让人联想到《指环王》中魔王索伦的眼睛,它是M1蟹状星云。M1位于金牛座,在金牛左角尖的天关星右边约一度位置。整个蟹状星云是一次超新星爆发之后散开的残骸,它的亮度和木星差不多。在6500光年外的地球,古代中国的天文学家观测到了这场爆炸,日期刚好是公元1054年7月4日(美国国庆日)。实际上,当时的人们在白天用肉眼就看得见!过了6个月,它才从肉眼能见的视野中淡出。

这张封面图片是由可视光线和X射线合成的。可见光图像由哈勃望远镜摄得,作为外层;内中看起来像蓝色靶心的图像是由钱德拉X射线望远镜摄得。

可见光图像显示的是超新星爆发时混合着重物质残骸迅速膨胀的尘埃和气体云。此星云现在的直径为11光年,质量是太阳的4.5倍,并且仍以每秒1500 km的速度剧烈膨胀。不说别的,光是这次古老爆发所产生的动能也足够震撼了。

靶心正中的那个蓝色亮点正是脉冲星所在。正是脉冲星的形成导致恒星爆炸。在那颗濒临死亡的恒星内核,约有一颗与太阳(直径约为1400 000 km)差不多质量的物质聚爆成直径约30 km的中子星。聚爆产生的巨大动能,加上中子形成时微中子的猛烈冲击,撕裂了恒星,宣告了它的死亡。

脉冲星仍在以每秒30次的速度旋转,并且一边旋转一边发光,通过望远镜可以看到闪光。正是由于这种光线脉冲,人们才把它命名为“脉冲星”。


1986年1月28日,美国东部时间上午11:39,“挑战者”号航天飞机在发射仅73.124秒后,因右侧固体火箭推进器的故障,在1.5万米的高空化成碎片。7名航天勇士魂断苍穹,其中包括高中教师克丽斯塔·麦考利芙。麦考利芙的母亲目睹女儿在1.5万米高空中不幸罹难,当时她脸上的表情,至今印刻在我的心头无法拂去。

挑战者号之所以解体,是由于高热气体从出现故障的固体火箭推进器的外壳接缝处泄露出来,喷到外部燃料舱体上。主液氢燃料舱底部发生爆炸,液氢被点燃,并将液氢燃料推入上方的液氧燃料舱中。与此同时,固体火箭推进器脱离了下支架,开始绕上支架滚动。推进器的机头捅破了液氧舱。异位滚动的推进器导致整个飞行器逆向气流旋转,但同时仍然以1.5马赫的速度飞行。在巨大的过载下,挑战者号迅速被撕成碎片。

在火箭推进器的圆形接缝处,有两个由合成橡胶制成的同心密封圈。当壳体通过螺栓连接在一起时,密封圈被压缩,起到密封作用,确保气体不会从接缝处逸出。

但在发射前夜,发射台气温降到了-8℃,比密封圈的最低承限温度低了13℃,比以往发射气温低了18℃。这个气温下的密封圈已经硬得失去了弹性,无法很好地密封高热气体。推进器点火后,高热气体迅速累积,对壳腔形成了压力脉冲。助推器壳体向外膨胀开来,密封圈受到的压力变小。但是硬化的密封圈缺乏弹性无法保持密封,一些高热气体就泄漏出来,并且将密封圈上超过1/6的部分都气化了。

设计推进器的莫顿·赛奥科公司的工程师事前已经知道密封圈有问题,并早在7年前就已经将这些问题报告给莫顿·赛奥科公司和美国宇航局的管理人员。事实上,在以前的发射中,密封圈就曾出现过类似的损坏,只是没有引发灾难而已。发射气温越低,后果就越严重。工程师们已经针对该问题设计了修复方案,但修复方案却迟迟未得以实施。

工程师们知道密封圈在低温的时候会硬化。也知道挑战者号发射时的气温比以往任何一次发射时的都要低,远低于红色警戒线。简而言之,这次发射的风险太高了,他们不能对危险视而不见。于是他们写了备忘录,发出高危预警信号。他们强烈要求赛奥科公司和美国宇航局的管理人员们取消此次发射任务。在临发射数小时前所开的紧急会议上,这些工程师展示了最有说服力的数据。他们摆事实、讲道理,软硬兼施,拒绝执行这次发射任务。但最后,管理人员们却对此无动于衷。

发射时,一些工程师不忍观看现场直播,因为他们担心发射台上会发生爆炸惨剧。但是,随着挑战者号优雅升空,他们开始有点安心了。就在挑战者号解体前的瞬间,看着飞行器已经迈过1马赫的关口时,一位工程师还说他们已经“躲过一劫”。

管理人员们听不进去工程师们的抗议,也不看备忘录,更没有命悬一线的危急感。他们认为自己更了解情况,认为工程师们小题大做了,他们不相信工程师们的数据和结论。他们之所以进行这次发射任务,是因为面临着很大的财务和政治压力。他们对此心存侥幸,希望一切都能平安无事。

这些管理人员不只是愚蠢至极,他们是在草菅人命。他们以为自己才是专家,他们的恐惧、希望和直觉才是准的。恰恰是因为他们的自以为是,七名优秀宇航员的生命以及一代人对太空旅行的梦想,都在那个寒冷的早晨一起灰飞烟灭了。他们篡夺了真正了解情况的工程师们的权力。

而那些工程师呢?当然,工程师做了他们应该做的事情。他们通知了管理人员,并且极力捍卫自身立场。他们经由适当的渠道,调用了所有合适的沟通协议。他们做了在体系内力所能及的事情,只是最后不得不听从领导的决定。因此,看起来工程师可以问心无愧了。

但是,我不知道那些工程师之中,是否有人会躺在床上夜不能寐,眼前浮现克丽斯塔·麦考利芙母亲脸上的惨痛表情,为之前没有给丹·拉瑟[1]打电话而悔恨不已。

这本书主要阐述软件开发者的专业精神。书中包含了许多实务性的意见,试图回答诸如以下的问题:

你还会发现,在本书的实务性意见背后,隐隐体现出一种奋力突破的积极态度。这种态度提倡要诚信,要富有荣誉感、自尊心和自豪感,要勇于承担作为一名手艺人和工程师所肩负的重大责任。这种责任包括要努力工作,出色完成任务;要擅于沟通,能够就事论事;要管理好时间,能够坦然面对艰难的“风险回报”决策。

除此之外,这种责任之中还包括神圣的使命感。身为一名工程师,你比任何管理者可能都了解得更透彻。了解这些也意味着你肩负着要敢于行动的重大责任。

[McConnell87]:Malcolm McConnell, Challenger “A Major Malfunction”, New York, NY: Simon & Schuster, 1987

[Wiki-Challenger]:“Space Shuttle Challenger disaster.”

[1] 丹·拉瑟,美国记者、新闻主播。曾任美国哥伦比亚广播公司的CBS晚间新闻的当家主播,此外也是新闻杂志节目60分钟的主持人。曾任美联社记者,自1981年3月9日登上晚间新闻当家主播算起,到2005年3月9日后告别主播台,担任此一职位长达24年整。——译者注


我的职业生涯中有很多次与他人合作的经历。尽管有很多事情是我个人的梦想与追求,但我几乎总能找到志同道合的人。这一点上,我觉得有点像《星球大战》里的西斯,“身边总会有伴”。

我认为,算得上专业的第一次合作,是在13岁时和John Marchese一起造电脑。我思考,他动手。我指出该焊线的地方,他来焊;我指出该装继电器的地方,他来装。我们乐此不疲地在这上头忙活了数百小时。我们的确鼓捣出了不少看着相当有型的家伙,上面装着继电器、按钮、小灯,甚至还有电传打字机!当然,这些电脑都没法用,但它们看起来真的很棒,我们也确实干得十分卖力。谢谢你,John!

进中学的第一年,我在德语课上认识了Tim Conrad。Tim很聪明。在我们搭档造电脑时,他思考,我动手。他教给了我一些电子学知识,他也是第一个向我介绍PDP-8的人。我们用一些很基础的元器件真的造出了一台可以工作的18位二进制计算器,能够进行加减乘除的运算。那年我们把所有的周末、寒暑假和圣诞假期都投了进去,干得很疯。最终,机器跑得棒极了。谢谢你,Tim!

Tim和我自学了计算机编程,在1968年,这并不是件容易的事,但我们做到了。我们特别找来了有关PDP-8汇编器、FORTRAN、COBOL、PL/1的书。我们如饥似渴地读书,并写了一堆根本没有可能去实际执行的程序,因为当时还没法摸到计算机。但纯粹出于爱好,我们孜孜不倦地写了许多程序。

在中学二年级的课程中,开设了计算机科学的科目。学校有一台ASR-33电传打字机,通过一台110波特的拨号调制解调器,可以连接到伊利诺伊理工学院的Univac 1108分时系统上。学校在那上面有一个账号。Tim和我马上就成了那台机器实际上的操作者,其他人都没法靠近它。

通过调制解调器连接到主机上时,要先拿起电话进行拨号,当听到准备接收调制解调器信号的回答时,按下电传打字机上的“orig”键,发起端的调制解调器就会发出尖锐的啸叫,开始发送信息。这时数据连接已经建立,可以挂断电话。

电话机拨号盘上有锁,只有老师才有钥匙。但这并无大碍,因为我们发现,只要在叉簧开关上拍打出电话号码,就可以拨出电话。我会敲鼓,节奏感很强,反应也快,所以即使电话上了锁,我也可以在10秒内把调制解调器拨通。

计算机实验室里有两台电传打字机,一台在线,另一台离线,两台都被学生们拿来写程序。学生们使用打孔纸带在电传打字机上录入程序,程序内容都打在纸带上。他们用的编程语言是IITran,这种解释型语言相当强大。最后,学生们会把这些纸带放在电传打字机旁的一个篮子里。

课后,Tim和我会拨通计算机(当然是通过敲打叉簧的方式拨通的),把纸带加载到IITran批处理系统里,然后挂断电话。载入速度大概是每秒10个字母吧,这个过程并不快。大概一小时后,我们会回拨电话,接收打印内容,这次仍然是每秒10个字母。电传打字机无法根据学生姓名分页返回结果列表。它只能一页接一页不断地打出返回结果。因此,我们需要用剪刀把返回的打印结果剪开,用夹子把输入纸带和结果列表夹在一起,再放到专门装输出结果的篮子里。

Tim和我成了此道达人。甚至连老师们看到我们在那个房间里也不会来过问。我们其实有点越界了,他们对此也很清楚,因为他们从未要求我们这么做,也从没说我们可以这么做,更没给过我们电话的钥匙。我们悄悄进去,他们默契离开——放手让我们去做。在此,向我的数学老师McDermit先生、Fogel先生和Robien先生一并说声:“谢谢你们!”

做完作业之后,我们就开始玩了。我们会一个程序接一个程序地写着玩,极尽疯狂之能事。我们在电传打字机上编写能够使用ASCII绘制圆形和抛物线的程序。我们编写随机漫步程序和随机文字生成程序。我们将50的阶乘算到最后一位。我们乐此不疲地想出各种编程题目,并努力用程序实现。

两年后,Tim、我们的伙伴Richard Lloyd还有我,被ASC公司聘为程序员。这家公司位于伊利诺伊州莱克布拉夫市。当时Tim和我都只有17岁。我们当时觉得上大学是浪费时间,便决定马上进入职场。在那里我们遇见了Bill Hohri、 Frank Ryder、Big Jim Carlin和John Miller,他们为我们这些年轻人提供了学习专业编程的实战机会。那段经历有得有失。当然,我在其中颇受教益。所以,我想对他们所有人,包括促进和推动这个过程的Richard,说声:“谢谢你们!”

19岁那年我辞职了,并且变得消沉。在那段时间,我在姐夫那里修理割草机,但是我干得实在太糟了,最后他不得不炒了我。谢谢你,Wes!

一年后我又重整旗鼓,进入了Ourboard Marine 公司。那时我已经结婚了,而且正要升级做爸爸。他们最终也炒了我。谢谢你们,John、Ralph还有Tom!

随后我开始在Teradyne工作,在那儿我认识了Russ Ashdown、Ken Finder、Bob Copithorne、Chuck Studee,还有 CK Srithran (现在叫Kris Iyer了)。Ken是我的老板,Chuck和CK是我的搭档。我从他们所有人身上都学到了许多东西。谢谢你们,伙计们!

接着我遇见了Mike Carew。在Teradyne,我们俩成了黄金搭档。我们一起写了好几个系统。“如果你想活儿干得又快又好,就把它交给Bob和Mike!”我们共事的时光充满欢乐。谢谢你,Mike!

Jerry Fitzpatrick也是我在Teradyne时的同事,我们是在玩“龙与地下城”游戏时认识的,但随即迅速结成同盟。我们一起为玩家写了一个可以在Commodore 64家用电脑上运行的“龙与地下城”游戏软件。在Teradyne,我们还一起开始了一个叫“电子接线员”的项目。Jerry和我共事了好几年,并成为我的终生挚友,谢谢你,Jerry!

在Teradyne时,我曾在英国工作过一年。在那儿我和Mike Kergozou搭档,期间所有事情我们几乎都是两人一起筹划的,虽然这些事情大部分与自行车和酒吧分不开。Mike是个十分勤勉的程序员,注重质量和原则(不过,或许他自己可能不会认同这样的评价)。谢谢你,Mike!

1987年从英国回来后,我开始和Jim Newkirk搭档。我们都离开了Teradyne(前后相隔几个月),加入了一家新创公司Clear Communication。我们在那里一起努力拼搏了好几年,却一直没能成就财富梦想。但是,我们还是奋力前行。谢谢你,Jim!

最终我们一起创办了Object Mentor公司。在所有我有幸共事过的人中,Jim是最率直、最严谨和最专注的。他教会我许多事情,内容之多无法在此一一列举。为此,我谨将本书题献给他!

此外,和我搭档过的、合作过的、对我的职业生涯产生过影响的人,还有许许多多,他们是:Lowell Lindstrom、Dave Thomas、Michael Feathers、Bob Koss、Brett Schuchert、Dean Wampler、Pascal Roy、Jeff Langr、James Grenning、Brian Button、 Alan Francis、Mike Hill、Eric Meade、Ron Jeffries、Kent Beck、Martin Fowler、Grady Booch等。还有许多人的名字恕在此无法一一详列。谢谢你们每个人,谢谢大家!

当然,我亲爱的妻子Ann Marie是我最好的人生搭档。我20岁时和Ann结婚,那时她的18岁生日刚过去3天。38年来,她一直是我坚定不移的伴侣,是我的舵,我的帆,也是我的爱与生命。我期待同她携手再走40年。

现在,我的合作伙伴和搭档则是我的孩子们。我和大女儿Angela合作紧密,她是我可爱的小保姆和坚强的助手,她让我在专注前行的同时,不会错过一个约会或是遗忘任何承诺。我和儿子Micah也是业务上的搭档。他创办了8th Light,他的商业头脑远胜于年轻时的我。我们新近的合作事业Clean Coders令人激动!

我的小儿子Justin刚刚开始加入Micah的8th Light。我的小女儿Gina是霍尼韦尔的化学工程师。他们的事业刚刚拉开序幕!

在生命中,我们从孩子们身上收获最多。谢谢你们,我的孩子们!


我猜,你之所以拿起这本书,因为你是程序员,“职业素养”这个说法吸引了你。你应该如此。我们这种专业人士迫切渴求的,正是“职业素养”。

我也是程序员。我编了42年[1]的程序。这42年里,我什么都经历过。我被开除过,也被表扬过。我当过小组长,当过主管,也当过普通员工,甚至当过CEO。我的同事有聪明绝顶的,也有混日子的懒鬼(slug)[2]。我曾经开发过尖端的嵌入式软硬件系统,也写过寻常公司的工资系统。我用过COBOL、FORTRAN、BAL、PDP-8、PDP-11、C、C++、Java、Ruby、Smalltalk,还有其他许多语言和系统。我的同事有混工资的家伙,也包括无可挑剔的专业人士。本书要讲的,正是那些无可挑剔的专业人士。

在这本书里,我会尝试定义专业程序员。我会讲解,成为真正专业的程序员,需要什么样的态度、原则、行动。

这些态度、原则、行动从哪里得知?它们源于我一路走来的亲身体会。坦白说,看到我第一次做程序员时的表现,你多半不会想到与“专业”二字搭边。

那是1969年,我17岁的时候。我父亲说服本地一家名为ASC的公司雇用我为兼职程序员。(是的,我父亲做得出这种事情。我曾见到他冲到疾驰的汽车前,伸出双臂大喊“停”,车真的就停下来了。没人敢对他说不。)那家公司把我扔在保管所有IBM电脑操作手册的房间里。我的任务就是把历年的更新记录到操作手册上。就是在那里,我第一次见到了“本页有意留空”(This page intentionally left blank)这句话。

这个活干了好几天之后,我的上司让我写个简单的Easycoder[3]程序。领到这个任务可真叫人激动,我还从来没在真正的计算机上写过程序呢。不过,我曾钻研过Autocoder的说明书,对如何开始写这个程序,我也有些模糊的想法。

程序要做的就是,从磁带上读取记录,将旧的ID替换为新的ID。新的ID从1开始,逐个加1。然后,把更换了新ID的记录写到新的磁带上。

上司给我看了一个架子,上面堆着许多红色和蓝色的打孔卡片。想象一下,你买了50张纸牌,一半是红色的,一半是蓝色的,然后把它们一张张叠起来。那些打孔卡片就是这个样子的。这些卡片打着蓝色和红色的标识,每种颜色的卡片大概200张。卡片的内容是所有程序员都会用到的子程序库的源代码。程序员通常会拿走堆在最上面的卡片,确认没拿错其他卡片,然后把卡片排在自己程序卡片的末尾。

我自己的程序写在编码表单上。编码表单是纸做的巨大的矩形列表,有25行,80列。每一行对应一张卡片。程序用大写字母和2号铅笔填在编码表单上。每行的最后6列,用2号铅笔编上号。通常编号以10为基础递增,这样将来还可以插入卡片。

填完编码表单,就要交给负责打孔的人。这家公司有几十名女员工,她们从一个大公文框中取出编码表单,然后把这些表单“打”到打孔机上。打孔机很像打字机,不过字符是打在卡片上的,而不是纸上。

第二天,负责纸带打孔的人会把对应的纸带通过办公交流信件发回给我。我那一小堆的打孔卡片,用我的编码表单包起来,外面用橡皮筋捆上。我想看看哪些卡片有打孔问题,但没有发现。于是我拿出一张子程序库的卡片,附加在我的程序卡片末尾,上楼交给电脑操作员。

计算机安放在密封的房间,有锁闭的大门,有高出地面的地板(用来走线)。我敲了门,操作员一脸严肃地拿走我那堆卡片,放在计算机房的另一个公文框内。等他们有空的时候,就会运行我的程序。

第二天,我拿回了自己的卡片。卡片外面裹着运行结果详单,用另一根橡皮筋捆起来(那时候我们得用很多橡皮筋)。

我翻开结果详单,发现编译失败了。详单里的出错消息我压根看不懂,所以我去找了上司。他仔细看了看,叽叽咕咕地说了几句,在上面做了个记号,然后拿起我的卡片,告诉我跟他走。

上司带我去了打孔室,找了一台没人用的打孔机。他逐个纠正了程序卡片上的错误,又加上了一两张卡片。他简单地介绍自己在做什么,但我根本来不及弄明白。

他把新的卡片带到计算机房,然后敲了门。他对操作员说了几句神秘的话,便跟在操作员身后进入了机房,还招手示意我跟上去。我们看着操作员开动磁带存储器,读入纸带。磁带旋转起来,打印机嗒嗒响起来,然后便结束了,程序运行正常了。

又过了一天,我的上司对我表示了感谢,告诉我以后不用来了。显然,ASC认为他们没时间去教一个17岁的孩子写程序。

但是我和ASC却没有就此断了关系。过了几个月,我得到了一份全职的工作(虽然是三班倒的第二班),管理ASC的离线打印机。这些打印机以磁带上存储的图片为材料,印刷垃圾邮件。我的任务是给打印机装纸,给磁带机装磁带,解决卡纸问题,除此之外,就是盯着机器运行。

那是1970年,我上不了大学,也不想上大学。学校里一片喧嚣。我一直如饥似渴地学习使用COBOL、FORTRAN、PL/1、PDP-8、IBM 360汇编语言。我的想法是不去上大学,自学成材,尽自己的力量去找份编程的工作。

一年后我做到了。我晋升为ASC的全职程序员。我与两个好朋友——Richard和Tim,我们都是19岁——一起,与同一组的另外3名程序员为卡车司机工会编写实时会计系统。我用的计算机是Varian 620i。这种微机很简单,结构类似PDP-8,区别在于它的字长为16位,而且有两个寄存器。我们使用的语言也是汇编。

这个系统的每行代码都是我们自己写的,我说的是,每一行代码。我们自己写了操作系统,自己写了中断头,自己写了IO驱动器,自己写了磁盘文件系统,自己写了内存的交换覆盖模块,甚至自己写了重定位的链接器,所有的应用程序都是自己写的。我们持续工作了8个月,每周工作70到80小时,为了赶那该死的工期。当时,我的工资是每年7200美元。

系统按期交付了,之后我们便辞职了。

辞职很突然,我们也很不满。要知道,完成了所有工作,顺利交付了系统之后,公司才给我们涨了2%的薪水。我们感到受骗了,我们的劳动不受尊重。我们中的一些人另找了工作,径直辞了职。

我却选了一条不同,而且非常不幸的路。我和一个朋友冲进老板办公室去发泄,出来的时候还在大吵大嚷。这可真过瘾——但只过了一天的瘾。

第二天,我忽然发现没有工作了。我19岁,失业,没有学位。我面试了一些程序员的职位,但都表现得不够理想。所以我在我姐夫的割草机修理铺干了4个月。不幸的是,我脑子里可能缺少修理割草机的那根弦。他最后只好让我走人了,我的感觉糟透了。

那时候我每天凌晨3点才睡觉,睡觉之前的活动是吃比萨,在我父母的老式黑白电视机上看很老的恐怖电影,虽然那些电影里只有几个鬼怪可看。我睡到下午1点才起来,希望逃避沉闷惨淡的白天。我在本地一所社区大学学习微积分,但是考试却通不过。我真是个废物。

我母亲把我拉到一边说,我的生活糟透了,只有傻瓜才会没找好下家就辞职,才会这么冲动辞职,才会和同事一起闹事。她还告诉我,辞职前一定要找好下家,要非常冷静,非常沉着,不要拉上其他人。她劝我打电话给以前的老板求情。我母亲说:你要把姿态放低。

19岁的人根本不知道什么是放低姿态,我也不例外。但是,现实已经撕碎了我的骄傲。最后我给老板打了电话,而且真正把姿态放得很低。结果奏效了,老板很高兴让我重新上班,给我6800美元的年薪,我也欣然接受。

我又在那里工作了18个月,观察自己的一举一动,尽自己努力成为一名有价值的员工。我升了职,加了薪,有了稳定的收入。生活走上了正轨。我离职时没和公司发生任何冲突,同时我已经确定了更好的去处。

你可能认为我从此变成熟了,就这样成了专业人士。其实并非如此。这段经历只是我需要学习的众多课程的第一课。后来,我曾经因为粗心耽误了关键日期被炒鱿鱼,因为不小心向客户泄露机密数据几乎被炒鱿鱼。我曾经领导过毫无成功希望的项目,看着它垮掉,明知需要他人帮助却无动于衷。我曾经好强地固守自己的技术决策,即便这些决策在客户的需求面前黯然失色。我曾经雇用完全不合适的人,让我的老板背上沉重的负担。最糟糕的是,因为我领导无方,其他两个人被炒了鱿鱼。

所以,请你把这本书看成我的错误大全,它记录了我干过的所有蠢事;也请你把这本书当成一份指引,靠它绕开我曾经走过的弯路。

[1] 别大惊小怪。

[2] 这是一种技术界的说法,来源未知。

[3] Easycoder是Honeywell H200上的汇编程序,类似IBM 1401上的Autocoder。


“噢,笑吧,科廷,老伙计。这是上帝,或者也可以说是命运或自然,跟我们开的一个玩笑。不过,不管这家伙是谁或是什么,他真幽默!哈哈!”

——霍华德,《碧血金沙》

这么说,你确实是想成为专业的软件工程师,对吧?你希望能昂首挺胸向世界宣告“我是专业人士”,希望人们满怀尊重地看着你,充满敬意地对待你。希望母亲们会指着你告诉自己的孩子要成为像你这样的人。这些都是你想要的,对吧?

“专业主义”有很深的含义,它不但象征着荣誉与骄傲,而且明确意味着责任与义务。这两者密切相关,因为从你无法负责的事情上不可能获得荣誉与骄傲。

做个非专业人士可轻松多了。非专业人士不需要为自己所做的工作负责,他们大可把责任推给雇主。如果非专业人士把事情搞砸了,收拾摊子的往往是雇主;而专业人士如果犯了错,只好自己收拾残局。

如果你不小心放过了某个模块里的一个bug,以致公司损失了1万美元,结果将会怎样呢?非专业人士会耸耸肩说:“难免要出点儿状况嘛。”然后像没事儿人一样继续写其他模块。而专业人士会自己为公司的那1万美元买单[1]

哇,自掏腰包?那可真让人心疼唉!但专业人士就必须这么做。实际上,专业主义的精髓就在于将公司利益视同个人利益。看到了吧,“专业主义”就意味着担当责任。

想必你读过前面的引言了,对吧?如果没有,赶紧翻回去读一遍,因为本书将要讲的内容,都在它塑造的情境里展开。

我曾因不负责任尝尽了苦头,所以明白尽职尽责的重要意义。

那是1979年,当时我是一家叫Teradyne的公司的“负责工程师”,所负责的软件控制着一个测量电话线路质量的小型机系统和微机系统,该系统的中央小型机通过带宽为300波特的拨号电话线与几十台控制测量硬件的外围微机连接在一起,程序是用汇编语言编写的。

我们的客户是各大电话公司的客服经理,他们每个人都负责10万条甚至更多的电话线路。我的系统负责帮助这些服务区经理抢在客户之前发现各种线路故障并及时修复。这可以减少客户投诉率,以免对此做监测的公共设施委员会相应下调电话公司收取的服务费。总之,这些系统极其重要。

每天晚上,这些系统都会运行“夜间例行程序”,即中央小型机会通知外围微机对所控制的电话线路进行检测;每天早上,中央计算机就能获取故障线路清单及其故障特征。根据这些报告,各服务区经理会安排人员修复故障,这样就不会有客户投诉了。

一次,我对几十个客户推出了一版新发布。“推出”这词可真是形象啊。我把软件写在磁带上,就把这些带子“推出”给客户了。客户载入这些磁带,然后重启系统。

这一新发布修复了几个小故障,还增加了客户要求的一项新功能。之前我们曾承诺会在截止日期之前提供那项新功能。我连夜赶工,总算在约定日期前交付了磁带。

两天后,我接到现场服务经理Tom的电话,他告诉我已经有好几个客户投诉“夜间例行程序”没能执行完成,他们没收到任何报告。我不由心头一沉:为了按时交付软件,我没测试例行程序。我测试了系统的其他大部分功能,但测试例行程序要费好几个小时,而当时我又必须交付软件。因为故障修复部分都不涉及例行程序部分的编码,所以我也没担心会有什么不妥。

收不到夜间报告,问题可就大了。修理工们会一时无事可忙但随后又要超负荷工作,而且,有些电话客户也可能会在这期间发现故障并投诉。要是弄丢一晚的数据,某一服务区经理肯定会打电话臭骂Tom。

我启动实验室系统,加载新软件,然后开始对“夜间例行程序”进行测试。几小时后,运行中断。例行程序运行失败!如果我在匆忙交付软件前对此进行测试,就不会发生服务区丢失数据的事了,服务区经理们这时也不会炮轰Tom了。

我打电话给Tom,说我能重现问题了。Tom告诉我其他大部分客户也已经打电话抱怨了,并问我什么时候能解决问题。我说我也没把握,但正在努力。同时我告诉他应该建议客户倒回去使用旧版软件。Tom发火了,说那对客户来说无疑是个双重打击,因为客户不仅为此丢失了一整个晚上的数据,而且还无法使用事先承诺的新功能。

故障排查非常困难,每次测试就要好几个小时。第一次修复失败了。第二次也没能成功。我试了好几次,等我发现问题所在时,好几天已过去了。这期间,Tom每隔几小时就打电话问我问题什么时候能解决,他还把那些服务区经理喋喋不休的抱怨如数传达给我,并一再告诉我让那些客户重新起用旧软件令他多么尴尬。

最后,我终于找出了缺陷所在,重新交付修复了问题的新程序,一切恢复正常。Tom也平静下来,不再提这段插曲,毕竟,他不是我的上司。事后,我的老板过来对我说:“你最好别再犯同样的错误。”我只能默默地点点头。

经过反省,我意识到没有对例行程序进行测试就交付软件是不负责任的。为了如期交付产品,我忽略了测试环节,整个过程中只考虑要如何保全自己的颜面,却没顾及客户和雇主的声誉。我本该早点儿担起责任,告诉Tom测试还未完成、自己不能按时交付产品。那么做绝非易事,Tom一定会不高兴,但客户不会丢失数据,客服经理也不会打电话来轰炸。

那么,我们该如何承担责任呢?的确有一些原则可供参考。援引“希波克拉底誓言”或许显得有点夸张,但没有比这更好的引据了。的确,作为一名有追求有抱负的专业人士,他的首要职责与目标难道不正是尽其所能行有益之事吗?

软件开发人员能做出什么坏事呢?从纯软件角度看,他可以破坏软件的功能与架构。我们会探讨如何避免带来这些破坏。

显然,我们希望软件可以运行。没错,我们中的大部分人今天之所以是程序员,是因为我们曾开发出可用的软件,而且希望能再度体验那种成功创作的喜悦。但希望软件有用的不单单是我们,客户和雇主也希望它们能用。是啊,他们出钱,让我们去开发那些能按照他们意愿运行的软件。

开发的软件有bug会损害软件的功能。因此,要做得专业,就不能留下bug。

“等等!”你肯定会说,“可是那是不可能的呀。软件开发太复杂了,怎么可能会没bug呢!”

当然,你说的没错。软件开发太复杂了,不可能没什么bug。但很不幸,这并不能为你开脱。人体太复杂了,不可能尽知其全部,但医生仍要发誓不伤害病人。如果他们都不拿“人体的复杂性”作托词,我们又怎么能开脱自己的责任呢?

“你的意思是我们要追求完美喽?”你可能会这样抬杠吧?

不,我其实是想告诉你,要对自己的不完美负责。代码中难免会出现bug,但这并不意味着你不用对它们负责;没人能写出完美的软件,但这并不表示你不用对不完美负责。

所谓专业人士,就是能对自己犯下的错误负责的人,哪怕那些错误实际上在所难免。所以,雄心勃勃的专业人士们,你们要练习的第一件事就是“道歉”。道歉是必要的,但还不够。你不能一而再、再而三地犯相同的错误。职业经验多了之后,你的失误率应该快速减少,甚至渐近于零。失误率永远不可能等于零,但你有责任让它无限接近零。

1.让QA找不出任何问题

因此,发布软件时,你应该确保QA找不出任何问题。故意发送明知有缺陷的代码,这种做法是极其不专业的。什么样的代码是有缺陷的呢?那些你没把握的代码都是!

有些家伙会把QA当作啄木鸟看待。他们把自己没有全盘检查过的代码发送过去,想等QA找出bug再反馈回来。没错,有些公司确实按照所发现的bug数来奖励测试人员,揪出的bug越多,奖金越多。

且不说这么做是否会大幅增加公司成本,严重损害软件,是否会破坏计划并让企业对开发小组的信心打折扣,也不去评判这么做是否等同于懒惰失职,把自己没把握的代码发送给QA这么做本身就是不专业的。这违背了“不行损害之事”的原则。

QA会发现bug吗?可能会吧,所以,准备好道歉吧,然后反思那些bug是怎么逃过你的注意的,想办法防止它再次出现。

每次QA找出问题时,更糟糕的是用户找出问题时,你都该震惊羞愧,并决心以此为戒。

2.要确信代码正常运行

你怎么知道代码能否常运行呢?很简单,测试!一遍遍地测,翻来覆去、颠来倒去地测,使出浑身解数来测!

你或许会担心这么狂测代码会占用很多时间,毕竟,你还要赶进度,要在截止日期前完工。如果不停地花时间做测试,你就没时间写别的代码了。言之有理!所以要实行自动化测试。写一些随时都能运行的单元测试,然后尽可能多地执行这些测试。

要用这些自动化单元测试去测多少代码呢?还要说吗?全部!全部都要测!

我是在建议进行百分百测试覆盖吗?不,我不是在建议,我是在要求!你写的每一行代码都要测试。完毕!

这是不是不切实际?当然不是。你写代码是因为想执行它,如果你希望代码可以执行,那你就该知道它是否可行。而要知道它是否可行,就一定要对它进行测试。

我是开源项目FitNesse的主要贡献者和代码提交者。在写作本书的时候,FitNesse的代码有6万多行。在这6万行代码中有2000多个单元测试,超过2.6万行。Emma的报告显示,这2000多个测试对代码的覆盖率约为90%。

为什么只有90%呢?因为Emma会忽略一些执行的代码。我确信实际的覆盖率会比90%高许多。能达到100%吗?不,达不到,100%只是个理想值。

但是有些代码不是很难测试吗?是的,但之所以很难测试,是因为设计时就没考虑如何测试。唯一的解决办法就是要设计易于测试的代码,最好是先写测试,再写要测的代码。

这一方法叫做测试驱动开发(TDD),我们在随后的章节里会继续谈到。

3.自动化QA

FitNesse的整个QA流程即是执行单元测试和验收测试。如果这些测试通过了,我就会发布软件。这意味着我的QA流程大概需要3分钟,只要我想要,可以随时执行完整的测试流程。

没错,FitNesse即使有bug也不是什么人命关天的事,也不会有人为此损失几百万美元。值得一提的是FitNesse用户上万,但它的bug列表却很短。

当然,也不排除有些系统因其任务极其关键特殊,不能只靠简短的自动化测试来判断软件是否已经足够高质量,是否可以投入使用。而且,作为开发人员,你需要有个相对迅捷可靠的机制,以此判断所写的代码可否正常工作,并且不会干扰系统的其他部分。因此,你的自动化测试至少要能够让你知道,你的系统很有可能通过QA的测试。

成熟的专业开发人员知道,聪明人不会为了发布新功能而破坏结构。结构良好的代码更灵活。以牺牲结构为代价,得不偿失,将来必追悔莫及。

所有软件项目的根本指导原则是,软件要易于修改。如果违背这条原则搭建僵化的结构,就破坏了构筑整个行业的经济模型。

简言之,你必须能让修改不必花太高代价就可以完成。

不幸的是,实在是已有太多的项目因结构糟糕而深陷失败的泥潭。那些曾经只要几天就能完成的任务现在需要耗费几周甚至几个月的时间。急于重新树立威望的管理层于是聘来更多的开发人员来加快项目进度,但这些开发人员只会进一步破坏结构,乱上添乱。

描述如何创建灵活可维护的结构的软件设计原则和模式[2]已经有许多了。专业的软件开发人员会牢记这些原则和模式,并在开发软件时认真遵循。但是其中有一条实在是没几个软件开发人员会认真照做,那就是,如果你希望自己的软件灵活可变,那就应该时常修改它!

要想证明软件易于修改,唯一办法就是做些实际的修改。如果发现这些改动并不像你预想的那样简单,你便应该改进设计,使后续修改变简单。

该在什么时候做这些简单的小修改呢?随时!关注哪个模块,就对它做点简单的修改来改进结构。每次通读代码的时候,也可以不时调整一下结构。

这一策略有时也叫“无情重构”,我把它叫作“童子军训练守则”:对每个模块,每检入一次代码,就要让它比上次检出时变得更为简洁。每次读代码,都别忘了进行点滴的改善。

这完全与大多数人对软件的理解相反。他们认为对上线运行的软件不断地做修改是危险的。错!让软件保持固定不变才是危险的!如果一直不重构代码,等到最后不得不重构时,你就会发现代码已经“僵化了”。

为什么大多数开发人员不敢不断修改他的代码呢?因为他们害怕会改坏代码!为什么会有这样的担心呢?因为他们没做过测试。

话题又回到测试上来了。如果你有一套覆盖了全部代码的自动化测试,如果那套测试可以随时快速执行,那么你根本不会害怕修改代码。怎样才能证明你不怕修改代码呢?那就是,你一直在改。

专业开发人员对自己的代码和测试极有把握,他们会极其疯狂随意地做各种修改。他们敢于随心所欲修改类的名称。在通读代码时,如果发现一个冗长的方法,他们肯定会将它拆分,重新组织。他们还会把switch语句改为多态结构,或者将继承层次重构成一条“命令链”。简单地说,他们对待代码,就如同雕塑家对待泥巴那样,要对它进行不断的变形与塑造。

职业发展是你自己的事。雇主没有义务确保你在职场能够立于不败之地,也没义务培训你,送你参加各种会议或给你买各种书籍充电。这些都是你自己的事。将自己的职业发展寄希望于雇主的软件开发人员将会很惨。

有些雇主愿意为员工买各种书籍或送员工参加各种培训课程和会议。那样挺不错的,说明他们待你不薄。但可千万别就此认为这些是雇主该做的。如果他们不为你做这些,你就该自己想办法去做。

另外,雇主也没义务给你留学习时间。有些雇主会这么做,有些甚至要求你这么做。但是还是那句话,他们待你不薄,你应该适当表示感激。因为这些优待不是你理所当然就该享有的。

雇主出了钱,你必须付出时间和精力。为了说明问题,就用一周工作40小时的美国标准来做参照吧。这40小时应该用来解决雇主的问题,而不是你自己的问题。

你应该计划每周工作60小时。前40小时是给雇主的,后20小时是给自己的。在这剩余的20小时里,你应该看书、练习、学习,或者做其他能提升职业能力的事情。

你肯定会说:“那我的家庭该怎么办?还有我的生活呢?难道我就该为雇主牺牲这些吗?”

在此,我不是说要占用你全部的业余时间。我是指每周额外增加20小时,也就是大约每天3小时。如果你在午饭时间看看书,在通勤路上听听播客,花90分钟学一门新的语言,那么你就都能兼顾到了。

做个简单的计算吧。一周有168小时,给你的雇主40小时,为自己的职业发展留20小时,剩下的108小时再留56小时给睡眠,那么还剩52小时可做其他的事呢。

或许你不愿那么勤勉。没问题。只是那样的话你也不能自视为专业人士了,因为所谓“术业有专攻”那也是需要投入时间去追求的。

或许你会觉得工作就该在上班时完成,不该再带回家中。赞成!那20小时你不用为雇主工作。相反,你该为自己的职业发展工作。

有时这两者并不矛盾,而是一致的。有时你为雇主做的工作让你个人的职业发展受益匪浅,这种情况下,在那20小时里花点时间为雇主工作也是合理的。但别忘了,那20小时是为你自己的。它们将会让你成为更有价值的专业人士。

或许你会觉得这样做只会让人精力枯竭。恰恰相反,这样做其实能让你免于枯竭匮乏。假设你是因为热爱软件而成为软件开发者,渴望成为专业开发者的动力也正是来自对软件的热情,那么在那20小时里,就应该做能够激发、强化你的热情的事。那20小时应该充满乐趣!

你知道什么是N-S(Nassi-Schneiderman)图表吗?如果不知道,那为什么不了解一下呢?你知道“米利型”(Mealy)和“摩尔型”(Moore)这两种状态机的差别吗?你应该知道的。你能不需查阅算法手册就可写出一个快速排序程序吗?你知道“变换分析”(Transform Analysis)这个术语的意思吗?你知道如何用数据流图进行功能分解吗?你知道“临时传递数据”(Tramp Data)的意思吗?你听说过“耦合性”(Conascence)吗?什么是Parnas表呢?

近50年来,各种观点、实践、技术、工具与术语在我们这一领域层出不穷。你对这些了解多少呢?如果想成为一名专业开发者,那你就得对其中的相当一大部分有所了解,而且要不断扩展这一知识面。

为什么要了解这些呢?这一行业发展迅速,许多旧见解似乎也已经过时了,不是吗?前半句似乎是显而易见的。确实,行业正迅猛发展,而有趣的是,从多个方面来看,这种进展都只是很浅层的。没错,我们不再需要为拿到编译结果苦等上24小时,我们也已经可以写出GB级别的系统,我们置身覆盖全球的网络之中,各种信息唾手可得。但另一方面,我们还是跟50年前一样,写着各种if和while语句。所以,改变说多也多,说少也少。

旧见解过时了这种说法明显是不对的。过去50年中产生的理念,已经过时的其实很少。有一部分理论确实在慢慢淡出,比如说“瀑布式开发”的理论确实不再流行了。但这并不表示我们不需要了解它,不需要知道它的长处和短处。

总的来说,那些在过去50年中来之不易的理念,绝大部分在今天仍像过去一样富有价值,甚至宝贵了。

别忘了桑塔亚纳的诅咒:“不能铭记过去的人,注定要重蹈覆辙。”

下面列出了每个专业软件开发人员必须精通的事项。

软件行业的飞速改变,意味着软件开发人员必须坚持广泛学习才不至于落伍。不写代码的架构师必然遭殃,他们很快会发现自己跟不上时代了;不学习新语言的程序员同样会遭殃,他们只能眼睁睁看着软件业一路发展,把自己抛在后面;学不会新规矩和新技术的开发人员更可怜,他们只能在日渐沦落的时候看着身边人越发优秀。

你会找那些已经不看医学期刊的医生看病吗?你会聘请那些不了解最新税法和判例的税务律师吗?雇主们干吗要聘用那些不能与时俱进的开发人员呢?

读书,看相关文章,关注博客和微博,参加技术大会,访问用户群,多参与读书与学习小组。不懂就学,不要畏难。如果你是.NET程序员,就去学学Java;如果你是Java程序员,就去学学Ruby;如果你是C语言程序员,就去学学Lisp;如果你真想练练脑子,就去学学Prolog和Forth吧!

业精于勤。真正的专业人士往往勤学苦干,以求得自身技能的纯熟精炼。只完成日常工作是不足以称为练习的,那只能算是种执行性质的操作,而不是练习。练习,指的是在日常工作之余专门练习技能,以期自我提升。

对软件开发人员来说,有什么可以用以操练的呢?乍一听,这概念显得荒唐。但是再仔细想一会儿,想想音乐家是如何掌握演练技能的。他们靠的不是表演,而是练习。他们又是如何练习的呢?首先,表演之前,都需要经历过特别的训练,音阶、练习曲、不断演奏等。他们一遍又一遍地训练自己的手指和意识,保持技巧纯熟。

那么软件开发者该怎样来不断训练自己呢?本书会用一整章的篇幅来谈论各种练习技巧,所以在此先不赘述了。简单说,我常用的一个技巧是重复做一些简单的练习,如“保龄球游戏”或“素数筛选”,我把这些练习叫作“卡塔”(kata)[3]。卡塔有很多类型。

卡塔的形式往往是一个有待解决的简单编程问题,比如编写计算拆分某个整数的素数因子等。练卡塔的目的不是找出解决方法(你已经知道方法了),而是训练你的手指和大脑。

每天我都会练一两个卡塔,时间往往安排在正式投入工作之前。我可能会选用Java、Ruby、Clojure或其他我希望保持纯熟的语言来练习。我会用卡塔来培养某种专门的技能,比如让我的手指习惯点击快捷键或习惯使用某些重构技法等。

不妨早晚都来个10分钟的卡塔吧,把它当作热身练习或者静心过程。

学习的第二个最佳方法是与他人合作。专业软件开发人员往往会更加努力地尝试与他人一起编程、一起练习、一起设计、一起计划,这样他们可以从彼此身上学到很多东西,而且能在更短的时间内更高质量地完成更多工作。

并不是让你花全部时间一直和别人共事。独处的时间也很重要。虽然我很喜欢和别人一起编程,但是如果不能经常独处,我也一样会发疯。

俗话说:教学相长。想迅速牢固地掌握某些事实和观念,最好的办法就是与你负责指导的人交流这些内容。这样,传道授业的同时,导师也会从中受益。

同样,让新人融入团队的最好办法是和他们坐到一起,向他们传授工作要诀。专业人士会视辅导新人为己任,他们不会放任未经辅导的新手恣意妄为。

每位专业软件开发人员都有义务了解自己开发的解决方案所对应的业务领域。如果编写财务系统,你就应该对财务领域有所了解;如果编写旅游应用程序,那么你需要去了解旅游业。你未必需要成为该领域的专家,但你仍需要用功,付出相当的努力来认识业务领域。

开始一个新领域的项目时,应当读一两本该领域相关的书,要就该领域的基础架构与基本知识作客户和用户访谈,还应当花时间和业内专家交流,了解他们的原则与价值观念。

最糟糕、最不专业的做法是,简单按照规格说明来编写代码,但却对为什么那些业务需要那样的规格定义不求甚解。相反,你应该对这一领域有所了解,能辨别、质疑规格说明书中的错误。

雇主的问题就是你的问题。你必须弄明白这些问题,并寻求最佳的解决方案。每次开发系统,都应该站在雇主的角度来思考,确保开发的功能真正能满足雇主的需要。

开发人员之间互相认同是容易的,但把一方换成雇主,人们就容易产生“彼”“此”之分。专业人士会尽全力避免这样的狭隘之见。

编程是一种创造性活动。写代码是无中生有的创造过程,我们大胆地从混沌之中创建秩序。我们自信地发布准确无误的指令,稍有差错,机器的错误行为就可能造成无法估量的损失。因此,编程也是极其自负的行为。

专业人士知道自己自负,不会故作谦逊。他们熟知自己的工作,并引以为荣;他们对自己的能力充满自信,并因此勇于承担有把握的风险。专业人士不是胆小鬼。

然而,专业人士也知道自己会摔跟头,自己的风险评估也有出错的时候,自己也有力不从心的时候。这时候,如果他们照照镜子,会看到那个自负的傻瓜正对着自己笑。

因此,在发现自己成为笑柄时,专业人士会第一个发笑。他从不会嘲讽别人,自作自受时他会接受别人的嘲讽。反之,他则会一笑了之。他不会因别人犯错就对之横加贬损,因为他知道,自己有可能就是下一个犯错的人。

专业人士都清楚自己的自负,也知道上天会注意到这种自负,并加以惩戒。如若果真遭遇挫折,最好的办法就是按照霍华德说的——一笑了之吧!

[PPP2001]:Robert C. Martin, _Principles, Patterns, and Practices of Agile Software____Development, _Upper Saddle River, NJ: Prentice Hall, 2002.

[1] 但愿他上了不错的错漏保险!

[2] [PPP2001]

[3] kata,这个词目前还没有公认的译法,可以理解为“套路”,或者某种固定的“形”。——译者注


相关图书

有限元基础与COMSOL案例分析
有限元基础与COMSOL案例分析
程序员的README
程序员的README
现代控制系统(第14版)
现代控制系统(第14版)
现代软件工程:如何高效构建软件
现代软件工程:如何高效构建软件
GitLab CI/CD 从入门到实战
GitLab CI/CD 从入门到实战
科学知识图谱:工具、方法与应用
科学知识图谱:工具、方法与应用

相关文章

相关课程