描述
开 本: 16开纸 张: 纯质纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302583646
史蒂夫·麦康奈尔(Steve McConnell)的《代码大全》是全球公认的编程最佳实用指南,十多年来一直帮助开发人员写出更好的软件。这本经典书籍包含行之有效的实践和数百个范例代码,充分展现了软件构建的艺术和科学。史蒂夫对学术界和日常商业实践进行了广泛的研究,从中萃取出精华,通过通俗易懂的表达方式和体例,形成了一套行之有效的技术、原理和实践体系,旨在帮助广大程序员以最快的速度、更少的时间、更少的预算,来写出质量更高、更优美的代码。
作为一本综合性强和实用性高的经典参考书,本书适合任何一个程序员阅读,无论经验水平、开发环境或项目规模如何,都可以从中得到启发,构建出高质量的代码,真正做到代码完成的境界。
透过本书,发现经得起时间考验的技巧和策略,从而帮助读者:
& 实现大道至简和更有创新的设计
& 收获合作开发的好处
& 应用防御性编程技术来减少和清除错误
& 利用机会来以安全的方式重构或演化代码
& 使用适合具体项目的构建实践
& 快速有效地调试问题
& 尽早正确地解决关键的构建问题
& 质量内建贯穿于整个项目周期,无论开始、中间和结尾
《代码大全2(纪念版)》作为名家经典著作,是一本完整的软件构建手册,涵盖软件构建过程中的所有细节。它从软件质量和编程思想等方面论述软件构建的各个主题,并详细论述主流的新技术、高屋建瓴的观点和通用的概念,还含有丰富而典型的程序示例。本书所论述的技术不仅填补了初级与中高级编程技术之间的空白,同时还为程序员提供了一个有关编程技巧的信息来源。
《代码大全2(纪念版)》对经验丰富的程序员、技术带头人、自学的程序员及几乎不懂太多编程技巧的学生大有帮助。无论是什么背景的读者,都可以通过阅读和领会本书,在更短的时间内更轻松地写出更好、更简洁和更优雅的程序。
第Ⅰ部分 奠定基础
第1 章 欢迎来到软件构建的世界 003
1.1 什么是软件构建 003
1.2 软件构建为何如此重要 006
1.3 如何阅读本书 008
第2 章 通过隐喻更充分地理解软件开发 009
2.1 隐喻的重要性 009
2.2 如何使用软件隐喻 012
2.3 常见的软件隐喻 013
第3 章 谋定而后动:前期准备 023
3.1 前期准备的重要性 024
3.2 确定要开发什么类型的软件 030
3.3 定义问题的先决条件 034
3.4 需求的先决条件 036
3.5 架构的先决条件 041
3.6 前期准备所花费的时间 052
第4 章 关键的构建决策 057
4.1 编程语言的选择 057
4.2 编程约定 062
4.3 判断个人处于技术浪潮中的哪个阶段 062
4.4 选择重要的构建实践 065
第II 部分 高质量的代码
第5 章 软件构建的设计 069
5.1 设计挑战 070
5.2 关键设计概念 073
5.3 设计构建基块:启发式方法 083
5.4 设计实践 107
5.5 点评各种流行的方法论 115
第6 章 可以工作的类 121
6.1 类的基础:抽象数据类型(ADT) 122
6.2 良好的类接口 129
6.3 设计和实现问题 139
6.4 创建类的理由 149
6.5 语言特定问题 153
6.6 超越类:包 153
第7 章 高质量的子程序 157
7.1 创建子程序的正当理由 160
7.2 子程序级别的设计 165
7.3 好的子程序名称 169
7.4 一个子程序应该有多长 171
7.5 如何使用子程序参数 173
7.6 函数使用中的特别注意事项 180
7.7 宏子程序和内联子程序 182
第8 章 防御式编程 187
8.1 保护程序,使其免受无效输入的影响 188
8.2 断言 189
8.3 错误处理技术 194
8.4 异常 198
8.5 隔离程序,使之包容由错误造成的损害 203
8.6 调试辅助代码 205
8.7 确定在生产代码中保留多少防御式代码 209
8.8 对防御式编程采取防御的姿态 211
第9 章 伪代码编程过程 215
9.1 类和子程序构建步骤总结 215
9.2 面向专家的伪代码 218
9.3 使用PPP 构建子程序 220
9.4 PPP 的替代方案 233
第Ⅲ部分 变量
第10 章 变量使用中的常规问题 239
10.1 数据扫盲 240
10.2 简化变量声明 241
10.3 变量初始化指南 242
10.4 作用域 247
10.5 持久性 254
10.6 绑定时间 255
10.7 数据类型和控制结构之间的关系 257
10.8 每个变量只有一个用途 258
第11 章 变量名称的威力 263
11.1 选择好名称的注意事项 263
11.2 特定数据类型的命名 269
11.3 命名规范的威力 275
11.4 非正式的命名规范 276
11.5 前缀的标准化 283
11.6 创建可读的短名称 286
11.7 变量名称避坑指南 289
第12 章 基本数据类型 295
12.1 一般的数字 296
12.2 整型 297
12.3 浮点型 299
12.4 字符和字符串 302
12.5 布尔变量 305
12.6 枚举类型 307
12.7 具名常量 312
12.8 数组 314
12.9 创建自定义类型( 类型别名) 316
第13 章 不常见的数据类型 323
13.1 结构体 323
13.2 指针 327
13.3 全局数据 340
第Ⅳ部分 语句
第14 章 直线型代码的组织 353
14.1 顺序攸关的语句 353
14.2 顺序无关的语句 356
第15 章 使用条件语句 361
15.1 if 语句 361
15.2 case 语句 367
第16 章 控制循环 373
16.1 选择循环类型 373
16.2 控制循环 379
16.3 轻松创建循环:由内而外 391
16.4 循环和数组的对应关系 393
第17 章 不常见的控制结构 395
17.1 子程序中的多个返回点 395
17.2 递归 397
17.3 goto 语句 402
17.4 众说纷纭,谈谈不常见的控制结构 413
第18 章 表驱动法 417
18.1 表驱动法使用总则 417
18.2 直接访问表 419
18.3 索引访问表 431
18.4 阶梯访问表 433
18.5 表查询的其他示例 436
第Ⅴ部分 代码改进
第20 章 软件质量概述 469
20.1 软件质量的特性 469
20.2 改进软件质量的技术 472
20.3 质量保证技术的相对效能 475
20.4 何时进行质量保证 479
20.5 软件质量的普遍原理 479
第21 章 协同构建 483
21.1 协同开发实践概述 484
21.2 结对编程 487
21.3 正式审查 489
21.4 其他类型的协同开发实践 496
第22 章 开发人员测试 503
22.1 开发者测试对软件质量所起的作用 504
22.2 开发人员测试的推荐方法 507
22.3 一些测试技巧 509
22.4 典型错误 522
22.5 测试支持工具 528
22.6 改进测试 534
22.7 维护测试记录 535
第23 章 调试 541
23.1 调试问题概述 541
23.2 发现缺陷 546
23.3 修复缺陷 557
23.4 调试中的心理因素 560
23.5 那些显而易见和不太明显的调试工具 563
第24 章 重构 569
24.1 软件演变的类型 570
24.2 重构简介 571
24.3 特定的重构 577
24.4 安全重构 585
24.5 重构策略 587
第25 章 代码调优策略 591
25.1 性能概述 592
25.2 代码调优简介 595
25.3 各式各样的臃肿和蜜糖 601
25.4 度量 607
25.5 迭代 608
25.6 代码调优方法总结 609
第26 章 代码调优技术 613
26.1 逻辑 614
26.2 循环 619
26.3 数据变换 628
26.4 表达式 633
26.5 子程序 642
26.6 用低级语言重新编码 643
26.7 改得越多,越不会有大的改观 646
第Ⅵ部分 系统化考虑
第27 章 程序规模对构建的影响 651
27.1 沟通和规模 651
27.2 项目规模的范围 652
27.3 项目规模对错误的影响 653
27.4 项目规模对生产力的影响 655
27.5 项目规模对开发活动的影响 656
第19 章 常规控制问题 437
19.1 布尔表达式 437
19.2 复合语句( 语句块) 448
19.3 空语句 449
19.4 驾驭深层嵌套 451
19.5 编程基础:结构化编程 460
19.6 控制结构与复杂度 462
第28 章 管理构建 663
28.1 鼓励良好的编码实践 664
28.2 配置管理 666
28.3 评估构建进度表 673
28.4 度量 679
28.5 以人为本,善待每一位程序员 683
28.6 向上管理 689
第29 章 集成 693
29.1 集成方法的重要性 693
29.2 集成的频率,阶段式还是增量式 695
29.3 增量式集成策略 698
29.4 每日构建和冒烟测试 707
第30 章 编程工具 715
30.1 设计工具 716
30.2 源代码工具 716
30.3 可执行码工具 721
30.4 面向工具的环境 726
30.5 自己动手写编程工具 726
30.6 工具的幻境 728
第Ⅶ部分 软件匠艺
第31 章 代码的布局和风格 733
31.1 基本理论 734
31.2 布局技术 741
31.3 布局风格 743
31.4 控制结构的布局 750
31.5 单条语句的布局 757
31.6 注释的布局 768
31.7 子程序的布局 771
31.8 类的布局 772
第32 章 自文档代码 781
32.1 外部文档 781
32.2 编程风格即文档 782
32.3 注释,还是不注释 785
32.4 高效注释的关键 788
32.5 注释的技术 795
32.6 IEEE 标准 815
第33 章 个人性格 821
33.1 个人性格与本书主题有关 822
33.2 聪明与谦卑 823
33.3 好奇心 824
33.4 理性诚实 827
33.5 沟通与合作 830
33.6 创造力与规范 830
33.7 懒惰 831
33.8 没有想象中那么重要的性格因素 832
33.9 习惯 833
第34 章 关于软件匠艺 837
34.1 征服复杂性 837
34.2 优选开发过程 839
34.3 编写程序时,先考虑人,再考虑机器 840
34.4 深入语言去编程,而不是用语言来编程 842
34.5 借助于规范来保持专注 843
34.6 面向问题域编程 844
34.7 当心落石 846
34.8 迭代,迭代,迭代,重要的事情说三遍 848
34.9 警惕编程中的执念 849
试验 851
第35 章 更多信息来源 853
35.1 与软件构建相关的信息 853
35.2 软件构建之外的话题 854
35.3 出版物 856
35.4 软件开发者的阅读计划 857
35.5 加入专业组织 859
参考文献 861
“最佳软件工程实践与一般软件工程实践,两者的差异非常大,用‘一个在天上,一个在地上’这样的比喻来形容,恐怕也不夸张,而且远远超过其他任何工程学科。从这一点来看,用于传播优秀软件工程实践的工具,其重要性不言而喻。”
—布鲁克斯
前 言
在写作本书的过程中,我主要考虑的是缩短同一个行业中两端的差距,一端是权威、专业人士,另一端是普通的商用实践人员。在如涓涓细流一般“浸润”并被普及成为业内知晓的通用实践之前,许多强大的编程技术其实早已经隐身于期刊杂志和学术论文中很多年。
在二十一世纪的前十年,处于前沿的软件开发实践已经得到了突飞猛进的发展。然而,通用实践却一直裹足不前。bug 随处可见,交付时间一拖再拖,超出预算,等等,这样的情形在很多软件项目中仍然屡见不鲜,甚至还有很多软件根本无法满足其用户的要求。来自软件行业和学术机构的研究人员发现,早在二十世纪七十年代,就有许多足以消除大多数编程难题的高效实践。然而,这些高效实践的报道并没有走出专业技术期刊的影响圈,以至于还有相当一部分软件组织在二十一世纪的前十几年,仍然没有采用这些高效的编程实践。研究还发现,一项研究进展走向商用实践,一般需要五到十年甚至更多的时间(Raghavan and Chand 1989, Rogers 1995, Parnas 1999)。这本书最初的写作动机就是以高效的方式缩短这个过程,使这些关键的发现可以马上供大多数程序员采用。
哪些人适合阅读本书
本书中包含的研究和编程逸事将帮助大家创建高质量的软件,更轻松、更快速地做好自己的工作。本书将帮助你看清楚过去存在的难题,从而知道未来如何避免。书中描述的编程实践将帮助你从容掌控大型项目,帮助你成功维护和修改软件,直到满足项目变更的需求。
? 有经验的程序员 作为一本内容全面和容易上手的软件开发实践指南,本书适合有经验的程序员阅读。本书聚焦于软件构建( 软件生命周期内程序员最熟悉的部分),初衷是让自学成才的程序员以及受过正规训练的程序员能够透彻理解功能强大的软件开发技术。
? 技术带头人 许多技术带头人都用《代码大全2》来培训过团队中资历较浅的程序员。不过,那么也可以用本书来填补自己的知识空白。如果是有经验的程序员,也许不会完全认同书中得出的结论,但如果仔细阅读本书并认真思考每个难题后,那么你会发现自己从此以后可以从容解答别人提出的任何一个软件构建方面的难题了,因为这些问题你都认真思考过。
? 自学的程序员 如果没有接受过太多正规培训,那么这本书将会是你如影随形的良伴。每年有近5 万名新手进入软件开发行业(BLS 2004, Hecker 2004),但每年实际只有3.5 万人有软件相关的学位(NCES 2002)。* 根据这些数字,很快可以得出一个结论,有很多程序员都没有接受过正规的软件开发教育。在由工程师、会计、科学家、教师和小企业主组成的新兴专业人士团体中,出现了自学成才的程序员,编程是他们日常工作中的一部分,但他们并不认为自己就是程序员。无论受过什么程度的编程开发培训,本书都可以帮助你见微知著,洞悉高效的编程实践。
? 学生 前面提到经验丰富但缺乏正规专业教育的程序员,与其相对应的便是年轻的学生。作为职场新人,他们往往理论知识丰富,但缺乏构建软件产品的实际动手经验。那些实用的、关于好代码的学问和知识,通常传递得很慢,在软件架构师、项目主管、业务分析和资深程序员共同参与的形如宗教仪式的“舞蹈”中,真正传承下来的有用实践,可谓少之又少。留下来的往往都是个别程序员的试验品和错误。本书的目的是代替这些传统智慧盛宴的慢传递方式,通过精挑细选,将之前就有的技巧提示和有效的开发策略高度整合到一起。对学生而言,本书可以帮助他们从学术环境轻松迁移到专业开发环境。
还可以从哪些地方找到更多相关信息
本书综合介绍大量软件构建技术,这些技术的来源很广泛。多年以来,除了广泛散落在很多地方以外,关于软件构建的大部分智慧结晶并没有作为书面参考被记录下来(Hildebrand 1989, McConnell 1997a)。
译注
这里想谈一下Github 的情况。Github 在2021 年11 月公布的Octoverse报告中指出,Github 开发者数量目前已达到7300 万,其中美国开发者人数约1355 万,中国有755 万。总体而言,2021 年比前一年新增了21.3 万名首次开源项目贡献者。到2025 年,用户数量预计会达到1亿。
其实呢,专业程序员用的那些高效、高能的编程技术并不神秘。只不过,在日复一日埋头于眼前项目的奔波和劳累中,真的几乎没有几个专家还能够有时间公开分享自己的经验和教训,导致广大程序员很难找到一个好的资源集中介绍编程相关信息。
本书描述的编程技术正好可以填补入门级教科书和高级编程教科书之间的空白。在读过Java 编程入门、中高级Java 编程和高级Java 编程之后,你会读哪一本关于编程的书呢?你会读详细介绍英特尔或摩托罗拉硬件的书,介绍Windows 或Linux 操作系统功能以及其他编程语言的书,那些没有详细参考书的编程语言或程序,是没有人会用的。但是,本书是少数几本只专注于讨论编程的书。有些总能让人受益匪浅的编程技术就是适用于任何环境或者语言的通用实践。对于这样的实践,其他的书一般都略过不提,本书则不同,偏偏就要集中介绍这些通用实践。
本书可谓博采众长,选材来源广泛,如下图所示。要想获得本书包含的所有信息,另一个唯一可取的方式是遍历浩如烟海的文字,在汗牛充栋的书山和几百册技术类期刊中寻宝,同时你本人还需要加持丰富的开发实践经验。如果这些都没问题,你仍然可以从本书中受益,因为它“海纳百川”,把所有精华汇聚于一处,非常方便你随时参考。
专业经验
介绍编程
语言的书
其他介绍
软件的书
杂志上
发表的文章
软件构建
技术参考
本书的关键收益
不管背景如何,本书都可以帮助你以更少的时间和更少的痛苦写出更好的程序。
? 一本完整的软件构建参考 本书讨论了软件构建的方方面面,比如软件质量和编程思维。它直击软件构建的真实细节,比如构建类的步骤,抽丝剥茧,阐述数据和控制结构的使用、调试、重构和代码调优技术及策略等。对于这些主题,不必按顺序从头读到尾。因为本书在设计的时候,已经优先考虑到要让大家更容易找到自己感兴趣的具体信息。
? 随时可用的检查清单 全书包含35 个检查清单,可以用来评估软件架构、设计方法、类和子程序的质量、变量名称、控制结构、代码布局和测试用例等。
? 时新的信息 本书描述前沿技术,许多技术都还没有普及成为商业开发实践。本书的素材取自行业实践和研究机构,描述的很多开发技术在未来很多年都普遍适用。
? 从更广的视角来看待软件开发 通过本书,你将有机会以参观者的角度,不再疲于奔命,而是冷静下来搞清楚哪些行得通,哪些行不通。实干派的程序员基本上没有时间读上几百本书籍和专业技术期刊上发表的文章( 其中的精华都包含在本书中)。
纳入本书的研究经验和开发经验将帮助你展开想象,启发你对项目的思考,让你能够选择策略性的行动,从而使自己不至于反反复复地掉入同样的坑中。
? 字字珠玑,全是干货 有些技术书籍华而不实,废话十之八九,仅有一两成的真知灼见。本书兼容并蓄,会讲到每种编程技术的利与弊。对于特定项目的具体要求,你显然比旁观者
更为清楚。所以,为了帮助你在特定条件下作出更好的决策,本书提供了你需要掌握的客观信息。
? 可以应用于大多数常见编程语言的概念 本书描述的技术可以充分用于你所选择的编程语言,不管是C 语言、C# 语言、Java 语言还是其他语言。
? 大量代码示例 本书包含将近500 个代码示例,好代码有,烂代码也有。之所以包含这么多代码示例,是因为我个人从这些代码示例中受益匪浅。推己及人,我希望其他程序员也能够从中收获良多。这些代码范例涉及多种编程语言,因为至少掌握两种语言通常是区分专业程序员和非专业程序员的分水岭。作为一名程序员,一旦意识到编程准则超越于任何一种特定语言的语法,就意味着专业知识的殿堂已经向他敞开大门,质量和生产力从此以后将出现质的飞跃。为了尽可能减轻多种编程语言所带来的负担,我有意回避了只有真正内行才看得懂的语言特性( 除非还有具体展开的讨论)。你不需要通过理解不同代码片段之间的每个细微差异来理解它们的意义。如果把注意力集中在要阐述的关键点上,你会发现自己完全能够读懂代码,不管它是用什么语言来写的。为了让你更容易理解,我特别针对代码范例中的重要部分增加了注释。
? 访问其他信息来源 本书收集了大部分以软件构建为主题的信息,但这还没完。除第1 章外,各章的“更多资源”小节还给出了其他书籍和文章,以方便大家进一步了解最感兴趣的主题。
为什么要写这本书
软件工程领域已经充分意识到,迫切需要一本全面包含高效开发实践的软件开发参考手册。
计算机科学与技术委员会有一份报告指出,软件开发质量和生产力要想取得最大的效益,只能来自于对现有高效软件工程实践相关知识进行编纂、分类并广泛传播(CSTB 1990, McConnell 1997a)。该委员会最后得出一个结论:与这些软件工程实践相关的知识的传播策略要根植于“软件工程参考手册”这个基本概念。
? 软件构建是一个长期不受重视的主题 有那么一段时间,软件开发和写代码被混为一谈。但在软件开发周期中一些独特的活动被识别出来之后,圈子中有些思想领袖就开始花时间分析项目管理、需求、设计和测试,并掀起一场轰轰烈烈的方法论之争。对这些新领域进行研究的热潮,把原本一脉相承的代码构建冷落在一旁,就像它和软件开发没有什么关系一样。
对代码构建的讨论之所以冷门,还有一个原因。有人建议,如果把代码构建当作独立的软件开发活动,就意味着必须把它当作一个独立的阶段。实际上,软件活动和阶段真的没有必要有任何一一对应的特定关系,不管其他软件活动是以阶段、迭代还是其他方式来执行,都不影响我们对代码构建进行讨论,这样做才是“正确”的。
? 软件构建的重要性不可小觑 软件构建长期被研究人员和技术作家忽略的另一个原因是,他们错误地认为,相较于其他软件开发活动,代码构建是一个相对机械的过程,几乎没有任何改进的机会。然而,事实并非如此。
在小型项目中,代码构建的投入占比一般为65% 左右,中型项目为50%。对于错误,小型项目中代码构建所产生的占比为75%,中型和大型项目则为50% ~ 75%。显然,错误占比为50% ~ 75% 的任何活动都有机会得以显著改进( 第27 章包含更详细的统计数据和分析)。
有评论人士指出,尽管代码构建错误在总的错误中占比很高,但其修复成本低于需求和架构错误。言下之意,代码构建的重要性也就不该那么高。没错,构建错误的修复成本实际上并不高。但研究人员发现,一直以来,一些不起眼儿的代码错误却是最终造成修复成本高达几亿美元的一些软件错误(Weinberg 1983, SEN 1990)。显然,修复成本不高,并不意味着它们就应该优先级低。
具有讽刺意味的是,软件构建之所以不受重视,另一个原因居然是它是软件生命周期中唯一一个必须要认真完成的活动。需求可以靠假设,用不着认真开发;架构可以打折扣,用不着认真设计;测试可以缩水或者略过不做,用不着做全盘计划和执行。但是,如果要开发一个程序,那么一定得好好构建代码,这样一来,构建便在改进开发实践中成为一个独特而富有成效的领域。
关于高效构建实践,还没有一本理想的同类书。
软件构建的重要性既然那么明显,我便理所当然地认为我在构思这本书的时候,肯定已经有其他人写过高效构建实践的书。
显然,业界需要一本介绍如何进行高效编程的书。但我发现,软件构建方面的书乏善可陈,而且都不全面。有些书写于二十世纪九十年代之前甚至更早,讲的是只有真正内行才看得懂的小众语言,比如ALGOL、PL/I、Ratfor 和Smalltalk。有些是压根儿没有写过生产代码*
(译注:所谓生产代码,是指包含系统逻辑并在生产环境中运行的那部分代码。)的教授写的。教授们写的技术书适用于学生的项目,但对于这些技术在整个大规模软件开发环境中是否适用,他们并没有多少概念。还有一些书呢,则鼓吹作者最新最爱的方法体系,完全忽略那些庞大的、经年累月沉淀下来的实践知识宝库。
简而言之,从来没有一本书能够像本书一样,从专业经验、行业研究和学术成果中萃取出这样一套实用的编程技术体系,包含当前的编程语言、面向对象的编程语言以及前沿的开发实践。显然,以编程为主题的书需要由知晓最新理论发展水平的人来写,而不是真正动手写代码构建软件产品并以实践为乐的人来写。对于本书,我的设想是全面而完整地讨论如何构建代码,是一本由程序员写给程序员看的书。
作者说明
欢迎来信讨论本书讨论的任何一个主题,勘误建议和其他相关话题都可以。请通过电子邮件[email protected] 联系,或者访问网站www.stevemcconnell.com。
史蒂夫·麦康奈尔(Steve McConnell)
2004 年阵亡将士纪念日
于华盛顿贝尔维尤
“当艺术评论家们聚在一起的时候,谈的都是形式啊,结构和意义什么的。当艺术家们聚在一起的时候,谈论的却是在哪里可以买到便宜的松脂油。”
—毕加索
评论
还没有评论。