如何成为一名优秀的程序员
作者:左轻侯
8289字节
点击:44788
回复:7852
所属分类:技术随笔
创建时间:2006-06-27 22:38:58
最后修改时间:2006-06-27 22:38:58
如何成为一名优秀的程序员
左轻侯
2006.2.11
我一直想当然地认为《代码大全》(Code Complete)是一本讨论算法和数据结构的书,就象《编程珠玑》(Programming Pearls)一样。直到阅读了出版社发给我的样章以后,我才发现,不是那么一回事。在我收到的10章内容中,作者Steve McConnell广泛讨论了结对编程、代码检查、重构、测试、调试、增量集成、性能调整,甚至是程序员个人性格等诸多领域内的问题,并且结合自身的丰富经验,进行了鞭辟入里的分析。这些内容并没有涉及太多的代码,虽然偶尔也会涉及到代码。从这些内容来看,本书似乎应属于软件工程一类,但是又不能完全划分为软件工程类别。
在dearbook网站上的图书简介中写道:“……这也是一本完整的软件构建手册,涵盖了软件构建过程中的所有细节。它从软件质量和编程思想等方面论述了软件构建的各个问题,并详细论述了紧跟潮流的新技术、高屋建瓴的观点、通用的概念,还含有丰富而典型的程序示例。”照我看来,这个概括似乎仍然难以令人满意。如果用我自己的语言来描述,应该是这样:相对于关注代码本身(从算法到特定的编程语言)的图书,本书主要讨论的是代码以外的经验和技巧,它们涉及的范围极其广泛,从贴近代码层面的命名规则,到和代码相差十万八千里的“把程序员当人看”问题。其中有很多东西,已经远远超出传统意义上的软件工程的范围。但是,它们的最终目的,都是指向“如何写出高质量的代码”这一问题。
正如作者在前言中指出的:“我写这本书的首要目的,就是希望缩小本行业中一般商业实践与大师级人物及专家们之间的知识差距。”很多证据都表明,在程序编写这一行业中,新手的生产效率和经验丰富的专家相比,可以达到数量级的差距。如何在尽量短的时间内缩小这一差距,是每一个希望成为优秀程序员的读者都关心的问题。讨论代码层面的技术的图书已经汗牛充栋,相比之下,讨论代码以外的技术的图书就要少得多,而正如我们所知,产生优质代码的条件,决不仅仅取决于程序员对编程语言的熟悉。本书正是试图缩短这种差距的一次尝试,它的努力方向是将代码层面以外的实践经验传授给读者。
作者努力的结果是显而易见的。就象Samuelson的《经济学》影响了好几代经济学家一样,十几年来,这本书影响了一代程序员。我想任何一个程序员,在阅读了本书的目录以后,都很难不对它产生极大的兴趣。一个小小的例子是,一位从Redmond(微软总部)归来的同事告诉我,那里的开发人员人手一册《Code Complete》。
事有凑巧,在收到出版社的约稿之前,我正致力于在一个新成立的团队中构建他们的开发过程,这让我有机会实际接触到许多本书涉及的问题,并对它们进行思考。因此,我愉快地接受了为本书撰写书评这一任务,并希望结合自己的经验写出一些心得。由于我没有能够看到本书的完整内容,也由于时间和能力有限,我没有对全书进行整体的分析,而是采用了引用一部分原文再加以评论的方式。对于一本厚达964页的大书来,这无疑是管中窥豹,我只能希望读者能够从一斑中窥视到全豹的彪炳花纹。
第20章,软件质量概述
大部分研究都发现,检查比测试的成本更小。NASA 软件工程实验室的一项研究发现,阅读代码每小时能够检测出的缺陷要比测试高出80%左右(Basili and Selby 1987),另一个组织则发现使用测试来检测缺陷的成本是检查的6 倍(Ackerman, Buchwald and Lewski 1989)。后来,IBM 的一项研究又发现,检查发现一个错误只需要3.5 个工作时,而测试则需要花费15-25 个工作时(Kaplan 1995)。
在净室(ClearRoom)方法中,尽量将缺陷消灭在编码阶段而不是测试阶段是一个基本的思想。这种思想也许在更早的时代就已经有人提出过了,但似乎没有人把它运用到这样近乎极端的地步。在净室过程中,通过严格的代码复查(Code Review)来保证最少的缺陷。代码在进行复查之前甚至没有编译过(这意味着程序员不能再依赖编译器的强制语法检查),而通过复查的代码可以不经过模块级别的测试,就直接进行集成测试。程序员的表现由代码最终的缺陷数量来决定。
也许这种方法确实过于极端,但是这个基本方向是确凿无确的。依赖编译器和测试人员来找出缺陷,是程序员最大的恶习之一,即使不通过净室方法,也应该通过其他方法来加以避免。考虑到现实情况,完全的代码复查可能几乎无法实现,最大的原因在于生产率。实施净室过程后,一个程序员每月最终完成的代码量可能在200-300行,但是在我们面对的项目中,往往一个程序员一天完成的代码量都要远远超过这个数字。能够采取的平衡措施是,实行代码抽查,并且仍然在更大的程度上依赖测试人员(在本书中也提到,综合多种方法可以获得更高的缺陷排除效率)。这样至少可以尽量地提高代码的质量。
第23章,调试
就解决问题的表象而言,一种方法是随机的修改代码,直到你的代码看起来能工作。典型的思维逻辑是这样的:“这个循环好像有问题。可能是一个off-by-one 错误。让我先来写一个-1 试试。哦,这样不行。那么我就写个+1 试试。哈,看来程序正常工作了。我可以宣布问题搞定了。”
尽管这种方法受到了很多程序员的追捧,但它非常低效。随机地修改代码就如同是把一辆Pontiac Aztek 汽车转来转去,以为这样能修复它的引擎故障。你学不到任何东西,你只是在晃来晃去地浪费时间。你会争辩说随机修改程序是有效的,因为“我不知道这段代码到底出了什么事,我想试试这样修改,希望它有用。”不要随机修改代码。这就是所谓的“voodoo programming(巫毒编程)”。在没有理解代码的时候对它所做的修改越大,你对它能正确工作的信心就越低。
这是在初学者,甚至在某些有多年经验的程序员身上都能见到的习惯。据我个人的经验,在程序员者失去对解决问题的兴趣或感到疲惫的时候,最容易被这种习惯所左右。而某些程序员对解决问题从来就没有兴趣——他们并不试图理解问题,他们只是试图写出一段代码可以生成一个正确的结果而已。这种习惯是导致代码缺陷的最大来源之一。如果他们不改正这种习惯,将永远也无法成为优秀的程序员。
某次代码复查时,在进入代码的细节之前,一位程序员先向别人介绍他解决这个问题的思路。但他一开始就遇到了问题,他无法清晰地表述他的思路。进入代码层次之后,大家发现,他使用了一种非常古怪的方式来实现需要的功能。这种方式是如此古怪,以致于别人难以阅读他的代码,甚至他自己也无法清晰地表述。很明显,这是 “随机的修改代码,直到你的代码看起来能工作”的典型例子。
在编码之前,必须透彻地了解需要解决的问题,并且找到清晰的解决思路。如果在编码过程中发现原有的思路不够清晰,或者无法达到目的,必须先停下来重新思考,即使这样做的结果可能导致重写全部代码。
第34章,软件工艺
不要将编程思路局限到所用语言能自动支持的范围。杰出的程序员会考虑他们要干什么,然后才是怎样用手头的工具去实现他们的目标。
如果某个类的子程序成员与类的抽象不一致,你会为图省事用它,而不用更一致的子程序吗?应以尽量保持类接口抽象的方式写代码。不必因为语言支持全局数据和goto,就使用它们。要避免用这些有危险的编程特性,而代之以编程规范来弥补语言的弱项。编程要使用所用语言里最显而易见的方式。这等于说是“如果Freddie从桥上跳下来,难道你也愿意跳吗?”认真考虑你的技术目标,然后确定如何用你的语言最好地实现这些目标。
你的语言不支持断言?那就编写自己的assert()子程序,也许功能上与内置的assert()不完全一样,但你仍能实现其大部分用处。你的语言不支持枚举类型或具名常量?不碍事,可以按一定方式用全局变量定义自己的枚举或具名常量,只要有清楚的命名规范。
所有的人都在说:“语言不重要,重要是思想。”理论上这句话并不算错,但很少有人深入探讨这个问题的细节。
在不同的编程语言里,有一些东西是相通的,了解这些东西,就是了解编程的思想。但是这并不意味着,你一旦掌握了他们就能够精通所有的编程语言。每一门编程语言都在解决某些问题上有独到之处,这也是它们存在的意义。必须深入地学习需要掌握的语言,尽量透彻地掌握它的细节。在另一门语言上的经验有助于缩短你的学习过程,但不会取代学习过程。而深入了解一门语言的目的,正是为了用更好的方式贯彻编程思想。反过来,学习和实践一门优秀的语言,也会有利于你更深入地思考和理解编程的思想。
第33章,个人性格
聪明不像是个人性格的一个方面,也确实不是。碰巧的是,高智商与优秀程序员之间并无太密切的联系。
什么?!难道不需要智商很高吗 ?
对,是不需要。没人能同计算机那样迅速敏捷。要充分理解一个普通的程序,你得有很强的吸取细节的能力并同时消化它们。如何专注你的聪明才智,比你有多聪明更重要。
正如第5章“软件构建中的设计”所提到的,Edsger Dijkstra在1972年的图灵奖演讲会上宣读了一篇名为《The Humble Programmer.》(谦卑的程序员)的文章。他认为大部分编程工作都旨在弥补我们有限的智力。精通编程的人是那些了解自己头脑有多大局限性的人,都很谦虚。而那些编程糟糕的人,总是拒绝接受自己脑瓜不能胜任工作的事实,自负使得他们无法成为优秀的程序员。承认自己智力有限并通过学习来弥补,你会成为更好的程序员。你越是谦虚,进步就越快。
个人性格和编码能力是否有关?这是一个象上去相当玄虚的问题,也是一个争议很大的问题(二者互为因果)。就我个人的经验而言,我见过的许许多多程序员,他们的技术水平和谦虚程度成严格的正比关系,无一例外。而且,当一个人的技术水平提高时,他的谦虚程度也会随之提高。这话听上去简直都不那么能令人相信。
我们已经见过了太多too smart的程序员和他们写下的代码。这些代码充斥着故作高深的思路和晦涩难懂的代码,并成为炫耀的资本。事实上,过于复杂的东西跟软件开发的本质是相悖的,因为“致力于降低复杂度是软件开发的核心”(第34章《软件工艺》)。优秀的程序员写下的代码,必定清晰、简洁、优雅。
正如本书中所说:“编程的整个过程如同建造空中楼阁一样——这是人们能做的纯粹脑力劳动之一。”(第33章《个人性格》)软件开发在某种意义上就是表达人对现实世界的理解,因此,一个伟大的程序员必定是一个伟大的哲学家。而伟大的哲学家都很明白人类理性的局限,这就是谦虚的来源。