基本信息
- 原书名:Code Reading: The Open Source Perspective
- 原出版社: Addison-Wesley
编辑推荐
无论从哪方面讲,代码阅读都不是一个容易的课题。在此之前,我不知道是否其他书籍曾尝试过阐述这一主题。因此,当我看到这本书时,我毫不犹豫地选择了它。阅读这本书时,我的第一反应是“这本书在介绍什么呢?”。我在阅读和理解他人的代码时,曾有过无数次这种感觉。就如同,当您遇到一段新代码时,需要花一段时间来理解与消化一样,理解与消化这本书背后的思想也要花费一些时间。实际上,我多次打开这本书,重新阅读部分内容,并将它应用到实际的环境中,从而通过具体的形式不断加深对这个课题相关理论的理解。如果您的情况和我类似,那么这本书可能很适合您。
内容简介
计算机书籍
[b>本书荣获美国(2004年度)第14届[/b>[b>Jolt大奖[/b>[/a> [b>图书:技术类 生产效率大奖[/b>
[font color="#FF6600"> 代码阅读有自身的一套技能,重要的是能够确定什么时候使用哪项技术。本书中,作者使用600多个现实的例子,向读者展示如何区分好的(和坏的)代码,如何阅读,应该注意什么,以及如何使用这些知识改进自己的代码。养成阅读高品质代码的习惯,可以提高编写代码的能力。 [/font>
阅读代码是程序员的基本技能,同时也是软件开发、维护、演进、审查和重用过程中不可或缺的组成部分。本书首次将阅读代码作为一项独立课题,系统性地加以论述。本书引用的代码均取材于开放源码项目--所有程序员都应该珍视的宝库。本书围绕代码阅读,详细论述了相关的知识与技能。"他山之石、可以攻玉",通过仔细阅读并学习本书,可以快速地提高读者代码阅读的技能与技巧,进而从现有的优秀代码、算法、构架、设计中汲取营养,提高自身的开发与设计能力。 本书适用于对程序设计的基本知识有一定了解,并想进一步提高自身开发能力的读者。
作译者
目录
1.1 为什么以及如何阅读代码 2
1.1.1 将代码作为文献 2
1.1.2 以代码为范例 4
1.1.3 维护 4
1.1.4 演进 5
1.1.5 重用 6
1.1.6 审查 6
1.2 如何阅读本书 7
1.2.1 印刷约定 7
1.2.2 图解 8
1.2.3 练习 9
1.2.4 辅助材料 9
1.2.5 工具 10
1.2.6 大纲 10
1.2.7伟大语言的争论 10
进阶读物 11
第2章 基本编程元素 1
2.1 一个完整的程序 1
译者序
有一些人,确实存在,我们却无缘相见
有一种生活,还没有到来,我们却已永远离开
开放源码--程序员的天堂
好的程序就如同好的音乐一样,它们完成得那么巧妙,那么完美,体现出完全没有词藻的美丽。就如同好的音乐能够改变你对人生的看法、让你重新审视你的生活、和多年前的人进行跨时空的交流一样,作为软件开发人员,好的程序所能够带来的感受丝毫不逊于音乐给你带来的冲击。更为难得的是,这些宝贵的程序往往并非由"权威人士"、"享誉海内外的专家"所编写,它们是由一个个普通的程序员写就。这些程序员和读者没有什么不同。虽然这些程序员并非吒咤风云的人物,但专业创造了专家,长时间集中在某个领域中就能够创建出所有程序员都应该珍视的财富。就如同古代的米开朗基罗,相比于当时那些声名显赫的主教、贵族来说,他是多么的微不足道,但时至今日,那些人和他们的名字都随风漂逝,昔日的荣光都随时间而暗淡,而米开朗基罗的名字却铭刻在大多数甚至是普通人的心中,许多人的脑海中都能回忆出那些完美的雕塑--《大卫》、《创世纪》。这份荣耀在文艺史上可能无人能及。
但一个不可忽视的现实是,对于大部分正在使用的软件,我们很难看到它们的源代码,从而也就失去了欣赏和从中学习的机会。和音乐不同的是,你不可能花钱买到一份拷贝回家欣赏。幸运的是,现在情况已经发生了很大的改变,我们拥有了一个宝贵的资源--开放源码项目。
开放源码和商业产品的源代码有着本质上的不同。这种不同体现在以下几个方面:
1.开放源码项目中的大部分代码都经历过许多人的阅读和检查,在商业产品中由于人力和版权方面的限制,根本不可能做到这一点。同时,由于作者在开发时就意识到自己编写的代码要被别人阅读,故而无论是在规范的遵守、算法的优化方面都会格外用心。
2.开放源码由于没有严格的时间限制,少了时间与质量的权衡,从而产生的代码质量更高,对于读者也更有借鉴作用。例如,面向普通用户的软件,比如游戏、娱乐软件等,大都会选择在圣诞节和暑假之前发布,而为了满足市场销售的需要,软件新版本的开发工作也大都定在圣诞节和暑假之前二到三个月必须完成。这就要求软件的开发人员必须严格遵守时间上的要求。
3.开放源码能够优胜劣汰,拥有更快的更新速度。开放源码项目一般接受各种形式的反馈。来自全世界的代码阅读者都可以及时地反馈自己发现的问题,或好的看法。在这里,评判优劣的惟一标准是代码的质量。好的代码经历住时间的考验,留存下来。不好的代码和不太合格的代码提交者随着时间的推移迅速地淘汰。而在商业产品的源代码中,一些遗留代码中存在的问题可能永远得不到改正,因为开发它的人员已经离开公司或者从事其他工作,只要这段代码能够工作,没有人再去关注它的优劣。
4.开放源码没有权威崇拜。
开放源码的世界里没有阿谀奉承、阴奉阳违、沽名钓誉、挂着羊头卖狗肉、恬不知耻,所有的程序都经过无数人的检验。正是由于开放源码具有这些特性,使得它成为程序员学习和提高的首选材料。
代码阅读--入门与提高的必由之路
信息时代,我们整个社会的知识更新速度越来越快,而位于信息时代风口浪尖上的计算机技术,更是日新月益。作为程序员,总是要不断地学习新的知识。但我们要保持清醒,如何体现出我们的价值呢?难道是我们掌握了多少知识吗?不对!我们的价值归根到底要体现在我们创造出的系统上。否则空有满腹经伦,到头来也不过是纸上谈兵,于国于人毫无益处。
计算机科学是一门实践性很强的科学,许多内容往往在书本上根本学不到。就拿项目的组织来说,没有什么书籍专门论述应该如何组织与管理项目的目录结构,因为这本身就是一种见仁见智的活动,要受到各种因素的影响。代码中往往凝聚着许多实践性的知识,通过阅读代码才能真正掌握软件开发的真谛。我们可以将"书籍是人类进步的阶梯",扩展成"一切承载人类知识的材料,都是人类进步的阶梯"。
代码阅读是一件如此基本的事情,以至于人们根本没有意识到它的存在。这本书第一次将代码阅读这一主题单独列出来加以探讨,可以说极具开创性。
代码阅读不是一件容易的工作,但却是一件不得不做的工作,无论是工作的移交、新手的入门、或是加入新的项目,都要阅读大量由他人编写的代码。我们可能不止一次地听到过他人抱怨:与其读他人的代码,还不如自己去写更为轻松。可见,代码阅读任务可能远比实现一个链表或树形数据结构要复杂困难。但代码阅读也并非完全无章可循。掌握了一些常见的技巧以及常用的工具之后,能够有效地降低代码阅读的难度,提高工作效率。
我曾向一位资深的开发人员询问过,应该如何提高自身的开发与设计能力。他的回答是,广泛地阅读一些现有的构架,比如Apple的开发框架、Borland的OWL和Delphi、Smalltalk、MFC等,了解它们是如何组织的。计算机科学就是这样一门学科,入门十分容易,不需要深奥的数学知识,也没有复杂的物理模型;但要想提高却很难,真正能够叱诧风云、引领潮流的人却少之又少。这就有如人生,在蹒跚学步之时,主要的精力都要放在看脚下的路面上,注意路上的坎坷和荆棘;随着年龄的增长,当走路越来越稳健时,却迷失了方向,不知道应该走向何方。这个时候脚下的路已经不再重要,你需要从先哲们留下的只字片言,别人走过的"路"中汲取灵感,确定自己的方向。
由于微软Windows的广泛采用,使得许多程序员只将注意力放在Windows平台上,这种做法有失偏颇。做为文秘人员,当然可以这样做,因为微软在桌面系统上的确十分成功,基本覆盖了文秘人员对计算机的所有需求。但做为开发人员,必须跳出Windows这口"井"。总是局限在Windows这口"井"中,可能会限制您的思路与视野。当设计与实现复杂的系统时,需要借鉴许多前人的经验,而这时候,您就需要开阔的视野,才能从更为广泛的空间中吸收所需要的知识。跳出Windows之后,您能看到各种各样的构架,各种各样的抽象方法,各种各样不同的系统设计,也许其中一种就很适合您使用,不再需要冥思苦想,绞尽脑汁,不再进行大量的尝试,不再受大量的挫折之苦。Microsoft是一家出色的公司,为用户提供了很有用的产品,但Microsoft并非软件的全部。有许许多多出色的操作系统、编辑工具、各色软件需要我们去认识和借鉴,甚至包括那些已经逐渐淡出人们记忆的软件。因为我们不是软件的用户,我们是软件的开发者,我们需要借鉴前代的经验,才能更好地前进。那些消逝的软件并非由于它们不优秀,只不过它们不适合于生存下来而已。存活下来的软件也并不一定是优秀的软件,只不过它们适合于生存下来而已。就好像许多古代文明,我们现在只能通过一些石块来追溯它们昔日的辉煌,有记录的内容都已经随着时间的流逝而消失,尽管它们比石块更能清楚地告诉我们想要知道的内容,尽管石块根本就是这些文明中最无关紧要的部分。
在夕阳西下的时间,泡上一杯茶,合上笔记本,揉一下看了一会源代码有些累的眼睛,伸个懒腰。这是不是有一些"采菊东篱下,悠然见南山"的意境呢?只不过陶渊明种的是菊花,我们播种与收获的是代码而已。
前言
阅读代码可能是计算领域的专业人士最常见的活动之一,但人们很少将它作为一门课程来讲授,或正式地将它作为学习程序设计的方法。
造成这种现状的原因,最初可能是由于得不到源代码,或缺乏高品质的代码可供阅读。公司常常将源代码作为商业机密加以保护,很少允许其他人阅读、添加注释、试验并从中学习。仅在少数情况下,重要的专利代码允许扩散到公司之外,它们引起了公众极大的兴趣,并得到了创造性的发展。例如,整整一代程序员都受益于John Lions的Commentary on theUnix Operating System(《Unix操作系统注释》),该书列出了Unix核心第6版的完整源代码,并做了注释。虽然Lions的书在最初编写时受到AT&T相关授权的约束,只能用于操作系统课程,不对大众开放,但是,该书的副本已经通过私下影印流通了多年。
但是,在过去的几年里,开放源码软件的普及为我们提供了大量的代码,我们可以自由地阅读所有这些代码。今天最广泛使用的一些软件系统,比如Apache Web服务器、Perl语言、GNU/Linux操作系统、BIND域名服务器和sendmail邮件传输代理程序,实际上都有开放源码的形式。因此,我很幸运,能够使用开放源码软件(比如上面列出的这些软件系统)来编写本书,作为软件代码的初级读本和教科书。我的目标是为阅读他人的代码提供背景知识和技术。通过使用实际的例子(这些例子都取自正在使用的开放源码项目),我想介绍有可能出现在软件开发人员面前,与代码相关的大部分概念,包括编程构造、数据类型、数据结构、控制流程、项目组织、代码规范、文档和构架。另有一本书介绍接口和面向应用的代码,包括国际化和可移植问题、常用库和操作系统中的元件、低级代码、领域专有的声明性语言、脚本语言和混合语言系统。
本书是(就我所知)第一本专门将代码阅读作为一项独立活动加以讲述的书籍,是一本物有所值的书。将代码阅读作为一种独立的活动来介绍,肯定会存在不可避免的缺点:有可能其他的方式对内容的处理会更好,也有可能在讲述过程中缺失重要的材料。但我坚定地认为,代码阅读应该得到正确地训练,并用作提高编程能力的一种方法。因此,我希望本书将激起人们的兴趣,将代码阅读课程、活动和实践包括到计算教育的课程中,以便几年后我们的学生能从现有的开放源码系统中学习有用的知识,就如同他们的同辈们从伟大的文学作品中学习语言一样。
辅助材料
本书中提供的许多源代码示例都来自于NetBSD的源代码。NetBSD是一个免费的、高度可移植的类Unix操作系统,适用于多种平台,从64位AlphaServer到手持式设备。它清晰的设计和先进的特性,使得它无论对于生产环境,还是对于研究环境,都是一个极好的选择。之所以选择NetBSD,而不选择其他同样优秀,且广泛应用的免费类Unix系统(比如GNU/Linux、FreeBSD和OpenBSD),是因为NetBSD主要的目标就是强调正确的设计和编写良好的代码,这使得它成为提供源代码示例的最佳选择。根据其开发者的思想,有些系统好像拥有这样的哲学:"如果它能够工作,那么它就是正确的,"而NetBSD可以描述为"除非它正确,否则它就不能工作。"另外,NetBSD系统的一些其他目标与本书的目标相当符合。尤其是,NetBSD避开了许可的拖累,提供一个可以在多种硬件平台上运行的可移植系统,与其他系统的互操作性良好,并且符合开放系统的实用规范。本书中使用的代码是一个(现已成为历史)export-19980407快照。有几个例子用到了我在代码中找出的一些错误;由于NetBSD的代码不断发展,如果使用来自更近版本的例子,这些珍贵的代码极有可能已经得到更正。
本书例子中,对系统其余部分的选用也都基于类似的前提:代码品质、结构、设计、效用、普及和不会使我的出版商不安的许可。我努力平衡语言方面的选择,积极地寻找合适的Java和C++代码。但是,当相似的思想能够使用不同的语言来演示时,我选择使用C语言,因为它拥有最基本的共同特性。
有时,我会使用真实的代码来说明不安全、不可移植、难以阅读或其他不好的编码实践。我认识到,我可能会由于贬低代码而受到指责,这些代码可能是其作者出于推进开放源码运动的良好信仰而贡献出来的,它们需要不断地改进而非仅仅是批评。如果我的注释冒犯了源代码的作者,我真诚地预先道歉。作为辩护,我得说,大部分情况下,注释并非针对特定的代码,而是用它来说明-种应该避免的情况。我用作反面教材的代码经常是"跛足的鸭子",在编写它们的时候,技术和其他的限制证实了这种做法,或者对它们的批评脱离了特定的上下文。任何情况下,我都希望大家能够愉快地接受这些注释,我公开地承认,我自己的代码中包含相似的,甚至可能更坏的错误。
序言
这也正是我们被灌输的思想,好像很合理。我们的工作是编写代码,所以我们需要学习如何编写代码。大学课程教我们编写程序。培训课程告诉我们如何调用新的库和API。这是整个行业中最大的悲剧之一。
因为,学习编写伟大代码的方式是阅读代码,阅读大量的代码:高品质的代码、低品质的代码;汇编语言代码、Haskell代码;千里之外的陌生人所写的代码;以及我们自己上周刚刚编写的代码。因为,如果不这样,我们就会不断地重做别人已经完成的工作,重复过去已经发生过的成功和错误。
恐怕没有哪个伟大的小说家从未读过其他人的著作,没有哪个伟大的画家从未研究过他人的绘画作品,没有哪个技术熟练的外科医生从未观摩过同事如何动手术,没有哪个波音767的机长不是首先在副驾驶员的位置上观看如何实际操作的。
可是,我们却期望程序员能够做到这些(即,不用读他人的代码就能够编写出优秀的代码。--译者注)。"本周的任务是编写……"。我们告诉开发人员语法和构造规则,之后,我们希望他们能够编写出相当于伟大小说的软件。
具有讽刺意味的是,对阅读代码来说,从来没有过比现在更好的时光。感谢开放源码社团所做出的巨大贡献,现在网络上有数以千兆的源代码,等待我们去阅读。选定任何一种语言,您都能找到源代码。选择一个问题域,也存在大量的源代码。选择一个级别,从微码(microcode)到高级的商业功能,您都能够找到大量的源代码。
代码阅读充满了乐趣。我喜欢阅读他人的代码。我阅读代码是为了学习技巧,并分析陷阱。有时,我会碰到很小,但很宝贵的精华。我依旧记得,当我在PDP-11汇编程序中无意中找到一个二进制到八进制转换例程时所获得的惊喜,这段例程设法不用循环计数,在一个紧凑的循环中输出一个6位八进制数。
有时,我阅读代码是为了寻求一些故事,就如同在长途飞行之前,您在机场会选择一本书。我期望,从灵巧的结构和意外的对称美中能够获得愉悦。Jame Clark的gpic程序(属于他的GNU groff包)就是此类代码的一个绝佳例子。他用简明且优雅的结构实现了极为复杂的功能(一种说明性的、设备无关的绘图语言)。看完代码后,我受到了激励,想着如何同样整洁地构造自己的代码。
有时,我还批判地阅读代码。在这种情况下,阅读速度会放慢。当我阅读时,我会不断地向自己提问,比如:"为什么要这样写?"或"作者背景中的什么东西使他/她做出了这种选择?"我这样做经常是因为,我要复查代码来解决存在的问题。我寻找能够给予我指示的模式与线索。如果我看到,作者在代码中某处没有对共享的数据结构进行锁定,我就会怀疑同样的问题是否在别处同样存在,接下来,就会想是否就是这个错误引起了我正在处理的问题。我还使用我发现的不一致性,进一步验证我的理解;我经常发现,那些本来认为可能存在问题的地方,经过进一步仔细分析后,常常是完美的好代码。从中,我也学到了一些东西。
实际上,代码阅读是消除程序中存在问题的最有效方式之一。Robert Glass,本书的审稿人之一,说过:"通过正确地使用(代码)审查,软件产品中90%以上的错误能够在测试之前消除。"同一篇文章中,他引用的调查研究表明,"将注意力放到代码上的审查员比将注意力放到过程上的审查员要多发现90%的错误。"有趣的是,当阅读本书引用的代码片段时,我就碰到几个bug和几个可疑之处。存在这些问题的代码正在全球数千个站点上运行。虽然实际上没有严重的问题,这个练习表明我们编写的代码总是存在改进的空间。代码阅读能力显然拥有巨大的现实好处,如果您曾和明显不知道如何阅读代码的人共同做过代码复查,肯定已经体会到这些好处。
接下来就是维护--软件开发令人讨厌的远亲。虽然没有精确的统计数字,但大多数研究员都同意,我们花费在软件上的时间当中,超过一半是用在检查现有代码上:增加新的功能、修复bug、将其集成到新环境等。代码阅读技能极其重要。如果在一个10万行规模的程序中存在一个bug,给您一个小时的时间来找到它。您如何开始工作呢?您怎么知道您在找什么?并且,您如何评估做出的更改所造成的影响呢?
因为所有这些原因,以及更多的其他原因,我喜欢这本书。从本质上讲,这是一本实用主义的书。它没有采取抽象的、学院式的方式,而是将注意力放在代码本身上。本书分析了几百个代码片段,指出了其中的技巧、陷阱和(同等重要的)习惯用法。本书在代码原来的环境中谈论代码,同时论述了环境如何影响代码。本书还突出了代码阅读者的一些重要工具,从常见的工具如grep和find,到更为特殊的工具。同时,本书强调了构建工具的重要性:编写代码帮助阅读代码。此外,本书附带了书中论及的所有代码,并在配套盘上做了交叉引用,方便使用。
本书应该包括在每个编程课程中,每个开发人员都应该有一本。作为一个社团,如果我们在代码阅读投入更多的精力,既可以节省我们的时间,又能够减少我们的痛苦。我们将会节省本行业的资金。同时,我们也会在工作中体会到更多的乐趣。
Dave Thomas
The Pragmatic Programmers,LLC
http://www.pragmaticprogrammer.com