《程序员的职业素养》试读:第1章 专业主义


“噢,笑吧,科廷,老伙计。这是上帝,或者也可以说是命运或自然,跟我们开的一个玩笑。不过,不管这家伙是谁或是什么,他真幽默!哈哈!” ——¬霍华德,《碧血金沙》 这么说,你确实是想成为一名专业的软件工程师,对吧?你希望能昂首挺胸向世界宣告“我是专业人士”,希望人们充满敬意地注视着你,对你礼遇有加。希望母亲们会指着你告诉自己的孩子要成为像你这样的人。这些都是你想要的,对吧? 1.1 清楚你要什么 “专业主义”有很深的含义,它不但象征着荣誉与骄傲,而且明确意味着责任与义务。这两者密切相关,因为从你无法负责的事情上不可能获得荣誉与骄傲。 做个非专业人士可轻松多了。非专业人士不需要为自己所做的工作负责,他们大可把责任推给雇主。如果非专业人士把事情搞砸了,收拾摊子的往往是雇主;而专业人士如果犯了错,只好自己收拾残局。 如果你不小心放过了某个模块里的一个bug,以致公司损失了1万美元,结果将会怎样呢?非专业人士会耸耸肩说:“状况总是难免的嘛。”然后像没事儿人一样继续写下一个模块。而专业人士会自己为公司的那1万美元买单 ! 哇,自掏腰包?那可真让人心疼唉!但专业人士就必须这么做。实际上,专业主义的精髓就在于将公司利益视同个人利益。看到了吧,“专业主义”就意味着担当责任。 1.2 担当责任 想必你读过前面的引言了,对吧?如果没有,赶紧翻回去读一遍,因为本书将要讲的内容,都在其营造的语境里展开。 我曾因不负责任尝尽了苦头,所以明白尽职尽责的重要意义。 那是1979年,当时我是一家叫Teradyne的公司的“负责工程师”,所负责的软件控制着一个测量电话线路质量的小型机系统和微机系统,该系统的中央小型机通过带宽为300波特的拨号电话线与几十台控制测量硬件的外围微机连接在一起,程序是用汇编语言编写的。 我们的客户是各大电话公司的客服经理,他们每个人都负责10万条甚至更多的电话线路。我的系统负责帮助这些服务区经理抢在客户之前发现各种线路故障并及时修复。这可以减少客户投诉率,以免对此做监测的公共设施委员会相应下调电话公司收取的服务费。简单地说,这些系统极其重要。 每天晚上,这些系统都会运行“夜间例行程序”,即中央小型机会通知外围微机对所控制的电话线路进行检测;每天早上,中央计算机就能获取故障线路清单及其故障特征。根据这些报告,各服务区经理会安排人员修复故障,这样就不会有客户投诉了。 一次,我对几十个客户推出了一版新发布。“推出”这词可真是形象啊。我把软件写在磁带上,就把这些带子“推出”给客户了。客户载入这些磁带,然后重启系统。 这一新发布修复了几个小故障,还增加了客户要求的一项新功能。之前我们曾承诺会在截止日期之前提供那项新功能。我连夜赶工,总算在约定日期前交付了磁带。 两天后,我接到现场服务经理Tom的电话,他告诉我已经有好几个客户投诉“夜间例行程序”没能执行完成,他们没收到任何报告。我不由心头一沉:为了按时交付软件,我没测试“例程”。我测试了系统的其他大部分功能,但测试“例程”要费好几个小时,而当时我又必须交付软件。因为故障修复部分都不涉及“例程”部分的编码,所以我也没担心会有什么不妥。 收不到夜间报告,问题可就大了。修理工们会一时无事可忙但随后又要超负荷工作,而且,有些电话客户也可能会在这期间发现故障并投诉。要是弄丢一晚的数据,某一服务区经理肯定会打电话臭骂Tom。 我启动实验室系统,加载新软件,然后开始对“夜间例行程序”进行测试。几小时后,运行中断。“例程”运行失败!如果我在匆忙交付软件前对此进行测试,就不会发生服务区丢失数据的事了,服务区经理们这时也不会炮轰Tom了。 我打电话给Tom,说我能重现问题了。Tom告诉我其他大部分客户也已经打电话抱怨了,并问我什么时候能解决问题。我说我也没把握,但正在努力。同时我告诉他应该建议客户倒回去使用旧版软件。Tom发火了,说那对客户来说无疑是个双重打击,因为客户不仅为此丢失了一整个晚上的数据,而且还无法使用事先承诺的新功能。 故障排查非常困难,每次测试就要好几个小时。第一次修复失败了。第二次也没能成功。我试了好几次,等我发现问题所在时,好几天已过去了。这期间,Tom每隔几小时就打电话问我问题什么时候能解决,他也没少让我听那些服务区经理对他喋喋不休的抱怨,并一再告诉我让那些客户重新起用旧软件令他多么尴尬。 最后,我终于找出了缺陷所在,重新交付修复了问题的新程序,一切恢复正常。Tom也平静下来,不再提这段插曲,毕竟,他不是我的上司。事后,我的老板过来对我说:“你最好别再犯同样的错误。”我只能默默地点点头。 经过反省,我意识到未对“例程”进行测试就交付软件是不负责任的。为了如期交付产品,我忽略了测试环节,整个过程中只考虑要如何保全自己的颜面,却没顾及客户和雇主的声誉。我本该早点儿担起责任,告诉Tom测试还未完成、自己不能按时交付产品。那么做绝非易事,Tom一定会不高兴,但客户不会丢失数据,客服经理也不会打电话来轰炸。 1.3 首先,不行损害之事 那么,我们该如何承担责任呢?的确有一些原则可供参考。援引“希波克拉底誓言”或许显得有点夸张,但没有比这更好的引据了。的确,作为一名有追求有抱负的专业人士,他的首要职责与目标难道不正是尽其所能行有益之事吗? 软件开发人员能做出什么坏事呢?从纯软件角度看,他可以破坏软件的功能与架构。我们会探讨如何避免带来这些破坏。 1.3.1 不要破坏软件功能 显然,我们希望软件可以运行。没错,我们中的大部分人今天之所以是程序员,是因为我们曾带来了可用的软件,而且希望能再度体验那种成功创作的喜悦。但希望软件有用的不单单是我们,客户和雇主也希望它们能用。是啊,他们出钱,让我们去开发那些能按照他们意愿运行的软件。 开发的软件有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的测试。 1.3.2 不要破坏结构 成熟的专业开发人员知道,聪明人不会为了发布新功能而破坏结构。结构良好的代码更灵活。以牺牲结构为代价,得不偿失,将来必追悔莫及。 所有软件项目的根本指导原则是,软件要易于修改。如果违背这条原则搭建僵化的结构,就破坏了构筑整个行业的经济模型。 简言之,你必须保证,不需太高代价就可以。 不幸的是,实在是已有太多的项目因结构糟糕而深陷失败的泥潭。那些曾经只要几天就能完成的任务现在需要耗费几周甚至几个月的时间。急于重新树立威望的管理层于是聘来更多的开发人员来加快项目进度,但这些开发人员只会进一步破坏结构,乱上添乱。 描述如何创建灵活可维护的结构的软件设计原则和模式 已经有许多了。专业的软件开发人员会牢记这些原则和模式,并在开发软件时认真遵循。但是其中有一条实在是没几个软件开发人员会认真照做,那就是,如果你希望自己的软件灵活可变,那就应该时常修改它! 要想证明软件易于修改,唯一办法就是做些实际的修改。如果发现这些改动并不像你预想的那样简单,你便应该改进设计,使后续修改变简单。 该在什么时候做这些简单的小修改呢?随时!关注哪个模块,就对它做点简单的修改来改进结构。每次通读代码的时候,也可以不时调整一下结构。 这一策略有时也叫“无情重构”,我把它叫作“童子军训练守则”:对每个模块,每检入一次代码,就要让它比上次检出时变得更为简洁。每次读代码,都别忘了进行点滴的改善。 这完全与大多数人对软件的理解相反。他们认为对可工作软件不断地做一系列修改是危险的。错!让软件保持固定不变才是危险的!如果一直不重构代码,等到最后不得不重构时,你就会发现代码已经“僵化了”。 为什么大多数开发人员不敢不断修改他的代码呢?因为他们害怕会改坏代码!为什么会有这样的担心呢?因为他们没做过测试。 话题又回到测试上来了。如果你有一套覆盖了全部代码的自动化测试,如果那套测试可以随时快速执行,那么你根本不会害怕修改代码。怎样才能证明你不怕修改代码呢?那就是,你一直在改。 专业开发人员对自己的代码和测试极有把握,他们会极其疯狂随意地做各种修改。他们敢于随心所欲修改类的名称。在通读代码时,如果发现一个冗长的方法,他们肯定会将它拆分,重新组织。他们还会把switch语句改为多态结构,或者将继承层次重构成一条“命令链”。简单地说,他们对待代码,就如同雕塑家对待泥巴那样,要对它进行不断的变形与塑造。

>程序员的职业素养

程序员的职业素养
作者: Robert C.Martin
原作名: The Clean Coder:A Code of Conduct for Professional Programmers
isbn: 7115291578
书名: 程序员的职业素养
页数: 178
译者: 章显洲, 余晟
定价: 49.00元
出版社: 人民邮电出版社
装帧: 平装
出版年: 2012-9-1