Conner's profile☆ Conner Wang ☆PhotosBlogListsMore Tools Help

Blog


    March 28

    最近比较忙,而且有点不太顺

      自从上个星期六感冒了,一直到现在还没有好利索。手腕又受了伤,有好几天没有去健身了。
      这段时间挺忙的,事情太多,日程排的满满的。
      下面是本周的一些安排:
    周一:上午上课;下午下课,班助开会;晚上找班长谈话
    周二:上午上课;下午给接口实验室的老师调试服务器;晚上查宿舍
    周三:上午上课;下午给学生开班会;
    周四:上午去档案局;下午上课
    周五:上午上课;下午上课
      还要抽空补补J2EE的课,给同学处理图片,还要准备下周的专业英语讲课,另外还有DIP和CV的课本和阅读资料没有做。自已的学习计划还没有完成,争取周末的时候就能看完,把图书馆的书还上。
    希望下周能步入一个较慢一点的节奏,快受不了了,呵呵!

    March 13

    《代码大全》传奇[转载]

    久违了,代码大全

                                 □ 专题策划:孟岩 佘广 陈元玉
    《代码大全》的英文版名称是 Code Complete: A Practical Handbook of Software Construction。作者是美国Contrux公司总裁 Steve McConnell。 它获得1993年美国软件开发杂志Jolt大奖,被美国包括MIT在内的十多所大学作为计算机软件学科的教材。全书的中文名实际应该理解为《代码完成:软件创建实践手册》。
    《代码大全》这本书影响了90年代很多的程序员,帮助他们实现了自己在软件开发领域的梦想。在推出第二版的中译版之际,我们组织了一期关于《代码大全》的技术专题,一方面,回顾一下这本著作创作过程的前前后后,以及中译版的感人故事;另一方面,也对本书第二版向读者作一个介绍。在这里,让我们用法国作家图尼埃在他的《飞翔的吸血蝠》一文中的这段话来打开这本著作的传奇故事:
    “是的,书的自然的、不可遏止的志愿是离心的。它写出来就是要发表、传播、推广、被人买、被人读。那赫赫有名的作家的象牙之塔实为一座发射塔。总是要从那里回到作者,如同回到作家之不可或缺的合作者一样。一本书不是只有一个作者,而是有无数的作者。因为在创造行为中,读过的人、正在读或将要读的人之总和有充分的权利加诸那个写的人身上。一本书写出但尚未被阅读,其存在是不完全的。
    它只拥有半个存在。那是一种潜在性、一个没有血肉的、空的、不幸的生命。它要活起来就要呼唤帮助。一个作家出版一本书的时候,他知道他是朝着一群无名无姓的男人和女人放出一大群纸鸟,一大群干瘪的、渴望着血的吸血蝠,它们散开来寻找读者,碰上谁是谁。一本书一旦冲向一个读者,就立刻因他的热、他的梦而膨胀起来。它绽开花朵,终于实现了自身……”
     
    《代码大全》传奇

                                        □ 文/金戈
    《代码大全》(第2版)的中文版已经面世,我作为本书译者之一,受《程序员》杂志之邀,来写一篇文字,讲讲《代码大全》这一传奇佳作背后的故事,实在荣幸。
    讲这本传奇佳作的故事,还要从它背后的传奇人物说起,他就是Steve McConnell(斯蒂夫·麦克奈尔)。
    距离微软美国总部和波音公司不远的地方,就是华盛顿州的第五大城市——Bellevue。McConnell就和他的妻儿住在这个美丽的地方。
    McConnell是一位牧师的儿子,然而他选择了一条不同的道路。早年,McConnell在华盛顿州的Whitman大学学的是哲学系,并取得了学士学位。当时,学计算机只是他的第二计划。
    正是在大学的计算机编程课堂上,McConnell最早接触到编程。对他来说,编程序并不是什么难事,然而直到毕业的时候,他也不知道自己以后要做什么。McConnell心想,反正学过编程,出去就能找到程序员的工作,一边工作一边再慢慢地想以后到底要干什么吧。就这样,在走出校园后的那几年,McConnell就一直在寻寻觅觅,想知道自己以后到底要做什么。直到一天早上,他一觉醒来之后突然就意识到,原来他已经在做着他想做的事情了——做一名软件开发人员。从此以后,McConnell就和编程结下了不解之缘。
    McConnell在大学实习阶段就开始为一家保险公司写程序,积累了一些编程经验。后来,McConnell去了另一家软件公司,编写面向最终用户的软件,又积累了不少经验,却最终由于公司差劲的管理和不佳的道德而选择了离开。不过在这段时间, McConnell知道了IEEE(电子工程学会),并决定长期为该组织撰稿写作,这也成为他职业生涯中的一项重要选择。
    1989年从那家公司离职后,McConnell已经有了四年多在公司工作的经验。这时他放弃了给某家公司固定打工的念头,攒了大半年的备用金,收集了西雅图地区一些大的科技公司的联系方式,开始了新的工作。McConnell一边做着他的咨询工作,一边读着“成人自考”。他所服务过的公司就包括有大名鼎鼎的波音和微软。最终,McConnell在西雅图大学以优等成绩获得软件工程硕士学位,并被列入该校美国大学优等生荣誉学会,几年后他还成为该校的副教授呢。
    接下来,McConnell又想做另一件事了,就是写一本书了。他很想把他这么多年来的编程经验和所学到的有用知识写出来和其他人分享。于是,他花了一年半的时间完成初稿,交给出版社,而后又历经了11个月的时间完成终稿,又花了11个月的时间进行编辑,最终完成了这本处女作,并在1993年由微软出版社出版。按McConnell的话说,他就像做一项软件工程一样精心地写作这本书,前后花了近4年的时间。如果再算上McConnell此前积累经验、收集素材、整理代码等等,真可谓是十年磨一剑啦。
    这本书,正是被我们称为传奇之作的《Code Complete》。
    1994年,McConnell所写的这本《Code Complete》被美国《软件开发》杂志授予震撼大奖(Jolt Award),这可是素有软件业界奥斯卡之奖之称的巨大荣誉。
    在Amazon网站上,这本13年前的著作至今已被上百位读者打过分[LD1],目前得分是4.5颗星,可见它在读者心中的价值。让我们来看看国外的读者们读了此书之后都说了些什么吧:
    ◆ 如果你只想买“一”本关于软件开发的书的话,就买这一本吧!
    ◆ 要让这本书发挥最大的功效,一定要把它放在身边随时备用……直到你的同事把它“顺”走。然后你还得再买一本,还是要放在触手可及的地方。如此反复,直到你身边到处都能找到这本书的时候,这时候再买一本自己留好。从1993年到现在(这是读者1996年10月发的评论),我已经“经手”11本《Code Complete》了,不过我还是觉得它物有所值!
    ◆ 是程序员就一定要读过这本书!然后再读一遍!之后……找个时间再读一读!把它放在你的桌上(现在它应该已经够旧了)——让别人把它“偷走”——然后再买一本回来——如此循环往复……
    ◆ 我想,我从来没见过如此吸引人的计算机书——写得真好,关于构建软件的几乎所有细节都写得恰到好处……我已经读过两遍了,每一遍都读得很爽。我曾把这本书当成结婚礼物送给我的一个朋友,他也是做程序员的,可没过多久他就差不多快离婚了——因为在度蜜月的时候他还只顾着读这本书……
    ◆ 这本书里所讲的内容在学校里没人教过,但是学校真应该教教这些内容!
    最后这位读者说的没错,这本书的内容在当时美国教计算机的学校是不教的。当时的美国高校逐渐呈现出两极分化的趋势,传统的计算机科学(Computer Science)教育不能很好的适应业界的人才需要,因此亟待加强软件工程(Software Engineering)方面的教育。随着《Code Complete》这本书的影响力越来越广,作为一本内容翔实、生动、全面、权威的软件构建与编码技术手册,它轻理论而重实践的特点获得很多高校的青睐,于是美国包括MIT(麻省理工学院)在内的十多所大学都最终将其作为计算机软件学科的教材。可以说,这本书影响了全世界很多国家一代的程序员。
    到今天,McConnell已经著有7本书,而其中的3本都曾获得《软件开发》杂志的震撼大奖或生产力大奖,这不能不说是一个软件业界作家不可跨越的奇迹。1998年,《软件开发》杂志的读者将McConnell评为软件行业中最具影响力的三人之一,与大名鼎鼎的Bill Gates和Linus Torvalds齐名。

    Steve McConnell的7本著作(1993-2006)
    ● 1993年——《代码大全》(Code Complete)Amazon网站4.5星。
    ● 1996年——《快速软件开发》(Rapid Development),关于优化软件开发计划的策略和最佳实践。Amazon网站5星。
    ● 1998年——《软件项目生存指南》(Software Project Survival Guide),手把手教你成功运作软件项目的指导手册。Amazon网站4.5星。
    ● 1999年——《淘金热过后》(After the Gold Rush),创建真正的软件工程专业。Amazon网站3.5星。
    ● 2004年——《专业软件开发》(Professional Software Development),《淘金热过后》一书的第二版,还是讲软件工程专业的事情。Amazon网站4星。
    ● 2004年——《代码大全(第2版)》(更新了大量内容,如Web开发、面向对象软件开发、敏捷软件实践,以及其它现代软件构建问题。)Amazon网站5星。
    ● 2006年——《Software Estimation》,论述软件项目规划与估算的专业著作。
    在1993年《Code Complete》刚发布之后,北京希望电脑公司和学苑出版社就从微软出版社引进了此书,由天奥主持翻译,并于同年11月首印10000册发行——速度可谓是“相当”地快了。
    不知道今天手捧《程序员》杂志的各位读者,有多少在12年前就在写程序的?90年代初期,中国的软件开发还非常不成熟,IT行业也刚刚起步,从事计算机软件开发的人员也是凤毛麟角,十分稀少。在那样的环境下,甭说软件工程了,能把一本专业的外文计算机图书翻译过来并在如此短的时间内出版已经是难能可贵了。受限于当时国内软件业相对落后的水平,当初的译本并非尽善尽美——尤其是对《Code Complete》这一书名的翻译,就更是引发了不小的争议。
    Code Complete用做这样一本书的书名,到底是什么意思呢?我们不妨对比其它一些常见的说法:Mission Complete——“任务完成”(游戏中常见);Download Complete——“下载完成”(浏览器中常见)……那么,Code Complete不就是“编码完成”的意思吗?
    我了解到,在一些现代软件工程中,“Code Complete”常常是指整个软件开发过程中一个重要的里程碑,就像更为耳熟能详的Beta、Final、Release Candidate(RC)以及Release-To-Manufacture(RTM)等等代号或称呼一样。在开发一个软件的过程中,到达这个里程碑,就意味着已经编写完成软件规格中所列出的所有功能了。当然,这里所谓的“完成”还只是在在局部而言,此后还需要进行系统级的代码集成与测试才能达到“产品完成”的程度。
    在软件工程到达“Code Complete”这一里程碑之前的主要工作内容,就是逐层地完成系统中的每一个部件——从一个个变量、一条条语句聚成一个个子程序、一个个类,再到一个个包、一个个子系统……直到所有这些部件把软件规格中所定义的所有功能特性都实现完成。
    这,才是《Code Complete》一书的主题所在——教会你为了到达“编码完成”这一重要里程碑所必需的所有软件构建技术。
    本书把软件构建过程中的方方面面讲的淋漓尽致,尤其是细微之处,更是能够窥见作者深厚的编码功力和丰富的编码经验。从内容上讲,全书确实是关于软件构建技术的“大全”之作。如此说来,当初这么一个简单的主谓结构短语被误译为 “代码大全”之后,却也被大多数业内人士所接受、认可甚至广为流传,还是有一定道理的。
    当然了,在现代的集成开发环境(IDE)中,“code complete”还有另外一个意思,就是“补全代码”——一种根据代码的上下文自动把不完整的代码补充完整的功能。如果有些人把这个意思认定为本书主题的话,那就实在是谬误至极了。
    摘自熊可宜对《代码大全》(第1版)的评价
    第一次阅读《代码大全》时,是在大约8年前,我读大学时。觉得读不懂,因为自己才刚刚抛弃Basic,开始学习C语言,除了一些习题,并没有多少编程的实际经验,书中的许多概念与方法都觉得非常陌生。随着一个DOS下的绘图软件Romantic Painter的开发,随着自己在开发这种较大软件时不断遇到各种问题,就越来越觉得《代码大全》不但提供了关于代码创建的最丰富的实践指南,而且就像一位导师逐渐辅导你成为一个真正专业的软件开发者。《代码大全》的英文名称是Code Complete,即代码完成,这是软件开发中的创建阶段的里程碑,即所有代码都编写完成了。而《代码大全》这个名字实际上应该理解为代码创建大全。
    盖茨说过微软最重要的财产就是代码。不错,软件开发中所有的关键活动,最终的目的都为了能够创建出正确的健壮的最好用的代码。而这本书,10年前写的书,至今仍未过时,因为它所探讨的内容不是表面的现象而是关于代码创建的内在本质。毫不夸张地说,这是世界上关于代码创建的最为丰富最为深刻的实践指南。

    由于年代久远,当年的《代码大全》也早已绝版,市面上甚至很多图书馆中也根本就见不到这本传奇之作的影子了。于是,2001年前后,在网友bear(熊可宜)的牵头带领下,百十来位素不相识的网友在“学苑版”《代码大全》的基础之上,历经4个多月的不懈努力,终于修订成了《代码大全》电子版图书。这些是近年来很多程序员能以窥此书的唯一途径了。
    事实上,“代码大全”这四个字从它在十多年前被确定下来之时,就注定要和这本书一起成为经典的代名词,甚至成为一个品牌。鉴于“代码大全”的大名早已深深印在一代程序员的心中,最终我们决定在本书的第2版中继续沿用这一“恰如其分”的错误,也借此向原书第1版各位译者、修订者们的辛勤劳动表示我们的敬意。
    时过境迁,再加上计算机行业本来就发展迅速,原书的一些内容已经看上去有些过时了——主要是书中所有示例所用的编程语言,有些早已淡出了历史舞台。而且McConnell在这几年间又有了更多的经验和感悟,他希望把这些内容也补充到原书中,让经典继续发扬光彩。于是他开始大幅度地修订《Code Complete》,让书中的内容与时俱进。没想到,这件事远没有想象的容易。
    在这十多年间,关于编程的新鲜概念层出不穷。编程技术已经全面地“面向对象”了;软件过程与方法也越来越“敏捷”了;尤其是随着基于Web的软件开发逐渐兴起,软件发行的节奏已经彻底地改变了,软件项目的周期变得越来越短,软件过程自然也需要适应这一变化;编程语言也得以迅猛发展,原书写作时McConnell所熟悉的Ada、C语言已经逐渐不再适应现今主流的软件开发任务了,而面向对象的开发语言,如Java、C++、C#等等日益成为程序员们的主流选择;伴随着全社会对计算机软件越来越强烈的需求,软件项目节奏的加快,也必定带动了诸如重构、测试驱动开发等编码技术的发展……等等。
    终于,2004年《Code Complete》第二版由微软出版社发行,再一次引起了编程类图书市场的火爆。用Amazon网站上读者评论的话来说:The Best Gets Better!新版的《Code Complete》继续演绎着传奇佳作的魅力,经过Amazon网站上数十位读者的评分,目前该书还保持着5颗星的佳绩,并在上架后相当长的一段时间内名列计算机编程类图书的销售榜首。这不得不让人对McConnell这位IT写作奇才佩服得五体投地。
    这次电子工业出版社引进《Code Complete》的第2版,实在是国内广大程序员的一件幸事。当年读过《代码大全》第1版的那一代程序员现如今有的已经走上领导岗位,也有的转向了其它的行业。国内的程序开发人员终于有机会再次读到这本风靡全球的软件构建与编码技术宝典。
    世界上最优秀的程序员们都是读过这本书的,你呢?
    [LD1]注:Amazon网站是在1995年7月才对外营业的,所以已经找不到更早的读者评论了。
     
    如何成为一名优秀的程序员?
                                  □ 文/左轻侯

    我一直想当然地认为《代码大全》(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章《个人性格》)软件开发在某种意义上就是表达人对现实世界的理解,因此,一个伟大的程序员必定是一个伟大的哲学家。而伟大的哲学家都很明白人类理性的局限,这就是谦虚的来源。
     
    如何编写高质量的代码
    ——来自《代码大全(第2版)》的启示

    □ 编译/陈硕

    软件的首要技术使命是管理复杂度,计算先驱Edsger Dijkstra指出,只有在“计算(Computing)”这种职业中,人的思维需要从一个字节大幅跨越到几百兆字节——跨度为109比1,也就是9个数量级1。Dijkstra还指出,没有谁的大脑能容得下一个现代的计算机程序,也就是说,作为软件开发人员,我们不应该试着在同一时间把整个程序都塞进自己的大脑,而应该试着以某种方式去组织程序,以便能够在一个时刻可以专注于一个特定的部分。这么做的目的是尽量减少在任一时间所要考虑的程序量,你需要同时记住的东西越多,就越可能漏掉其中的某一个,从而导致设计或编码的错误。
    尽管谁都希望成为英雄,自如地应对各种计算机问题,但没有人的大脑真正有能力同时掌握9个数量级的细节。计算机科学和软件工程已经开发了许多智力工具,来应对这种复杂度,《代码大全》围绕这一主题作了详尽的讨论。
    ◆ 在架构层将系统划分为多个子系统,以便让思绪在某段时间内能专注于系统的一小部分。(第5章)
    ◆ 仔细定义类接口,从而可以忽略类内部的工作机理。(第6.1节)
    ◆ 保持类接口的抽象性,从而不必记住不必要的细节。(第6.2节)
    ◆ 避免全局变量,因为它会大大增加总是需要兼顾的代码比例。(第13.3节)
    ◆ 避免深层次的继承,因为这样会耗费很大精力。(第6.3节)
    ◆ 避免深度嵌套的循环或条件判断,因为它们都能用简单的控制结构取代,后者占用较少的脑力资源。(第19.4节)
    ◆ 别用goto语句,因为它们引入了非顺序执行,多数人都不容易弄懂。(第17.3节)
    ◆ 小心定义错误处理的方法,不要滥用不同的错误处理技术。(第8.3节)
    ◆ 以系统的观点对待内置的异常机制,后者会成为非线性的控制结构。异常如果不受约束地使用,会和goto一样难以理解。(第8.4节)
    ◆ 不要让类过度膨胀,以至于占据整个程序。(第6章)
    ◆ 子程序应保持短小。(第7.4节)
    ◆ 使用清楚、不言自明的变量名,从而大脑不必费力记住诸如“i代表账号下标,j代表顾客下标,还是另有它意?”之类的细节。(第11章)
    ◆ 传递给子程序的参数数目应尽量少。更重要的是,只传递保持子程序接口抽象所必需的参数。(第7.5节)
    ◆ 用规范和约定来使大脑从记忆不同代码段的随意性、偶然性差异中解脱出来。(第4.2节,第31、32章)
    ◆ 只要有可能,一般情况下应避免“偶然性困难”2。(第5.2节)
    如果将复杂的逻辑判断代码放入布尔函数,并将其意图概括出来,就可以降低代码的复杂程度(第19.1节)。用查表法代替繁琐的逻辑链,也能达到同样目的(第18章)。如果采用定义良好的一致的类接口,你就无须操心类的实现细节,从而整体上简化自己的工作。
    采用编码规范主要也是为了降低复杂度。如果在格式编排、循环、变量命名、建模表示法等方面有统一的考虑,就能将精力集中于更具挑战性的编码问题上。规范最有用之处在于它们能免于你做出任意决定,省却了为之辩解的麻烦。
    各种形式的抽象对于管理复杂度都是很强大的工具。通过增强程序组件的抽象性,编程领域已经取得了很大的进步。Fred Brooks指出,计算机的科学最了不起的成就,就是从机器语言跃进到高级语言,解放了程序员——我们不用再操心某种特定的硬件细节,而能够专心于编程。子程序的想法则是另一个巨大的进步,随后的重要进步是类和程序包。
    以其功能对变量命名,说明问题是什么,而非其怎样实现,能提升其抽象层次。如果你说:“这是弹出栈,意味着我在取最近雇员的信息”,那么抽象使你可以省掉记住“弹出栈”的脑力步骤,你只需简单地说“我在取最近雇员的信息。”这一长进是微不足道的,但当你要减少从1到109这么大范围的复杂度时,任何改进措施都是值得的,勿以善小而不为。采用具名常量而非文字量(神秘数值)也能提高抽象级别。面向对象的编程方法提供同时适用于算法和数据的抽象,单靠功能分解做不到这一点。
    总而言之,软件设计与构建的主要目标就是征服复杂度。许多编程实践背后的动机正是为了降低程序的复杂度。降低复杂度几乎是衡量程序员成果的最重要依据。这是《代码大全》体现的最主要的编程思想。(虽然这本书从头至尾没有正式提到过“编程思想”这个词。)
    以上讨论“抽象”的文字本身也够抽象的,下面谈谈具体的、看得见摸得着的代码。
    何谓“高质量的代码”
    就“高质量的代码”而言,正确性、简单性、清晰性是首要的[SA04, Item 6],可测试性也同样重要。清晰性(可读性)是“易于维护、易于重构的程序”最有价值的特性。若无法读懂代码,你就不能有信心地修改,也无法调试和修正错误。阅读代码的次数要比编写代码多得多,即使在开发的初期也是如此。
    因此,为了让编写代码更方便而降低代码的可读性是非常不经济的。一项可读性原则是应该把修改你代码的人记在心上。编程首先是与人交流,其次才是与计算机交流。代码的维护者会感激你使代码容易理解——而且将来的维护者很可能就是你自己,到时候你得尝试记起自己六个月以前在想什么。
    可测试性指的是能很方便地用自动化的手段来测试你的程序,把代码应有的功能用另一种形式(测试用例)描述一遍,等于给代码再加一道保险,降级出错的可能。下面两句话经常被引用来说明代码可读性的重要。
    程序必须是写给人看的,仅仅偶尔才在机器上执行。——Harold Abelson等人[SICP]
    编写程序首先为人,其次为计算机。——Steve McConnell[M04, Section 34.3]
    与之相比,复用性、高效率就显得不那么重要,“使正确的程序变快”远远比“使快的程序变正确”容易得多[SA04, Item 8]。清晰的代码更容易写正确,更容易理解,更易于重构——因此更易于性能优化。
    至于富于技巧(tricky)、聪明(clever)更可算是代码的恶劣品质,编程不是为了炫耀自己的聪明程度,这样写程序简直是歪门邪道。不能手里拿个铁锤,就把满世界都看成钉子。(比如在重载操作符的时候应该保持其自然语义,否则宁可用具名子程序来实现相同的操作。[SA04, Item 26])Dijkstra在1972年的图灵奖演讲会上宣读了一篇名为《The Humble Programmer》(谦卑的程序员)的文章。
    他认为大部分编程工作都旨在弥补我们有限的智力。精通编程的人是那些了解自己头脑有多大局限性的人,都很谦虚。而那些编程糟糕的人,总是拒绝接受自己脑瓜不能胜任工作的事实,自负使得他们无法成为优秀的程序员。研究表明,谦虚的程序员善于弥补其不足之处,使用能奏效的最简单的技术,所编写的代码让自己和他人都易看懂,其中的错误也较少。
    调试代码的难度是首次编写这些代码的两倍。因此,如果你在编写代码的时候就已经发挥了全部聪明才智,那么按照常理,你将无法凭借自己的智慧去调试这些代码。——Brian Kernighan[KP78]
    那么代码的可读性具体体现在哪些方面呢?大致有以下几点。一是名字,最常见的有类名、子程序名、变量名;二是长度,比如类的长度、数据成员的数目、子程序的长度、子程序的参数数目、语句的嵌套层数;三是复杂度,包括表达式的复杂度、语句逻辑的复杂度等;四是耦合度,包括由于共享数据(含全局数据)导致的耦合、类之间耦合(继承、组合、友元)、子程序之间的耦合等;五是格式,包括缩进、空格、注释等。
    下面谈谈其中三点影响代码可读性的因素。
    名不正则言不顺
    “为变量命名”恐怕是编程中最普通的一项活动,一般介绍编程风格的书都会用几页的篇幅给出一些好的建议[KP99, Section 1.1],而《代码大全》用了整整一章30多页的篇幅(第11章)来讨论变量的命名,另外第7.3节专门讨论子程序的命名,第6.2节讨论了类的命名。如果变量、子程序和类型命名得当,代码本身就能用作程序的文档,可以减少注释和外部文档(第32.2节)。
    变量名
    为变量命名时最重要的考虑事项是,该名字要完全、准确地描述出该变量所代表的事物。currentDate和todaysDate都是很好的名字,因为它们都完全而且准确地描述出了“当前日期”这一概念。事实上,这两个名字都用了非常直白的词。程序员们有时候会忽视这些普通词语,而它们往往却是最明确的。cd和c是很糟的命名,因为它们太短,同时又不具有描述性。current也很糟,因为它并没有告诉你是当前的什么。date看上去不错,但经过最后推敲它也只是个坏名字,因为这里所说的日期并不是所有的日期均可,而只是特指当前日期;而date本身并未表达出这层含义。x、x1和x2永远是坏名字——传统上用x代表一个未知量;如果你不希望你的变量所代表的是一个未知量,那么请考虑取一个更好的名字吧。
    名字应该尽可能地明确。像x、temp、i这些名字都泛泛得可以用于多种目的,它们并没有像应该的那样提供足够信息,因此通常都是命名上的败笔。有人也许会反驳说,把i用作循环下标是最正常不过的了,难道非得写成indexOfTheLoop这种又臭又长的名字才算好吗?
    Steve McConnell认为,如果循环只有寥寥数行,而且只是单层循环,那么用i是也是可行的。不过试想一下,如果你一直习惯用i作循环下标,而你将来可能需要把这个循环放到另一个循环中去执行,即循环嵌套,那么内外层循环都用i作下标肯定是不行的。如果编译器提醒你说变量i重复定义,那还算走运;如果编译器默不作声,而你自己又忘了修改,呃,你听见虫子飞舞的声音了吗?由于代码会经常修改、扩充,或者复制到其他程序中去,因此很多有经验的程序员索性不使用类似于i这样的名字。
    如果循环不是只有几行,那么代码阅读者会很容易忘记i本来具有的含义,因此最好给循环下标换一个更有意义的名字。导致循环变长的常见原因之一是出现循环的嵌套使用。如果你使用了多个嵌套的循环,那么就应该给循环变量赋予更长的名字以提高可读性:
      for (int teamIndex = 0; teamIndex < teamCount; teamIndex++) {
       for (int eventIndex = 0; eventIndex <
    eventCount[teamIndex]; eventIndex++){
       score[teamIndex][eventIndex] = 0;
    }
      }
      
    谨慎地为循环下标变量命名可以避免产生常见的下标串话(index cross-talk)问题:想用j的时候写了i,想用i的时候却写了j。同时这也使得数据访问变得更加清晰:score[teamIndex][eventIndex]要比score[i][j]给出的信息更多。
    如果你一定要用i、j、k,那么不要把它们用于简单循环的循环下标之外的任何场合——这种传统已经太深入人心了,一旦违背该原则,将这些变量用于其他用途就可能造成误解。要想避免出现这样的问题,最简单的方法就是想出一个比i、j、k更具描述性的名字来。
    变量名的最佳长度似乎应该介于x和maximumNumberOf PointsInModernOlympics之间。太短的名字无法传达足够的信息。诸如x1和x2这样的名字所存在的问题是,即使你知道了x代表什么,也无法获知x1和x2之间的关系。太长的名字很难写,同时也会使得程序的视觉结构变得模糊不清。
    研究发现,当变量名的平均长度在10到16个字符的时候,调试程序所需花费的气力是最小的。平均名字长度在8到20个字符的程序也几乎同样容易调试。这项原则并不意味着你应该尽量把变量名的长度控制在9到15或者10到16个字符。它强调的是,如果你查看自己写的代码时发现了很多更短的名字,那么需要认真检查,确保这些名字含义足够清晰。
    子程序名
    好的子程序名字能清晰地描述子程序所做的一切。《代码大全》第7.3节列举并详细说明了若干条指导原则:描述子程序所做的所有事情,避免使用无意义的、模糊或表述不清的动词,不要仅通过数字来形成不同的子程序名字,根据需要确定子程序名字的长度,给函数命名时要对返回值有所描述,给过程起名时使用语气强烈的动词加宾语3的形式,准确使用对仗词,为常用操作确立命名规则等。
    类名
    类的名称应该表达了其中心目的,准确的描述该类的接口所模塑的抽象概念(第5.3节),一般用名词。
    无论如何,命名不是一锤子买卖,一旦发现有更好的名称,借助现代的IDE工具(Eclipse或Visual Studio 2005),我们很容易对变量、常量、类、子程序进行重命名(rename),这恐怕也是用得最多的一项重构操作了。
    宜短不宜长
    很多编程书籍都告诉我们不要写过长的子程序[SA04, Item 20],那么子程序写多长才合适呢?《代码大全》第7.4节专门讨论了这个问题。与一般书不同的是,McConnell不是以一个先知的口吻说“汝当如何如何”,而是列出了学术界的十多项研究成果,然后分析作结论。
    有研究表明,子程序的长度与错误量成反比,即:随着子程序长度的增加(上至200行代码),每行代码所包含的错误数量就会减少。另一项研究则发现,子程序的长度与错误量没有关联,而结构复杂度以及数据量却与错误量有关。还有研究发现,短小的子程序(含有32行或更少代码)与更低的成本或错误率无关。有证据表明,较长的子程序(含有65行或更多代码)使得每行代码的成本更低。……IBM所做的一项研究发现,最容易出错的是那些超过500行代码的子程序。超过500行之后,子程序的出错率就会与其长度成正比。
    这似乎与我们平时接受的“子程序越短越好”的教导相违背。McConnell认为,在任何时候,复杂的算法总会导致更长的子程序。在这种情况下,可以允许子程序的长度有序地增长到100至200行(不算源代码中的注释行和空行)。数十年的证据表明,这么长的子程序也和短小的子程序一样不易出错。与其对子程序的长度强加限制,还不如让其他因素——如子程序的内聚性、嵌套的层次、变量的数量、决策点的数量、解释子程序用意所需的注释数量以及其他一些跟复杂度相关的考虑事项等——来决定子程度的长度。
    这就是说,如果要编写一段超过200行代码的子程序,那就要小心了。对于超过200行代码的子程序来说,没有哪项研究发现它能降低成本和/或降低出错率,而且在超过200行后,迟早会在可读性方面遇到问题。
    不过,话说回来,在一开始写程序的时候,可以不必在意这个限制。在写完一个子程序,实现了应有的功能,并通过单元测试之后,如果它过长,我们可以很容易地用Extract Method重构法对它进行改进,使之符合项目编码标准中规定的子程序长度。
    McConnell似乎对数字7情有独钟,他建议把子程序的参数个数限制在大约7个以内(第7.4节),告诉我们要警惕拥有超过约7个数据成员的类,并把基类的派生类总数(注意不是继承体系的层数)限制在7±2等(第6.3节)。当然,书中都给出了理由,这里就不赘述了。
    格式与规范
    《代码大全》第31章专门介绍代码的布局与风格,前面提到过,编码规范最有用之处在于让你避免做出武断决定,避免把时间花在无谓的争执上(第34.5节)。McConnell并不像一位“家具警察”那样对待代码的格式,他认为好的代码布局应凸现程序的逻辑结构,使代码易于阅读、理解、检查及修改。至于循环体应该缩进几个空格,大括号的摆放位置这些问题,正确答案不止一种。每次回答同样内容比起只是回答正确更重要。
    第28.5节谈到了程序员的信仰问题,缩进风格、大括号的摆放位置、注释风格、命名习惯、对goto的使用、对全局变量的使用等等都是十分敏感的话题。关于这种问题,我觉得Herb Sutter和Andrei Alexandrescu的观点更贴近程序员的想法[SA04, Item 0]。
    那些“仅仅是个人品味、而不影响正确性或可读性的”议题不应出现在编码标准中。任何一个专业的程序员都应该能轻易地阅读并编写“那种格式与自己的习惯略有不同的”代码。
    每个源文件(甚至每个项目)内确保采用一致的编排格式,因为在同一块代码中切换若干种风格是很不和谐的。但是不要试图对多个项目(甚至对整个公司)强制使用相同的编排格式。 ◆ 不要指明缩进多少字符,但缩进要显出结构:你愿意用多少个空格来缩排都行,但至少每个文件保持一致。
    ◆ 不要规定每行的长度,但确保可读性。
    ◆ 不要规定注释的风格(某些工具将特定风格的注释提取为文档的情况除外),但一定编写有用的注释:只要有可能,尽量以代码代替注解。不要编写与代码重复的注解;这些注解会逐渐变得与代码不同步。一定编写说明性的注解,以解释所用的方法和基本原理。
    ……
    关于大括号的摆放,以下数种做法在可读性上没有区别:
      void using_k_and_r_style() {
       // ...
      }
      
      void putting_each_brace_on_its_own_line()
      {
       // ...
      }
      
      void or_putting_each_brace_on_its_own_line_indented()
      {
       // ...
      }
      
    如果你知道什么样的代码才是高质量的,那么怎样才能编写出这种代码呢?McConnell认为,好习惯很重要,因为程序员做的大部分事情都是无意识完成的(第33.9节)。例如,你曾想过该如何格式化缩进的循环体,但现在每当写新的循环体时就不再去想了,而以习惯的方式来做。对程序格式的方方面面几乎都是如此。你上次质疑编排风格是什么时候?如果你有五年编程经验,最后一次提出这个问题多半是在四年半之前,其余时间都是按习惯编程的。Bill Gates说过,任何日后出色的程序员在入行的前几年就做得很好,从那以后,程序员的优劣就定型了。其实任何行当都是如此,因此在初涉编程时,就应端正态度来学,尽快培养良好的习惯。
    说明:这篇文章大量文字直接取自《代码大全(第2版)》中译本。
     
    写在代码大全中文电子版之后
    □ 文/徐勇

    第一次阅读《代码大全》时,是在大约10年前(1995),
    我读大学低年级时。觉得读不懂,因为自己才刚刚抛弃Basic,开始学习C语言,除了一些习题,并没有多少编程的实际经验,书中的许多概念与方法都觉得非常陌生。随着一个DOS下的绘图软件RomanticPainter的开发,随着自己在开发这种较大软件时不断遇到到各种问题,就越来越觉得《代码大全》不但提供了关于代码创建的最丰富的实践指南,而且还像一位经验丰富的导师循序渐进地辅导你成为一个真正专业的软件开发者。
    2000年4月,我在工作之余利用空闲时间,系统重读了《代码大全》,作了一个全书的内容摘要,便于随时看看其中的要点,提醒自己或者加深理解。这时更加发现这本书的价值,觉得非常需要向更多的程序员推荐这本书,然而这时候,这本书早就没有出版了。
    这时我有了一个想法:将其扫描后,然后利用www.delphidevelopers.com网站发动大家OCR,然后校对后作为电子版供广大软件开发人员参考。于是我买了一台扫描仪。刚好在这个时候,我从一个论坛里看到在香港工作的Sequoia扫描了全部代码大全全书,于是便与他联系,托他回深圳的时候带过来。Sequoia扫描的图片应该是在图书馆里扫描的,质量很好,这为我们以后的OCR(光学字符识别)打下了很好的基础。
    然后2000年年底的时候,便在www.delphidevelopers.com 上提出了制作电子版的倡议,并在几个BBS上发了一些消息。接着陆续收到了许多朋友的回复。2001年元旦的时候,项目正式开始了。当时项目的口号是:One For All, All For One ! 这是取自电影《三剑客》中三剑合一时三位剑客说的那句话,用在这里再恰当不过了。
    化整为零。OCR,校对,汇编的工作被分割成许多小份,然后分派给每个志愿者。每个志愿者的名字与工作内容,发出日期,与送回日期都被公布在网上,便于大家对整个项目的进度有及时地了解。
    人们总愿意在自愿而乐意的事情中投入更多的精力。所有的朋友都素昧平生,作为软件开发者,大部分人都是很忙的,需要在晚上抽出自己的休息时间,将图片利用OCR软件变成文本文件,然后再对照图片,将这些包含有不少错误的纯文本排版为与原书一样的版式,最后交回Word文档。
    大家的热情都很高。
    第一个志愿者是Wu Ke,OCR工作最多的志愿者是differ,一个人完成了4个人的工作;工作持续时间最长的是 dongfang7,他也有一本代码大全,遇到没有的图片,就自己扫描OCR了,从最初的OCR工作一直到最后的统校,都有他的热情的支持;最具执着精神的是叫ctx的朋友,由于没有收到图片,结果自己照着书,一个字一个字地敲上去;还有远在加拿大的hcqian,花了两个星期对测试版的前面10章进行了系统的检查,发现不少缺陷。
    还有的朋友当日完成自己的任务,有的朋友工作至凌晨,有的朋友把书中的表格做得非常漂亮,有的朋友提出修改部分术语译法的建议,有的朋友一人完成几人的工作,有朋友认为这是一项享受而不是一项工作,还有朋友遗憾自己未能参加这个工作。
    我也将许多晚上花在对送回来的Word文档的校对上,体会到编辑工作的不易,常常觉得老眼昏花。所以,拥有一本纸质的《代码大全》是一件多么保护视力的事!
    其间还收到过CSDN蒋涛先生的Email鼓励。
    其实最终的电子版是来自天涯海角的近100位素不相识的朋友的热情和协作的成果。
    盖茨说过微软最重要的财产就是代码。不错,软件开发中所有的关键活动,最终的目的都为了能够创建出正确的健壮的最好用的代码。而这本书,10年前写的书,至今仍未过时,因为它所探讨的内容不是表面的现象,而是关于代码创建的内在本质与规律。毫不夸张地说,这是世界上关于代码创建的最为丰富最为深刻的实践指南。
     
    《代码大全》书评

    □ 文/徐勇

    《代码大全(第二版)》——软件构建实用手册
      编程既不完全是艺术,也不完全是科学。归因于其实践过程,它是介于艺术和科学之间的“工艺”。
    —— Steve McConnell

    《代码大全(第二版)》必将在每个开发者的计算机书架上熠熠发光。书的每一页都体现了通过多年高效编程经历才能得到的深遽眼光,它仍将是软件构建实践者的主要手册。项目领导应当从头至尾读读这本书,然后为其手下每人买上一本。您所在项目的软件品质将因此而有所提高。
    软件大师Steve McConnell的成名之作很可能是《代码大全》——一本软件构建的实用手册。(McConnell总是以“软件构建”来描述软件开发)。《代码大全》前所未有地影响了我对软件开发的思维方式。我知道内容有些琐碎,但要是哪本技术书堪称“即刻经典”的话,那么非此书莫属。这正是我殷切期待《代码大全》第二版的原因。如果您从未听说过《代码大全》,不要以为它高深莫测——该书并不像CMMI那样大谈软件开发的标准,而是为程序员的实践提供实用建议。它致力于深入设计、测试和集成方面的编码和调试问题。
    在该书的前言里列出了其九点主要益处,每一点都和作者主张一致。比如,该书是完整的软件开发参考书、即时可用的自我检查表、软件开发的透视,没有夸夸其谈。这本书通过自顶向下的方法循循善诱读者,从蓝图和设计讲起,深入合适的变量和语句命名方法和用法,最后来到改进代码的广阔世界(问答、测试、调试、重构和调整)、系统考虑(大小、集成度和工具),还有软件工艺的终极内容。
    像一本好的业务书那样,《代码大全(第二版)》有许多读者承认好却懒得做的规则。在阅读循环次数变量应命名为有意义的名字时,我只能笑一笑。CS-101课程曾斥责那种乱取变量名的憋脚作法,编程新手应对循环变量的命名约定铭记在心。如同贯穿本书的其它方面,对命名的推荐作法强调了共同的主题——写代码就要像编重要文档那样小心翼翼、考虑周全。思路和组织越清晰越好。
    除了彻底的重塑外,新版本还将过了时的C和Pascal代码示例多数替换为C++,有些是Java,还有少量的Visual Basic代码。和前面一版相同,这些例子所用的语言并不重要,只是为了说明演示的原理。网络的威力也在此得到了发挥,书中的页边空白处会时不时标一些能够直接访问的网址,来说明某些概念或提供检查表。并且承袭了McConnell以往所写书的风格,配套的网站(在Apache Web server下用PHP所写)和书有同样价值的参考作用。然而,不像先前书的网站,cc2e.com要求访问者在打开其知识宝库前,要注册或得到Construx网站会员资格。
      
    程序员
    在你的生涯中应养成良好的编程习惯,越早越好。如果你是学生,或者自学、想把事情做好,建议你马上阅读《代码大全》的下列几章:
    第7章“高质量子程序”—— 该章剖析子程序的方方面面,话题涵盖创建子程序的理由、子程序的长度、子程序名等等。
    第15章“使用条件语句”—— 该章论及if和case语句的正确用法。
    第16章“控制循环”—— 该章说明for、while和foreach循环结构的控制方法。
    对于老手们,作者则提供了调试、代码调整策略、程序源代码的布局和风格、罕用数据类型(结构、指针和全局数据)和协作构建(用以与其他程序员合作)。
    管理人员
    该书并不面向管理。不过,“管理构建”一章大概足以让管理者从开发人员那里借来《代码大全》看看。为了避免一大堆问题,应要求新手管理者,尤其是没有技术背景的新管理人员读一读“把程序员当人看(Treating Programmers as People)”一节。
    批判者
    《代码大全》并非没有批判者。有人抱怨1993年出版的第一版没有面向对象的编程方法(OOP)。1993年时OOP还是新颖的玩艺儿,所以第一版对此确实没有提及。现在McConnell对《代码大全》加入了“工作类”一章,后者含有创建高质量类的精华建议。这本书完全是OOP的气息。书中数不清的好坏编码示例都用Visual Basic、Java、C++、C#和C重新编写(这里“坏”指的是那些提供编码禁忌的示例)。
    另外一些批评者说书“只是对学校东西的老调重弹”,或者“尽是些老掉牙的东西,谁都知道。”这些评论者的确受过良好教育,但并非每个人都知道该如何做。我赞赏McConnell,不仅是因为他把这些知识编纂成册,更归功于他的书包括了要点和自我检查表。
    要点和自我检查表穿插于文中,归纳出McConnell认为是重要的地方。正如有经验的飞行员起飞前要做各项检查,软件开发者在发布代码前,可以使用McConnell的自我检查表。即使你不完全赞同作者的观点,该书可能促使你创建自己的开发检查表。
    购买者
    你还没有自己的《代码大全》书吗?然而,如果你已有第一版的话,是否该买第二版就不太好说了,因为作者认为仍有95%的内容与第一版相关。要想了解更多内容,请查看《代码大全》第二版网页上作者“关于第二版的说明”之内容,也可以看到第二版的目录、前言和第1、5章。
    这本书说的是软件开发中常被忽视之处:代码的写法。它并不针对某种特定语言、编程范例或开发方法,也并非讲的是通用标记语言(UML)、设计模式或数据结构,而是编码、低层设计、命名规范等等所有我们花费太多时间,多数开发书却闭口不谈的东西。从这个意义上说,Steve McConnell的《代码大全》相当独特,第一版刚被奉若神明,又有了新一版,拓展了原书的内容,巩固了该书的权威地位。
    在涵盖代码构建各个方面的同时,这部巨著充满着明智的建议、示例代码、无可辩驳的事实和有力的论据。通过无数新闻报纸和学术研究中的数据,结合争战故事和轶闻,该书下功夫来说服读者,而不是靠强词夺理来做到这一点。McConnell意在帮助读者成为更好的开发人员,但他希望采用劝说而不是说教的办法。这也是该书成为一本优秀书的原因之一。
    话题组织成七个不同的部分,从软件构建到伪代码的用法,到变量的命名,再到代码的编排等等。资料的安排很广泛,所以即使变量命名的话题就单独占了有用且有趣的一章。信仰意义之类的话题(如代码编排)也有所提及。
    我们可以对本书逐节考察其概要,但这样做对本书尚不能物尽其用。最好是着重于文中的若干关键主题。首当其冲的就是复杂性问题。克服复杂性是卓越开发者追求的重要目标——这就意味着应当写组织精良、易懂易维护的代码;意味着不要写花俏却是维护恶梦的代码。
    这一原则可延伸到所其次是要牢记代码通常看的次数要比写的次数多。因而应确保代码是可读懂的,同理要注意程序结构、命名规范的使用及注释代码等等。有地方,从如何命名子程序到怎样编排代码,还有另一个重要之处是最好的开发者总在不断自我发展和学习。所以要奋力完善自己,对自己做的事有清醒认识,关注业界的动态,不要夜郎自大。变量该如何称谓。
    书中的精彩资料太丰富了,以致于难以简单地评述之。希望进步的开发者都该阅读此书。对它的推我期待过《代码大全》第二版在6月8日的问世,每个开发者都该有一本此书。现在我已拿到手一个星期,并读了约一半内容。可以说这本书比它的第一版还要好。它以C++和Java等现代语言更新了内容,绝对是软件构建方面无与伦比的书籍……阅读此书我还将能学到很多知识,强烈推荐!无以言表。
    来源:http://www.cc2e.com.cn
    March 09

    没有指南针

      开学上课已经有一周了,上课、看书、乒乓、健身……
      这个学期很短暂,转眼就会过去。我得抓紧时间找准一个方向,然后去努力。
      要想发文章,就得研究理论;要想以后找个好工作,却又要搞应用。现在想学的东西很多,我喜欢应用性的东西,如编程、嵌入式、操作系统等。可是又要想办法以后能发文章,所以理论性的东西却又不能不看。这两者看似矛盾的,能不能找到矛盾的结合点呢?我问师兄,师兄们也没能给我一个理想的答案。我只能自己找,真希望赶快结束这漫无目的的尴尬境地。
      不过不管怎么样,我的生活都将会是充实的。我必须不断地给自己找事情做,惟有这样才能不给自己的心灵以空隙和机会,因为我不想痛苦和感伤。
      AL和LA只是隔着薄薄的一张纸吗?我不确定,我不敢去捅,怕伤了手指,不愿意相信纸的背后是一堵墙。
    March 04

    元宵节的雪

      今天是正月十五元宵节。
      经过了一个暖冬,年前就打了春,后天就是农历的“惊蛰了”。没想到经过几天绵绵的春雨,今天早上竟然飘起了鹅毛般的大学。不过由于太暖和的原因,雪一落到地上就溶化了。我是喜欢下雪天的,所以今天心情也比较好。
      明天就是开学的日子,又要变得忙碌起来了,我准备好了吗?
      ——!