高清版.pdf” file_size: “49.19MB” total_pages: 194 processed_date: “2026-08-26” method: “扫描版 PDF,pdftoppm 渲染目录+各章首页,vision 分析提取知识结构” status: done isbn: “978-7-115-34294-2” series: “图灵程序设计丛书”
软件开发与创新——ThoughtWorks文集(续集)
第二本 ThoughtWorks 文集,延续第一卷的”技术散文”风格,12 篇文章覆盖编程语言、测试、架构、交付创新、数据可视化五大主题。
基本信息
- 英文原名:The ThoughtWorks Anthology, Volume 2: More Essays on Software Technology and Innovation
- 原版版权:2012 年 ThoughtWorks
- 中文版:2014 年 1 月第 1 版,人民邮电出版社
- 字数:283 千字,194 页
- 主编:Rebecca Parsons、Martin Fowler 作前言
- 译者序:郑晔(ThoughtWorks 首席咨询师)
全书结构
全书分为 4 大部分 + 引言 + 参考文献 + 索引:
| 部分 | 包含章节 | 主题 |
|---|---|---|
| 引言 | 第 1 章 | 文集背景与阅读建议 |
| 第一部分 语言 | 第 2-4 章 | 新语言、OO 设计、函数式编程 |
| 第二部分 测试 | 第 5-7 章 | 性能测试、JS 测试、验收测试 |
| 第三部分 软件开发问题 | 第 8-11 章 | Java Web、集成、特性开关、交付创新 |
| 第四部分 数据可视化 | 第 12 章 | 信息可视化设计 |
第一部分:语言
第 2 章 最有趣的语言(Ola Bini)
核心观点:当下正处于编程语言复兴时代——新语言不断涌现,古老语言在新领域重焕生机,是自 1970 年代以来编程语言领域最好的时代。
语言复兴的原因:
- 需求端:软件问题越来越复杂,传统方法失效;并发/并行需求激增;创业公司对发布速度的要求
- 供给端:创建语言的工具高度成熟;JVM/CLR/LLVM 等平台降低了生态门槛
本章介绍的 7 种语言:
| 语言 | 核心特点 | 页码 |
|---|---|---|
| Clojure | Lisp 方言,JVM 平台,函数式+并发 | 5 |
| CoffeeScript | 编译到 JS,简化语法 | 10 |
| Erlang | 并发/分布式/高可用,古老语言重焕新生 | 14 |
| Factor | 串联式(concatenative)语言 | 18 |
| Fantom | JVM/.NET 双平台,类型系统优雅 | 21 |
| Haskell | 纯函数式,惰性求值,类型类 | 26 |
| Io | 原型式 OO,极简语法 | 30 |
关联:《SICP》-计算机程序的构造和解释-第二版(语言范式的底层基础)
第 3 章 面向对象程序设计:对象优于类(Aman King)
核心观点:OO 实践的重心正在从”预先设计类的结构”转向”以可运行的对象、解决实际问题为核心”。
转变的两个驱动力:
- 编码方式变化:TDD 推动代码(接口+实现)持续迭代,而非预先设计
- 技术栈多元化:从单一 Java 到 Ruby/JS/Groovy/Scala 多语言混用
核心概念:
- 类关注 vs 对象关注:类关注 = 关注数据属性、方法签名、继承结构;对象关注 = 关注对象在运行时的角色、职责、协作
- 角色的角色:对象在不同场景中扮演不同角色,比继承更灵活
- 职责分离:通过对象协作而非类层次实现
- 测试角度:TDD 自然驱动出更细粒度的对象设计
- 代码库线索:代码中处处可见”对象关注”的痕迹
“对象关注”的四种语言:Ruby、JavaScript、Groovy、Scala
关联:《实现模式》-Implementation Patterns-Kent Beck(Kent Beck 的 OO 设计模式思想)
第 4 章 使用面向对象语言进行函数式编程(Marc Needham)
核心观点:函数式编程的理念不必局限于函数式语言,在 C#/Ruby/Java/Scala 等 OO 语言中同样可以应用并获益。
关键实践:
| 概念 | 说明 |
|---|---|
| 集合思维转换 | 从”遍历每个元素”到”整体操作集合”(map/filter/reduce) |
| 拥抱集合 | 用集合操作替代命令式循环 |
| 勿忘封装 | 函数式不代表放弃封装,集合操作仍需合理封装 |
| 惰性求值 | 延迟计算直到需要时,提升效率 |
| 一等公民与高阶函数 | 函数作为值传递、作为参数/返回值 |
| 状态最小化 | 减少可变状态,降低复杂度 |
| 其他理念 | 模式匹配、柯里化、不可变性等 |
关联:《SICP》-计算机程序的构造和解释-第二版(函数式编程的思想源头)
第二部分:测试
第 5 章 极限性能测试(Alistair Jones, Patrick Kua)
核心观点:将敏捷价值观和原则应用到性能测试中,打破传统”性能测试 = 项目后期独立阶段”的模式。
灵感来源:Kent Beck —— “极限编程将一些常识性的原则和实践推向了极致。”
传统方式的不足:
- 性能测试作为独立阶段,安排在开发后期
- 与敏捷开发的迭代节奏不匹配
- 发现问题太晚,修复成本高
极限性能测试的核心方法:
| 实践 | 说明 |
|---|---|
| 独立的多功能团队 | 性能测试不是独立阶段,而是融入迭代 |
| 描述需求 | 用用户故事描述性能需求 |
| 设定计划与排定优先级 | 性能需求和功能需求一起排优先级 |
| 实现性能故事 | 像实现功能故事一样实现性能故事 |
| 展示与反馈 | 每个迭代展示性能改进 |
关键基础设施:
- 性能负责人(performance champion):专人推动
- 自动化部署:一键部署到性能测试环境
- 自动化分析:自动分析性能结果
- 结果仓库:历史性能数据可追溯
- 结果可视化:图表化展示性能趋势
- 自动化测试流程:性能测试纳入 CI
- 健全性测试(sanity test):快速验证环境
- 持续性能测试:每次构建都跑性能基线
- 规范的性能提升:系统化性能优化
收益:更好的性能、更低的复杂度、更高的团队效率、更合理的优先级、为持续交付奠基
关联:《Scrum敏捷软件开发》-Succeeding-with-Agile-Mike-Cohn(敏捷实践的组织级框架)
第 6 章 测试驱动 JavaScript(Brian Blignaut, Luca Grulla)
核心观点:Web 已从静态内容演进为富应用平台,JavaScript 是核心语言,但 JS 测试远未得到应有重视,需要系统化的测试驱动方法。
背景:
- JavaScript 长期被当作”二等语言”
- Web 2.0 后 JS 代码复杂度爆炸式增长
- jQuery 等库降低了开发门槛但增加了维护难度
- HTML5/本地存储/离线应用进一步推动富客户端发展
核心方法:
- 分离关注点:将 JS 代码按职责分离(DOM 操作 / 业务逻辑 / 数据层)
- 交互测试优于集成测试:单元测试关注交互,集成测试用 HTML 夹具
- 验收测试验证全集成:端到端测试确保整体功能
- 持续集成:JS 测试纳入 CI 流水线
工具分类:
- 单元测试框架
- 语法检查(Lint)
- Mock 框架
关联:《重构》-改善既有代码的设计(JS 代码重构同样适用)
第 7 章 构建更好的验收测试(James Bull)
核心观点:自动化验收测试常陷入”慢、脆、难维护”的困境,好的验收测试应该是快速、有弹性、易维护的。
验收测试的 5 项条件(隐含定义):
- 端到端验证系统行为
- 从用户角度出发
- 可自动化执行
- 验证业务价值
- 作为”完成”的判定标准
7.1 快速测试
| 实践 | 说明 |
|---|---|
| 基于用户行程的测试 | 围绕真实用户路径设计测试 |
| 并行执行测试集 | 多线程/多机器并行加速 |
| 多种测试驱动器 | 不同层级用不同测试工具 |
| 分开运行测试 | 按重要性/速度分层执行 |
| 等待元素显示要小心 | 避免硬编码 sleep,用智能等待 |
7.2 有弹性的测试
| 实践 | 说明 |
|---|---|
| 单独选择页面元素 | 用稳定的选择器(ID/数据属性),避免脆弱的 XPath/CSS |
| 等待元素显示(再强调) | 智能等待是稳定性的关键 |
| 测试中设置测试依赖数据 | 测试自己准备数据,不依赖外部状态 |
| 测试集成点 | 对外部依赖打桩,隔离测试 |
7.3 易于维护的测试
| 实践 | 说明 |
|---|---|
| 使用页面模型(Page Object) | 封装页面交互,测试只描述行为 |
| 结构一致的测试集 | 统一命名和组织方式 |
| 测试代码=产品代码 | 同样的质量标准、评审、重构 |
| 不受限于工具 | 工具是手段,不是目标 |
7.4 付诸实践
- 一地团队:同一地点的团队如何协作维护测试
- 维护测试,人人有责:不是测试人员的事,是整个团队的事
- 故事启动(story kickoff):需求讨论时就考虑验收测试
- 结对测试开发:测试和开发结对写测试
- 故事展示:演示时展示验收测试通过
关联:《Scrum敏捷软件开发》-Succeeding-with-Agile-Mike-Cohn(验收测试与敏捷团队协作)
第三部分:软件开发问题
第 8 章 现代 Java Web 应用(Sam Newman)
核心观点:传统 Java Web 受 Servlet API 和容器藩篱限制,发展滞后于其他平台;现代 Java Web 应用需要借鉴其他平台的优秀模式。
传统 Java Web 的问题:
- 依赖有状态服务器,难以水平扩展
- 绑定容器,测试和部署都笨重
- 违反 HTTP 规范(有状态、session 滥用)
- 厂商推动功能臃肿的商用容器
四大设计原则:
| 原则 | 说明 | 页码 |
|---|---|---|
| 无状态服务器 | 状态存客户端(cookie),服务端无状态,易于集群和扩展 | 120 |
| 容器可选 | 容器外测试,甚至不需要容器;降低依赖,提升可测试性 | 123 |
| 按新鲜程度分区 | 缓存分层策略:不同内容按更新频率区分缓存策略 | 125 |
| POST 重定向到 GET | PRG 模式,避免重复提交,符合 HTTP 语义 | 129 |
缓存策略要点:
- 缓存是可扩展网站的秘密武器
- 选择缓存的内容:静态资源 > 读多写少的数据 > 计算结果
- 按新鲜程度分区:不同数据有不同的缓存失效策略
- 反向代理和 CDN:在更靠近用户的位置缓存
关联:《程序员的自我修养》-链接、装载与库(理解底层有助于理解 Web 容器)
第 9 章 驾驭集成难题(Julio Maia)
核心观点:增量式开发中集成点多、集成环境不稳定/效率低,无法做到所有修改都在集成环境测试;需要通过关注点分离、可执行契约和模块化测试基础设施来驾驭。
持续集成方法的 4 个关键实践:
| 实践 | 说明 |
|---|---|
| 稳定基准(stable baseline) | 维护一个稳定的集成基准版本 |
| 集成 stub | 用桩替代未完成/不稳定的集成对端 |
| 构建流水线 | 分层构建:单元测试 → 组件测试 → 集成测试 |
| 监控器(monitor) | 实时监控集成健康状态 |
其他关键实践:
- 定义集成契约:以测试作为契约载体,明确各方预期
- 度量和可见性:收集生产力指标,用数据展示价值
- 价值传递:向利益相关方展示快速反馈的价值,获取支持
- 模块化测试基础设施:测试框架本身也要模块化、可维护
关联:《ThoughtWorks实践集锦》-第二册-实效敏捷(持续集成的更多实践)
第 10 章 实践中的特性开关(Cosmin Stejerean)
核心观点:特性分支模式导致延迟集成、合并风险高、阻碍重构;基于主干开发 + 特性开关是更好的替代方案。
特性分支的痛点:
- 分支越久,集成风险越高,合并成本越大
- 就算定期从主干合并到分支,也无法解决信息不对称
- 主干开发人员不知道分支在做什么,主干重构需要手动同步
- 分支重构进一步提升合并复杂度
- 最终导致开发人员排斥重构,技术债务累积
特性开关的核心思想:
- 所有特性在主干上开发
- 未完成的特性通过开关关闭,不暴露给用户
- 保持持续集成的收益
特性开关的关键实践:
| 实践 | 说明 | 页码 |
|---|---|---|
| 依赖注入 | 用 DI 管理开关实现,避免散落的 if | 139 |
| 注解 | 用注解标识特性开关代码 | 140 |
| 分离静态资源 | 特性相关的静态资源独立管理 | 141 |
| 阻止意外泄露 | 防止未完成特性意外暴露 | 142 |
| 运行时开关 | 可在运行时动态切换 | 142 |
| 不兼容依赖 | 处理特性间的依赖冲突 | 143 |
| 特性开关的测试 | 测试开关的各种状态组合 | 143 |
| 删除完成特性的开关 | 上线稳定后及时清理开关,避免技术债务 | 144 |
⚠️ 特性开关不是银弹:开关本身也会增加复杂度,必须及时清理已上线的开关。
关联:《重构》-改善既有代码的设计(清理开关是重构的一部分)、《Scrum敏捷软件开发》-Succeeding-with-Agile-Mike-Cohn(特性开关与敏捷交付)
第 11 章 交付创新(Marc McNeill)
核心观点:多数组织难以持续创新,问题在于创新过程缺乏敏捷性;需要将业务创新与交付流程融合,让创新真正落地。
痛点对比:
- 传统企业:某零售银行 4 年没能替换在线银行产品;某传媒组织 1 年设计站点概念没写一行代码
- 科技公司:Google 12 年间从搜索引擎发展到浏览器/移动 OS/办公软件;Facebook 4 年成长为巨头
- 差距不是因为团队没干活,而是时间花在了调研、分析、设计、商业案例等”前置环节”
核心方法:
- 价值流向:理解创新从想法到交付的价值流
- 协作文化:打破部门墙,跨职能协作
- 敏捷产品调研与发现:用敏捷方法做产品探索
- 快速启动(quick start):快速启动项目,快速验证
- 持续设计,持续交付:设计不是一次性的,而是和交付持续迭代
核心洞察:创新失败不是因为想法不好,而是因为交付太慢;敏捷不仅适用于编码阶段,也适用于创新和产品发现阶段。
关联:《ThoughtWorks实践集锦》-第二册-实效敏捷(敏捷实践的更多案例)
第四部分:数据可视化
第 12 章 一图胜千言(Farooq Ali)
核心观点:数据时代不缺数据,缺的是洞见;信息可视化是挖掘数据价值的核心工具,需要系统化的设计方法,而非仅凭创意。
核心理念:形式服从功能(form follows function)——可视化的形式设计要服务于数据表达和问题解决。
可视化设计原则
- 清晰 > 美观
- 展示数据,而非装饰
- 最小化墨水-数据比(data-ink ratio)
- 避免图表垃圾(chart junk)
可视化设计流程(5 步)
| 步骤 | 说明 | 页码 |
|---|---|---|
| 定义领域任务 | 明确用户要解决什么问题 | 160 |
| 任务抽象 | 将具体任务抽象为可视化任务 | 161 |
| 数据抽象 | 将数据抽象为可可视化的形式 | 161 |
| 可视化编码 | 选择合适的视觉编码方式 | 163 |
| 评估与完善 | 验证效果,持续迭代 | 167 |
可视化设计模式
| 模式 | 适用场景 |
|---|---|
| 随时间变化的数据 | 趋势图、时序图、折线图 |
| 相关性探索 | 散点图、热力图、平行坐标 |
| 层次与”局部到整体” | 树图、旭日图、冰柱图 |
| 连结和网络 | 节点-链接图、邻接矩阵 |
工具与框架
- 可视化程序库:D3.js、Processing 等
- 图型化工具:Tableau、Excel 等
关联:《奇思妙想》-15位计算机天才及其重大发现(可视化先驱的故事)
全书核心洞察
- 多范式融合是趋势:函数式编程思想融入 OO 语言,OO 从”类为中心”转向”对象为中心”,语言边界在模糊
- 测试的全栈化:从单元测试到性能测试、JS 测试、验收测试,测试不再是后期阶段,而是贯穿全生命周期
- 持续交付的深化:特性开关、持续集成、持续性能测试——都是为了更快、更安全地交付价值
- 创新需要敏捷:不仅编码要敏捷,产品发现、创新过程也要敏捷,否则”创新”只是纸上谈兵
- 数据可视化是核心能力:数据爆炸时代,将数据转化为洞见的可视化能力越来越重要
与第一卷的关系
- 第一卷(《软件开发沉思录》):更偏向”软件本质”的思考,涵盖架构、设计、流程、文化
- 第二卷(本书):更偏向”新趋势与实践”,涵盖新语言、Web 现代化、特性开关、数据可视化等
- 两卷都是文集形式,每篇文章独立成篇,可以按需阅读