目录 1
绪论 1
0.1 历史的回顾 1
0.2 软件的定义 2
0.3 什么是软件工程? 5
0.4 软件工程的大环境 7
0.5 软件工程究竟像什么? 8
0.5.1 雪球理论——做软件就像滚雪球 9
0.5.2 软件工程拆控制论——软件生产过程是个离散多环控制系统 10
0.5.3 兵法三十六计的启示 11
0.6 本书的组织 13
方法篇 17
1 经济为本 17
1.1 投入产出的概念 18
1.2 经济为本的启示 20
1.2.1 为技术而技术是条死胡同 20
1.2.2 以经济原则指导软件项目的决策过程 21
1.2.3 按照产品规律来营销软件产品 21
1.2.4 以收益为依据规划设计产品 23
小结 23
2 用户为先 25
2.2.1 界面设计和风格 26
2.2 用户友好的交互界 26
2.1 用户需求分析 26
2.2.2 界面的本地化 27
2.3 软件安装和部署 28
2.4 用户培训和技术认证 30
2.5 用户大会和开发人员网络 30
2.6 用户文档 31
2.7 用户支持和反馈 31
2.8 系统升级和版权管理 32
2.9 软件咨询服务 34
小结 35
3.1 什么是软件需求? 37
3 管理需求 37
3.2 了解需求 39
3.3 记录需求 41
3.4 追踪需求 42
3.5 在变化中管理需求 43
小结 44
4 及早集成 47
4.1 软件工程项目的风险 49
4.2 及早集成才能滚雪球 50
4.3 少食多餐 51
小结 52
5 连续验证 53
5.1 有关测试的理论 54
5.2 测试自动化 55
5.3 软件缺陷跟踪系统的概念和实际应用 57
5.3.1 软件缺陷的生命周期 58
5.3.2 欲穷千里目,更上一层楼 58
5.4 软件的“测不准”原理 59
5.5 另类的验证 59
小结 60
6 控制变化 61
6.1 循序渐进 62
6.2 同步协调 64
小结 65
7 规范流程 67
7.1 规范要点 68
7.2 CMM 69
7.3 Rational Unified Process 70
7.4 极限编程 70
7.5 发展方向 71
17.4.1 隐含规则 (1 73
小结 73
8 快速原型 75
8.1 软件中的“概念车” 75
8.2 大行不顾细谨 77
8.3 走向产品 78
小结 79
9 借鸡下蛋 81
9.1 外包 81
9.2 买进 83
9.3 开放代码运动 84
小结 86
10 开放标准 89
10.1 开放的意义 89
10.2 开放标准的种类 91
10.3 支持开放标准 92
小结 93
11 避繁就简 97
设计篇 97
11.1.1 面向履历表的设计 97
11.1 “不简单”的设计 97
11.1.2 “难得糊涂”的设计 98
11.1.3 委员会式的设计 99
11.2 简单就是金钱 99
11.3 简单才真的不简单 100
11.4 关键是平衡 103
11.5 皇帝的新衣 104
小结 105
12 因地制宜 107
12.1 有没有万能钥匙? 107
12.2 考量的因素 108
12.3 软件设计中的若干对矛盾 110
12.4 要马儿跑又要马儿不吃草 116
小结 117
13 变中求静 119
13.1 变在那里? 119
13.2 针对变化而设计 122
13.2.1 数据和代码的分离 122
13.2.2 输入数据和配置参数的分离 124
13.2.3 不变的和常变的代码分离 125
13.3 灰色地带 127
13.4 XML和数据化 129
小结 130
14.1 巨人的肩膀 131
14 分层平台 131
14.2 为什么软件要分层? 132
14.2.1 层次提升 132
14.2.2 隐藏细节 133
14.2.3 标准互换 134
14.3 分层的原则 135
14.3.1 实现和接口分离原则 135
14.3.2 单向性原则 135
14.4.1 OSI模型 136
14.3.3 服务接口的粒度提升原则 136
14.4 典型的分层设计 136
14.4.2 三层应用结构 138
14.5 分层的网络化 138
14.5.1 客户/服务器计算模式 138
14.5.2 万维网的拓展 139
14.6 应用编程接口 API 139
14.7 服务编程接口 SPI 141
小结 142
15 内外有别 143
15.1 MVC结构 144
15.2 万维网应用也要内外有别吗? 146
15.3 模型的设计 147
15.4 正交化设计 148
小结 149
16 模块封装 151
16.1 软件芯片 151
16.2 静态模块的粒度 152
16.2.1 函数 153
16.2.2 文件 153
16.2.3 类 154
16.2.4 相关类集合 154
16.3.1 构件 155
16.3.2 插入件 155
16.3 动态模块 155
16.2.5 子系统 155
16.3.3 进程 156
16.3.4 可执行应用 157
16.3.5 企业运行环境 157
16.4 模块关系的分析 157
16.4.1 代码类关系 158
16.4.2 数据类关系 158
16.5 模块划分 159
16.5.1 分割的原则 159
16.6.1 复用情形下的新问题 160
16.6 软件构件复用的理想 160
16.5.2 模块间的通信 160
16.6.2 没有金刚钻,别揽瓷器活 162
小结 163
17 合约接口 165
17.1 软件世界的“合同” 165
17.2 编程接口设计的“五项基本原则” 166
17.3 网络条件的新问题 171
17.4 从“貌合”到“神合” 173
17.4.2 言行一致 174
17.5 非编程式接口 175
小结 175
18 面向对象 177
18.1 面向对象的三性 178
18.1.1 继承性和逻辑三段论 178
18.1.2 封装性 180
18.1.3 多态性 181
18.2 继承“税” 182
18.2.1 多包“含” 182
18.2.2 单重继承 183
18.3 面向对象的建模和UML 183
18.3.1 软件建模 183
18.3.2 建模语言 184
18.4 双向工程 185
18.5 面向对象的编程语言 187
小结 188
19 巧用模板 189
19.1 变模板为“魔”板 190
19.1.1 编程 190
19.1.2 代码生成 191
19.1.3 数据转换 193
19.1.4 产生文档 194
19.2 通用模板语言和引擎 195
19.2.1 Velocity 196
19.2.2 XSLT 200
19.3.3 模板MVC 203
19.3.2 模板的模块化 203
19.3.1 模板流水线 203
19.3 模板也要正交吗? 203
小结 204
20 能伸能缩 205
20.1 伸缩性要从设计抓起 205
20.2 结构设计的适应性 206
20.2.1 并行度规划 206
20.2.2 逻辑分层和物理分布 207
20.2.3 同步还是异步 207
20.2.4 资源的竞争和平衡 207
20.3.1 调用函数重入 208
20.3 多线程安全性 208
20.3.2 变量可见度 209
20.3.3 死锁和保护 210
20.4 算法可伸缩 211
20.4.1 算法并行的可能性 211
20.4.2 线性化算法的必要性 211
20.4.3 递归算法 212
小结 214
21 套用成解 215
21.1 框架 215
21.2 面向对象方法中的设计定式 219
21.2.1 生成类定式 219
21.2.2 行为类定式 221
21.2.3 结构类定式 226
小结 228
22 见好就收 229
22.1 软件设计的使命 229
22.2 见好不收的误区 231
22.2.1 追求完美 231
22.2.2 画蛇添足 232
22.2.3 清谈误国 232
小结 233
23 决不重复 237
23.1 重复是万恶之首 237
实现篇 237
23.2 典型的代码重复 238
23.2.1 常量重复 239
23.2.2 变量或者属性的重复 241
23.2.3 代码重复 243
23.2.4 逻辑性重复 246
23.2.5 结构性重复 247
23.3 代码之外的重复 248
23.3.1 代码和数据库定义的重复 248
23.3.2 代码和库函数的重复 249
23.3.3 代码和注释的重复 250
23.3.4 测试说明和用户需求的重复 250
23.3.6 代码注解和文档 251
23.3.5 设计和代码的重复 251
小结 252
24 通俗易懂 253
24.1 写代码和写文章 253
24.2 代码的认知模型 254
24.3 误区种种 257
24.3.1 飞流直下三千尺,疑是银河落九天 257
24.3.2 为人性僻耽佳句,语不惊人死不休 258
24.3.3 千呼万唤始出来,犹抱琵琶半遮面 260
24.3.4 爱上层楼,为赋新词强说愁 263
24.4 入乡随俗 265
小结 267
25 精益求精 269
25.1 回炉改造的目的 269
25.2 有备才能无患 271
25.2.1 单元测试的概念和应用 272
25.2.2 谁来测试测试代码? 275
25.2.3 集成开发环境 275
25.2.4 版本控制 276
25.2.5 两个“动不得” 276
25.3 典型的回炉办法 276
25.3.1 去除重复 276
25.3.3 清理门户 277
25.3.2 返朴归真 277
25.3.4 面向侧面编程 278
小结 278
26 优化性能 281
26.1 多一事不如少一事 282
26.2 擒贼先擒王,打蛇找七寸 284
26.3 优化的方法 285
26.3.1 算法本身 285
26.3.2 经典代码优化方法 286
26.3.3 面向对象编程语言的优化 291
26.3.4 并行计算 293
26.3.5 体系结构 296
26.4 也别太执著 298
小结 298
27 照猫画虎 299
27.1 书法临帖的启示 299
27.2 软件工程中的“拿来主义” 301
27.3 “猫”在哪里? 302
27.4 邯郸学步的“戒”鉴 304
27.5 解剖麻雀 305
小结 306
28 严堵漏洞 307
28.1 资源泄漏 307
28.1.1 内存泄漏 307
28.1.2 网络资源泄漏 309
28.1.3 其他资源泄漏 310
28.2 防范性编程 311
28.2.1 空指针检查 311
28.2.2 返回值检查 312
28.2.3 存取控制 313
28.2.4 想不到的命名覆盖 315
28.2.5 例外不例外 317
28.2.6 宣检 319
28.2.7 明知山有虎,须要绕道行 320
小结 321
28.3 习惯成自然 321
29 雁过留声 323
29.1 版本控制概念和使用 323
29.1.1 有迹可循——变化的历史轨迹 323
29.1.2 协同工作——创建分支互不影响 325
29.1.3 灵活配置——创建多样性 327
29.2 使用版本控制工具的注意事项 329
29.2.1 有所选择 329
29.2.2 勤做备份 330
29.3 代码的注解 330
29.4 Log的使用和一般原则 332
小结 334
30.1 不是选择的选择 335
30 自动流程 335
30.2 哪些要自动化? 336
30.2.1 部分代码和文档生成 336
30.2.2 软件的编译和包装发布 337
30.2.3 质量测试 338
30.2.4 日常维护 339
30.3 与其他信息系统的集成 339
30.4 还要人的参与吗? 340
小结 341
31 利器常新 343
31.1 常用工具 344
31.2 锦上添花 347
31.3 语言的语言 348
31.4 专业联络 349
31.5 知识库框架 351
小结 353
管理篇 357
32 分工协作 357
32.1 软件管理的特殊性 357
32.1.1 人的因素 357
32.1.2 项目 359
32.2 组织结构 359
32.2.1 外科手术队 360
32.2.2 导演和制片人 361
32.2.4 分工不分家 362
32.2.3 三驾马车 362
32.3 雪球式成长 363
32.4 民主和集中 363
小结 364
33 目标驱动 365
33.1 代码量之谜 365
33.2 三个臭皮匠抵上一个诸葛亮? 366
33.3 “聪明”五项基本原则 367
33.4 激励机制 368
33.5 人才战略 370
33.5.1 管理梯队和技术梯队 370
33.5.2 师傅和徒弟 370
33.5.3 培养计划 371
小结 372
34 常来常往 373
34.1 升级须知 373
34.2 沟通的重要性 374
34.2.1 与客户的交流 374
34.2.2 项目团队之间的交流 374
34.2.3 开发队伍内部的交流 375
34.3 沟通形式 375
34.3.1 开会 375
34.3.2 电子邮件 376
34.4 技术审查 377
34.3.3 正式文档 377
34.5 开发环境的“风水” 378
34.6 分布式开发团队的沟通 380
小结 381
35 有张有弛 383
35.1 阶段性调整 383
35.2 发布聚会 384
35.3 不妨换换口味 385
35.4 需要锲而不舍吗? 387
35.5 7+1>8 387
小结 388
36.1 经验之经验 389
36 不断总结 389
36.2 学而不思则罔,思而不学则殆 391
36.3 怎么总结 393
36.3.1 两个基本原则 393
36.3.2 总结形式 393
36.4 从实践中来再回到实践中去 394
小结 395
后记 397
参考文献 399
网络资源 403
附录 兵法三十六计 405