书籍详情
代码质量
作者:(希)斯宾耐立思(Spinellis,D.)著,左飞,吴跃,李洁译
出版社:电子工业出版社
出版时间:2012-07-01
ISBN:9787121174216
定价:¥89.00
购买这本书可以去
内容简介
Jolt大奖素有"软件业之奥斯卡"的美称,本丛书精选自Jolt历届获奖图书,以植根于开发实践中的独到工程思想与杰出方法论为主要甄选方向。Diomidis Spinellis首部著作《代码阅读》(Code Reading)旨在阐明程序员应如何理解与修改代码,与此不同的是,《代码质量》重点讨论代码的非功能特性,深入讲述代码如何满足重要的非功能性需求,如可靠性、安全性、可移植性和可维护性,以及时间效率和空间效率。本书从Apache Web应用服务器、BSD UNIX操作系统和HSQLDB Java数据库等开源项目中攫取数百个小例子,并以实例为基准点,辅以理论分析,从实用的角度讲述每个专业软件开发人员能立即运用的概念和技术。《代码质量》荣获2007年Jolt大奖,适用于不同知识层次的软件工作、程序开发和研究人员。
作者简介
自1985年开始,本书作者DiomidisSpinellis在开发大量开创性的,并受到极高评价的商业和开源项目的过程中,一直在钻研、发展本书中所提及的各项技术,期间他编写和维护的代码行数超过25万行。他在英国伦敦帝国理工学院获得了软件工程方向的硕士学位及计算机科学博士学位。目前,他是希腊雅典经济与商业大学管理科学与技术系的教授。他曾撰写过多部畅销世界的计算机技术图书,包括《架构之美》、《代码质量》和《代码阅读》等。
目录
表目录
图目录
原书序言
前言
第1章 导论 1
1.1 软件质量 1
1.1.1 用户、制造者和管理者眼中的质量 2
1.1.2 质量属性 4
1.1.3 紧张的世界 6
1.2 如何阅读本书 8
1.2.1 排版约定 8
1.2.2 图示 9
1.2.3 图表 11
1.2.4 汇编代码 11
1.2.5 练习 11
1.2.6 补充材料 12
1.2.7 工具 12
第2章 可靠性 15
2.1 输入问题 16
2.2 输出问题 19
2.2.1 不完整输出或输出缺失 19
2.2.2 错误时刻的正确结果 22
2.2.3 错误的格式 22
2.3 逻辑问题 24
2.3.1 偏差为一的错误与循环迭代 24
2.3.2 被忽视的极端情况 25
2.3.3 被遗漏的情况、条件测试或步骤 27
2.3.4 被遗漏的方法 32
2.3.5 多余的功能 35
2.3.6 误解 37
2.4 计算问题 39
2.4.1 不正确的算法或计算 39
2.4.2 表达式中错误的操作数 41
2.4.3 表达式中不正确的运算符 44
2.4.4 运算符优先级问题 45
2.4.5 溢出、下溢和符号转换错误 46
2.5 并行性与时序问题 48
2.6 接口问题 53
2.6.1 不正确的例程或参数 53
2.6.2 没有测试返回值 55
2.6.3 未做错误探查或恢复 58
2.6.4 资源泄漏 60
2.6.5 面向对象功能的误用 63
2.7 数据处理问题 64
2.7.1 不正确的数据初始化 64
2.7.2 引用错误的数据变量 66
2.7.3 越界引用 69
2.7.4 不正确的下标使用 72
2.7.5 不正确的比例或数据单位 73
2.7.6 错误的数据打包与解包 75
2.7.7 不一致的数据 77
2.8 容错 79
2.8.1 管理策略 79
2.8.2 空间冗余 81
2.8.3 时间冗余 83
2.8.4 可复原性 84
第3章 安全性 93
3.1 脆弱代码 94
3.2 缓冲区溢出 98
3.3 竞态条件 103
3.4 问题API 106
3.4.1 容易出现缓冲区溢出的函数 106
3.4.2 格式字符串漏洞 108
3.4.3 路径和命令行解释器元字符漏洞 110
3.4.4 临时文件 111
3.4.5 不适合做加密用途的函数 112
3.4.6 可篡改数据 114
3.5 不可信输入 115
3.6 结果验证 120
3.7 数据与特权泄漏 124
3.7.1 数据泄漏 124
3.7.2 特权泄漏 128
3.7.3 Java的方案 129
3.7.4 分离特权代码 131
3.8 特洛伊木马 133
3.9 工具 135
第4章 时间性能 139
4.1 测量技术 143
4.1.1 负载描述 144
4.1.2 受限于I/O的任务 145
4.1.3 受限于内核的任务 148
4.1.4 受限于CPU的任务和剖析工具 149
4.2 算法复杂性 158
4.3 独立的代码 163
4.4 与操作系统交互 167
4.5 与外设交互 173
4.6 非故意的交互 175
4.7 缓存 178
4.7.1 一个简单的系统调用缓存 178
4.7.2 替换策略 180
4.7.3 预先计算结果 182
第5章 空间性能 189
5.1 数据 190
5.1.1 基本数据类型 191
5.1.2 聚合数据类型 194
5.1.3 对齐 196
5.1.4 对象 202
5.2 内存组织 206
5.3 内存层级结构 210
5.3.1 主存及其高速缓存 211
5.3.2 磁盘缓存和后备存储器 214
5.3.3 交换区和基于文件的磁盘存储 216
5.4 进程/操作系统接口 217
5.4.1 内存分配 218
5.4.2 内存映射 219
5.4.3 数据映射 219
5.4.4 代码映射 220
5.4.5 访问硬件资源 221
5.4.6 进程间通信 222
5.5 堆内存管理 224
5.5.1 堆碎片 225
5.5.2 堆剖析 230
5.5.3 内存泄漏 233
5.5.4 垃圾回收 237
5.6 栈内存管理 239
5.6.1 栈帧 240
5.6.2 栈空间 243
5.7 代码 248
5.7.1 设计期 250
5.7.2 编码期 252
5.7.3 构建期 253
第6章 可移植性 261
6.1 操作系统 262
6.2 硬件与处理器架构 267
6.2.1 数据类型的属性 267
6.2.2 数据存储 269
6.2.3 特定于机器的代码 271
6.3 编译器与语言扩展 273
6.3.1 编译器错误 273
6.4 图形用户界面(GUI) 277
6.5 国际化与本地化 279
6.5.1 字符集 280
6.5.2 区域 282
6.5.3 消息 285
第7章 可维护性 293
7.1 测量可维护性 294
7.1.1 可维护性指数 294
7.1.2 面向对象程序的度量 300
7.1.3 包的相关性度量 309
7.2 可分析性 316
7.2.1 一致性 318
7.2.2 表达式格式化 319
7.2.3 语句格式化 320
7.2.4 命名惯例 321
7.2.5 语句级注释 324
7.2.6 版本注释 326
7.2.7 视觉结构:块与缩进 327
7.2.8 表达式、函数以及方法的长度 328
7.2.9 控制结构 331
7.2.10 布尔表达式 335
7.2.11 可辨认性与内聚性 337
7.2.12 依赖和耦合 339
7.2.13 代码块注释 351
7.2.14 数据声明注释 354
7.2.15 恰当的标识符名字 355
7.2.16 依赖的位置 356
7.2.17 不确定性 357
7.2.18 可复查性 358
7.3 可变性 363
7.3.1 识别 363
7.3.2 分离 368
7.4 稳定性 377
7.4.1 封装与数据隐藏 378
7.4.2 数据抽象 381
7.4.3 类型检查 383
7.4.4 编译时断言 386
7.4.5 运行时检查和查看时断言 389
7.5 可测试性 390
7.5.1 单元测试 391
7.5.2 集成测试 394
7.5.3 系统测试 396
7.5.4 测试覆盖度分析 398
7.5.5 偶发性测试 401
7.6 开发环境的影响 406
7.6.1 增量构建 407
7.6.2 调整构建性能 410
第8章 浮点运算 417
8.1 浮点数表示 418
8.1.1 量度误差 420
8.1.2 舍入 421
8.1.3 内存格式 424
8.1.4 规格化和隐含的一位 425
8.1.5 阶码偏移 425
8.1.6 负数 426
8.1.7 反向规格化数 426
8.1.8 特殊值 427
8.2 舍入 428
8.3 溢出 432
8.4 下溢 434
8.5 消去 437
8.6 合并 441
8.7 无效运算 445
附录A 源代码致谢人员名单 453
参考文献 455表 目 录
表2-1 测试极端情况 26
表2-2 测试一个不含尾端的非对称范围的例子 26
表2-3 整数量的范围 46
表2-4 在程序生命周期不同阶段所做的参数类型检查 54
表2-5 在C++中约束类的使用 64表3-1 UNIX服务器开放网络端口列表 96
表3-2 Windows工作站开放网络端口列表 96
表3-3 进行ftpd缓冲区攻击时的栈 100
表3-4 展开栈(默认情况) 102
表3-5 在攻击过程中展开栈 102
表3-6 不安全的C函数及其安全的替代函数 107
表3-7 Java 2平台SE 5.0的许可 130表4-1 用时剖析特征、诊断工具及解决方案 144
表4-2 由环境切换和进程间通信导致的开销 168
表4-3 低速外设导致的开销 174表5-1 不同架构下基本数据类型的表示 191
表5-2 AMD64架构上结构体元素的对齐 197
表5-3 一个程序在不同架构和操作系统上的内存布局 209
表5-4 连续的地址空间限制及相应的解决方案 216
表5-5 构建选项对程序大小的影响 254表6-1 各种开发平台的可移植性问题 262
表6-2 Java平台标准字符编码 282
表6-3 区域特定的字段 284表7-1 可维护性指数的参数 295
表7-2 WebServerConnection方法与它们使用的字段 306
表7-3 WebServerConnection类的相似(内聚)方法与相异方法 307
表7-4 不同类型的访问控制下可以访问类成员的方法数 379表8-1 不同舍入模型的例子 422
表8-2 不同浮点格式的关键属性 424
表8-3 导致异常的运算和操作数 445
图 目 录
图1-1 软件质量的各个方面的例子:使用中质量、
外部质量、内部质量及过程质量 3
图1-2 本书脉络:软件质量的要素 5
图1-3 质量特征间的冲突 7
图1-4 标注列表示例 9
图1-5 基于UML的图示符号 10图2-1 使用评注,toString方法的反射式实现 21
图2-2 借助策略模式关联代码和数据 30
图2-3 使用接口实现创建处理器 30
图2-4 对象私有资源的显式管理 34
图2-5 邮件传送代理守护程序sendmail的调试代码 37
图2-6 通过静态分析探查null指针引用 42
图2-7 借助wait和notify管理资源的使用 49
图2-8 使用有瑕疵的双检锁模式 51
图2-9 内存泄漏与资源泄漏之间的关系 61
图2-10 在NetBSD内核中分配与释放文件描述符 62
图2-11 使用自动产生的源代码定义字体的轮廓 65
图2-12 NetBSD源代码中全局变量定义(左)和引用(右)的位置 67
图2-13 NetBSD内核全局变量所用的类型 68
图2-14 将字节串编码为改进过的UTF-8格式 76
图2-15 SCSI设备驱动程序中一个命令序列重传 84
图2-16 自有故障的磁盘上恢复数据 87图3-1 FTP守护进程中的缓冲区溢出 99
图3-2 PPP守护代码中的一个竞态条件 104
图3-3 pppd漏洞的检查/使用时间差利用 104
图3-4 检查/使用时间差漏洞利用时序图 105
图3-5 strcpy和strcat的不安全用法 108
图3-6 strcpy和strcat正确应用在一个动态分配大小的缓冲区上 108
图3-7 不安全地清除环境变量 116
图3-8 安全地清除环境变量 116
图3-9 未正确检查traceroute实现中的错误返回值 122
图3-10 在TCP Wrappers程序中嵌入特洛伊木马代码 134图4-1 专家对于优化代码的警告 142
图4-2 在HSQLDB代码中EJP对帕累托法则的阐述 151
图4-3 对于vfprintf函数的gprof输出的例子 153
图4-4 调用图中处理时间的传播 156
图4-5 某些常见算法类别的相对性能 159
图4-6 简单cat调用中的系统调用 169
图4-7 logger调用时本地进程间通信产生的系统调用 171
图4-8 ping名字查询的远程DNS进程间通信所产生的系统调用 172
图4-9 系统颠簸对运行时性能的影响 176
图4-10 使用用户ID来命名缓存代码 179
图4-11 缓存数据库行记录 181图5-1 结构体的两种存储方式:填充以确保对齐(上),
打包以节省内存(下) 199
图5-2 从大到小排列结构体元素,确保对齐且节省内存 200
图5-3 OpenCL算法继承树的UML类图 203
图5-4 三个OpenCL算法类的C++虚函数表 204
图5-5 指向实例数据的Java对象 205
图5-6 有着一个指向实例数据和类数据的句柄的Java对象 206
图5-7 内存资源的类型 207
图5-8 进程内存组织 207
图5-9 现代计算机的一个存储层次结构 211
图5-10 100万个分配对象的大小分布 227
图5-11 100万个分配对象的生命周期分布 227
图5-12 用于显示内存碎片的内存池快照 228
图5-13 外部内存碎片的一个例子 229
图5-14 内部内存碎片的一个例子 229
图5-15 Apache HTTP服务器内存分配剖析 231
图5-16 sed流编辑器的内存剖析 232
图5-17 valgrind内存泄漏测试工具的报告 236
图5-18 C正则表达式库中的内存泄漏 237
图5-20 一个栈帧的内容 242
图5-21 栈大小的快照 244
图5-22 数据和栈大小的关系 245
图5-23 源文件与目标文件大小之间的关系 249
图5-24 ACE地址类型中的继承 251图6-1 使用隔离层来提供可移植性 264
图6-2 存储于小端与大端架构上的整数0x04030201 270
图6-3 GUI可移植性策略的例子 278
图6-4 使用catgets接口做消息处理 287
图6-5 使用gettext接口做消息处理 287
图6-6 使用GNU gettext工具的消息本地化流程 288
图6-7 在Java servlet中访问本地化消息 290图7-1 测量扩展圈复杂度 297
图7-2 FreeBSD内核和用户程序的增长与可维护性指标随时间的变化 298
图7-3 所有FreeBSD模块的可维护性指数分布 298
图7-4 类的加权方法数度量:对所有的HSQLDB类(左);
不同的WMC值对应的Eclipse类个数(右) 301
图7-5 继承树深度度量:对于所有的HSQLDB类(左);
不同DIT值对应的Eclipse类的数量(右) 302
图7-6 HSQLDB:高DIT值的类的继承树度量和它们所定义的方法数 302
图7-7 Eclipse类的子类数度量 303
图7-8 对象类之间的耦合:对于每个HSQLDB类(左);
不同的CBO值对应的Eclipse类的数量(右) 304
图7-9 类的响应:对于所有的HSQLDB类(左);
不同的CBO值对应的Eclipse类的数量(右) 305
图7-10 方法的内聚缺乏度:对于所有的HSQLDB类(左);
对应于不同LCOM值的Eclipse类的个数(右) 308
图7-11 org.hsqldb包中的公有类和私有类 310
图7-12 Tomcat中一个不稳定的包 311
图7-13 Eclipse中一个稳定的包 311
图7-14 Eclipse的离心耦合与向心耦合之间的关系 312
图7-15 Eclipse包(左)和第三方包(右)的不稳定性分布 313
图7-16 junit包的稳定依赖 313
图7-17 MX4J包的不太稳定依赖 314
图7-18 Eclipse包的不稳定性与抽象度分布 315
图7-19 Xerces与Eclipse间的循环依赖 316
图7-20 所有的FreeBSD模块可维护性指数与模块大小的关系 329
图7-21 65000个C函数的函数长度分布 330
图7-22 在处理用户响应的过程中缺乏规则性 333
图7-23 用于处理用户响应的一个规则的控制结构 333
图7-24 在同一代码段里不同的break和continue范围 334
图7-25 ed的DES CBC实现中的公共耦合 345
图7-26 ed的DES CBC实现中的公共耦合关系 346
图7-27 在NetBSD内核中读取并使用磁盘分区内核 349
图7-28 低带宽X(LBX)扩展中增量缓存的设计 359
图7-29 低带宽X(LBX)扩展中增量缓存的实现 360
图7-30 servlet容器各元素间不必要的关系 370
图7-31 使用责任链设计模式来分离类 370
图7-32 两个不同的Catalina文件的公共代码行 374
图7-33 难以修改的格式化注释(左)与便于修改的格式化注释(右) 377
图7-34 在最内部的代码块中声明变量 378
图7-35 第7版UNIX中直接解释目录的数据 383
图7-36 Java 1.5之前的代码使用松散类型 384
图7-37 C库fomd实现中的特别单元测试 392
图7-38 JUnit测试框架中的单元测试 393
图7-39 Perl源代码测试覆盖度(左)和分支覆盖度(右)
与测试用例执行数的关系 400
图7-40 正则表达式引擎中断言的使用 402
图7-41 包含文件依赖关系的简化图 409
图7-42 文档依赖 411图8-1 二次方程消去误差以及对精度的影响 440
图8-2 计算远离原点的三角形面积时的合并误差 442
图8-3 验证浮点运算结果的代码 448
图目录
原书序言
前言
第1章 导论 1
1.1 软件质量 1
1.1.1 用户、制造者和管理者眼中的质量 2
1.1.2 质量属性 4
1.1.3 紧张的世界 6
1.2 如何阅读本书 8
1.2.1 排版约定 8
1.2.2 图示 9
1.2.3 图表 11
1.2.4 汇编代码 11
1.2.5 练习 11
1.2.6 补充材料 12
1.2.7 工具 12
第2章 可靠性 15
2.1 输入问题 16
2.2 输出问题 19
2.2.1 不完整输出或输出缺失 19
2.2.2 错误时刻的正确结果 22
2.2.3 错误的格式 22
2.3 逻辑问题 24
2.3.1 偏差为一的错误与循环迭代 24
2.3.2 被忽视的极端情况 25
2.3.3 被遗漏的情况、条件测试或步骤 27
2.3.4 被遗漏的方法 32
2.3.5 多余的功能 35
2.3.6 误解 37
2.4 计算问题 39
2.4.1 不正确的算法或计算 39
2.4.2 表达式中错误的操作数 41
2.4.3 表达式中不正确的运算符 44
2.4.4 运算符优先级问题 45
2.4.5 溢出、下溢和符号转换错误 46
2.5 并行性与时序问题 48
2.6 接口问题 53
2.6.1 不正确的例程或参数 53
2.6.2 没有测试返回值 55
2.6.3 未做错误探查或恢复 58
2.6.4 资源泄漏 60
2.6.5 面向对象功能的误用 63
2.7 数据处理问题 64
2.7.1 不正确的数据初始化 64
2.7.2 引用错误的数据变量 66
2.7.3 越界引用 69
2.7.4 不正确的下标使用 72
2.7.5 不正确的比例或数据单位 73
2.7.6 错误的数据打包与解包 75
2.7.7 不一致的数据 77
2.8 容错 79
2.8.1 管理策略 79
2.8.2 空间冗余 81
2.8.3 时间冗余 83
2.8.4 可复原性 84
第3章 安全性 93
3.1 脆弱代码 94
3.2 缓冲区溢出 98
3.3 竞态条件 103
3.4 问题API 106
3.4.1 容易出现缓冲区溢出的函数 106
3.4.2 格式字符串漏洞 108
3.4.3 路径和命令行解释器元字符漏洞 110
3.4.4 临时文件 111
3.4.5 不适合做加密用途的函数 112
3.4.6 可篡改数据 114
3.5 不可信输入 115
3.6 结果验证 120
3.7 数据与特权泄漏 124
3.7.1 数据泄漏 124
3.7.2 特权泄漏 128
3.7.3 Java的方案 129
3.7.4 分离特权代码 131
3.8 特洛伊木马 133
3.9 工具 135
第4章 时间性能 139
4.1 测量技术 143
4.1.1 负载描述 144
4.1.2 受限于I/O的任务 145
4.1.3 受限于内核的任务 148
4.1.4 受限于CPU的任务和剖析工具 149
4.2 算法复杂性 158
4.3 独立的代码 163
4.4 与操作系统交互 167
4.5 与外设交互 173
4.6 非故意的交互 175
4.7 缓存 178
4.7.1 一个简单的系统调用缓存 178
4.7.2 替换策略 180
4.7.3 预先计算结果 182
第5章 空间性能 189
5.1 数据 190
5.1.1 基本数据类型 191
5.1.2 聚合数据类型 194
5.1.3 对齐 196
5.1.4 对象 202
5.2 内存组织 206
5.3 内存层级结构 210
5.3.1 主存及其高速缓存 211
5.3.2 磁盘缓存和后备存储器 214
5.3.3 交换区和基于文件的磁盘存储 216
5.4 进程/操作系统接口 217
5.4.1 内存分配 218
5.4.2 内存映射 219
5.4.3 数据映射 219
5.4.4 代码映射 220
5.4.5 访问硬件资源 221
5.4.6 进程间通信 222
5.5 堆内存管理 224
5.5.1 堆碎片 225
5.5.2 堆剖析 230
5.5.3 内存泄漏 233
5.5.4 垃圾回收 237
5.6 栈内存管理 239
5.6.1 栈帧 240
5.6.2 栈空间 243
5.7 代码 248
5.7.1 设计期 250
5.7.2 编码期 252
5.7.3 构建期 253
第6章 可移植性 261
6.1 操作系统 262
6.2 硬件与处理器架构 267
6.2.1 数据类型的属性 267
6.2.2 数据存储 269
6.2.3 特定于机器的代码 271
6.3 编译器与语言扩展 273
6.3.1 编译器错误 273
6.4 图形用户界面(GUI) 277
6.5 国际化与本地化 279
6.5.1 字符集 280
6.5.2 区域 282
6.5.3 消息 285
第7章 可维护性 293
7.1 测量可维护性 294
7.1.1 可维护性指数 294
7.1.2 面向对象程序的度量 300
7.1.3 包的相关性度量 309
7.2 可分析性 316
7.2.1 一致性 318
7.2.2 表达式格式化 319
7.2.3 语句格式化 320
7.2.4 命名惯例 321
7.2.5 语句级注释 324
7.2.6 版本注释 326
7.2.7 视觉结构:块与缩进 327
7.2.8 表达式、函数以及方法的长度 328
7.2.9 控制结构 331
7.2.10 布尔表达式 335
7.2.11 可辨认性与内聚性 337
7.2.12 依赖和耦合 339
7.2.13 代码块注释 351
7.2.14 数据声明注释 354
7.2.15 恰当的标识符名字 355
7.2.16 依赖的位置 356
7.2.17 不确定性 357
7.2.18 可复查性 358
7.3 可变性 363
7.3.1 识别 363
7.3.2 分离 368
7.4 稳定性 377
7.4.1 封装与数据隐藏 378
7.4.2 数据抽象 381
7.4.3 类型检查 383
7.4.4 编译时断言 386
7.4.5 运行时检查和查看时断言 389
7.5 可测试性 390
7.5.1 单元测试 391
7.5.2 集成测试 394
7.5.3 系统测试 396
7.5.4 测试覆盖度分析 398
7.5.5 偶发性测试 401
7.6 开发环境的影响 406
7.6.1 增量构建 407
7.6.2 调整构建性能 410
第8章 浮点运算 417
8.1 浮点数表示 418
8.1.1 量度误差 420
8.1.2 舍入 421
8.1.3 内存格式 424
8.1.4 规格化和隐含的一位 425
8.1.5 阶码偏移 425
8.1.6 负数 426
8.1.7 反向规格化数 426
8.1.8 特殊值 427
8.2 舍入 428
8.3 溢出 432
8.4 下溢 434
8.5 消去 437
8.6 合并 441
8.7 无效运算 445
附录A 源代码致谢人员名单 453
参考文献 455表 目 录
表2-1 测试极端情况 26
表2-2 测试一个不含尾端的非对称范围的例子 26
表2-3 整数量的范围 46
表2-4 在程序生命周期不同阶段所做的参数类型检查 54
表2-5 在C++中约束类的使用 64表3-1 UNIX服务器开放网络端口列表 96
表3-2 Windows工作站开放网络端口列表 96
表3-3 进行ftpd缓冲区攻击时的栈 100
表3-4 展开栈(默认情况) 102
表3-5 在攻击过程中展开栈 102
表3-6 不安全的C函数及其安全的替代函数 107
表3-7 Java 2平台SE 5.0的许可 130表4-1 用时剖析特征、诊断工具及解决方案 144
表4-2 由环境切换和进程间通信导致的开销 168
表4-3 低速外设导致的开销 174表5-1 不同架构下基本数据类型的表示 191
表5-2 AMD64架构上结构体元素的对齐 197
表5-3 一个程序在不同架构和操作系统上的内存布局 209
表5-4 连续的地址空间限制及相应的解决方案 216
表5-5 构建选项对程序大小的影响 254表6-1 各种开发平台的可移植性问题 262
表6-2 Java平台标准字符编码 282
表6-3 区域特定的字段 284表7-1 可维护性指数的参数 295
表7-2 WebServerConnection方法与它们使用的字段 306
表7-3 WebServerConnection类的相似(内聚)方法与相异方法 307
表7-4 不同类型的访问控制下可以访问类成员的方法数 379表8-1 不同舍入模型的例子 422
表8-2 不同浮点格式的关键属性 424
表8-3 导致异常的运算和操作数 445
图 目 录
图1-1 软件质量的各个方面的例子:使用中质量、
外部质量、内部质量及过程质量 3
图1-2 本书脉络:软件质量的要素 5
图1-3 质量特征间的冲突 7
图1-4 标注列表示例 9
图1-5 基于UML的图示符号 10图2-1 使用评注,toString方法的反射式实现 21
图2-2 借助策略模式关联代码和数据 30
图2-3 使用接口实现创建处理器 30
图2-4 对象私有资源的显式管理 34
图2-5 邮件传送代理守护程序sendmail的调试代码 37
图2-6 通过静态分析探查null指针引用 42
图2-7 借助wait和notify管理资源的使用 49
图2-8 使用有瑕疵的双检锁模式 51
图2-9 内存泄漏与资源泄漏之间的关系 61
图2-10 在NetBSD内核中分配与释放文件描述符 62
图2-11 使用自动产生的源代码定义字体的轮廓 65
图2-12 NetBSD源代码中全局变量定义(左)和引用(右)的位置 67
图2-13 NetBSD内核全局变量所用的类型 68
图2-14 将字节串编码为改进过的UTF-8格式 76
图2-15 SCSI设备驱动程序中一个命令序列重传 84
图2-16 自有故障的磁盘上恢复数据 87图3-1 FTP守护进程中的缓冲区溢出 99
图3-2 PPP守护代码中的一个竞态条件 104
图3-3 pppd漏洞的检查/使用时间差利用 104
图3-4 检查/使用时间差漏洞利用时序图 105
图3-5 strcpy和strcat的不安全用法 108
图3-6 strcpy和strcat正确应用在一个动态分配大小的缓冲区上 108
图3-7 不安全地清除环境变量 116
图3-8 安全地清除环境变量 116
图3-9 未正确检查traceroute实现中的错误返回值 122
图3-10 在TCP Wrappers程序中嵌入特洛伊木马代码 134图4-1 专家对于优化代码的警告 142
图4-2 在HSQLDB代码中EJP对帕累托法则的阐述 151
图4-3 对于vfprintf函数的gprof输出的例子 153
图4-4 调用图中处理时间的传播 156
图4-5 某些常见算法类别的相对性能 159
图4-6 简单cat调用中的系统调用 169
图4-7 logger调用时本地进程间通信产生的系统调用 171
图4-8 ping名字查询的远程DNS进程间通信所产生的系统调用 172
图4-9 系统颠簸对运行时性能的影响 176
图4-10 使用用户ID来命名缓存代码 179
图4-11 缓存数据库行记录 181图5-1 结构体的两种存储方式:填充以确保对齐(上),
打包以节省内存(下) 199
图5-2 从大到小排列结构体元素,确保对齐且节省内存 200
图5-3 OpenCL算法继承树的UML类图 203
图5-4 三个OpenCL算法类的C++虚函数表 204
图5-5 指向实例数据的Java对象 205
图5-6 有着一个指向实例数据和类数据的句柄的Java对象 206
图5-7 内存资源的类型 207
图5-8 进程内存组织 207
图5-9 现代计算机的一个存储层次结构 211
图5-10 100万个分配对象的大小分布 227
图5-11 100万个分配对象的生命周期分布 227
图5-12 用于显示内存碎片的内存池快照 228
图5-13 外部内存碎片的一个例子 229
图5-14 内部内存碎片的一个例子 229
图5-15 Apache HTTP服务器内存分配剖析 231
图5-16 sed流编辑器的内存剖析 232
图5-17 valgrind内存泄漏测试工具的报告 236
图5-18 C正则表达式库中的内存泄漏 237
图5-20 一个栈帧的内容 242
图5-21 栈大小的快照 244
图5-22 数据和栈大小的关系 245
图5-23 源文件与目标文件大小之间的关系 249
图5-24 ACE地址类型中的继承 251图6-1 使用隔离层来提供可移植性 264
图6-2 存储于小端与大端架构上的整数0x04030201 270
图6-3 GUI可移植性策略的例子 278
图6-4 使用catgets接口做消息处理 287
图6-5 使用gettext接口做消息处理 287
图6-6 使用GNU gettext工具的消息本地化流程 288
图6-7 在Java servlet中访问本地化消息 290图7-1 测量扩展圈复杂度 297
图7-2 FreeBSD内核和用户程序的增长与可维护性指标随时间的变化 298
图7-3 所有FreeBSD模块的可维护性指数分布 298
图7-4 类的加权方法数度量:对所有的HSQLDB类(左);
不同的WMC值对应的Eclipse类个数(右) 301
图7-5 继承树深度度量:对于所有的HSQLDB类(左);
不同DIT值对应的Eclipse类的数量(右) 302
图7-6 HSQLDB:高DIT值的类的继承树度量和它们所定义的方法数 302
图7-7 Eclipse类的子类数度量 303
图7-8 对象类之间的耦合:对于每个HSQLDB类(左);
不同的CBO值对应的Eclipse类的数量(右) 304
图7-9 类的响应:对于所有的HSQLDB类(左);
不同的CBO值对应的Eclipse类的数量(右) 305
图7-10 方法的内聚缺乏度:对于所有的HSQLDB类(左);
对应于不同LCOM值的Eclipse类的个数(右) 308
图7-11 org.hsqldb包中的公有类和私有类 310
图7-12 Tomcat中一个不稳定的包 311
图7-13 Eclipse中一个稳定的包 311
图7-14 Eclipse的离心耦合与向心耦合之间的关系 312
图7-15 Eclipse包(左)和第三方包(右)的不稳定性分布 313
图7-16 junit包的稳定依赖 313
图7-17 MX4J包的不太稳定依赖 314
图7-18 Eclipse包的不稳定性与抽象度分布 315
图7-19 Xerces与Eclipse间的循环依赖 316
图7-20 所有的FreeBSD模块可维护性指数与模块大小的关系 329
图7-21 65000个C函数的函数长度分布 330
图7-22 在处理用户响应的过程中缺乏规则性 333
图7-23 用于处理用户响应的一个规则的控制结构 333
图7-24 在同一代码段里不同的break和continue范围 334
图7-25 ed的DES CBC实现中的公共耦合 345
图7-26 ed的DES CBC实现中的公共耦合关系 346
图7-27 在NetBSD内核中读取并使用磁盘分区内核 349
图7-28 低带宽X(LBX)扩展中增量缓存的设计 359
图7-29 低带宽X(LBX)扩展中增量缓存的实现 360
图7-30 servlet容器各元素间不必要的关系 370
图7-31 使用责任链设计模式来分离类 370
图7-32 两个不同的Catalina文件的公共代码行 374
图7-33 难以修改的格式化注释(左)与便于修改的格式化注释(右) 377
图7-34 在最内部的代码块中声明变量 378
图7-35 第7版UNIX中直接解释目录的数据 383
图7-36 Java 1.5之前的代码使用松散类型 384
图7-37 C库fomd实现中的特别单元测试 392
图7-38 JUnit测试框架中的单元测试 393
图7-39 Perl源代码测试覆盖度(左)和分支覆盖度(右)
与测试用例执行数的关系 400
图7-40 正则表达式引擎中断言的使用 402
图7-41 包含文件依赖关系的简化图 409
图7-42 文档依赖 411图8-1 二次方程消去误差以及对精度的影响 440
图8-2 计算远离原点的三角形面积时的合并误差 442
图8-3 验证浮点运算结果的代码 448
猜您喜欢