“重构”第二版

在过去的两年里,我一直致力于我的书“重构”的第二版。这里我详细介绍了新版以及一些备忘录,描述了我在这个项目最后几个月的想法。

这本书现在已经上市,你可以在informit icon(出版商的网站)、亚马逊或你喜欢的书店购买。购买这本书可以让你访问规范的网络版 - 它包含了实体书或电子书版本中没有的额外内容。

这本书可能需要一段时间才能通过各种分销渠道传播。特别是它往往很难到达其他国家,电子格式的国际可用性也会变得复杂,因为它与各个国家的图书发行协议有关。

如果你难以获得副本,最好的办法是联系informit,因为我的出版商比我更了解图书发行中的复杂情况。

详情 

我很幸运能与肯特·贝克一起参与C3项目,该项目催生了极限编程。我从肯特那里学到了很多东西(而且还在学习),但有一件事让我印象深刻,那就是他不断重构代码库以保持其健康的方法,这种方法当时被称为“重构”。在我的其他咨询工作中,我强调了这种技术的价值,但我无法为人们提供一本学习它的书,所以我最终自己写了一本。它是在20世纪结束之前出版的。

那是将近二十年前,这项技术现在已经广为人知,尽管它并没有像应该的那样得到很好的执行。这本书也保持得很好,我认为你可以拿这本书来学习如何重构,就像你多年前学习的那样。但这本书已经显露出它的年代,比如使用java.util.Vector

所以这些年来我一直想修改它,但我也有所犹豫。毕竟它仍然很好地教授了这项技术,而第二版往往没有改进第一版。但另一个力量一直在拉扯着我。在我写这本书的时候,将类作为代码结构的主要机制的主流观点正在兴起。然而,如今我们看到其他结构发挥着更大的作用。在我看来,类仍然很有价值,但我们的重构需要不再以类为中心,认识到它们可以随着代码被训练成新的形状而出现和消失。

在2015年和2016年初,我写了一系列文章,探讨了重构的各种情况,这帮助我了解了是否应该着手重写,以及如果要重写,应该如何重写。到2016年中期,我已经准备好开始认真工作了。如果你一直在想为什么我没有像以前那样经常为martinfowler.com写东西,那是因为从那时起,我的写作精力都集中在本书上了。

第二版的变化

这些变化既非常小,又涵盖了所有方面。它们很小,因为本书的基本结构没有改变。我从一个开头的例子开始,然后是关于原则的一章,对“代码异味”的调查,以及对测试的介绍。本书的大部分内容是重构的目录,在这68个重构中,除了10个之外,其他所有重构都保留了下来,我还增加了17个新的重构。(这里有详细介绍

尽管本书的整体结构没有改变,但对页面上文字的修改是巨大的。每一章和每一个重构都被重写了,大部分是从头开始写的。我很少有机会从旧版中复制粘贴文本。

重新定位到一个不太以类为中心的观点是其中很大一部分。虽然这听起来可能很简单,比如将“提取方法”改名为“提取函数”,但这确实需要重新思考每个重构的各个方面。我需要重新考虑动机,经常觉得需要重新构建它。机制至少需要详细审查,通常需要完全重写。我没有详细记录这件事,但我的感觉是,对于每一个相对简单的旧重构的导入,都有两个需要完全重新思考。

然而,还有另一个变化,从某种意义上说,它并不那么重要,但肯定会引起很多关注。这些例子不再用Java编写。

当我为我的写作选择一种语言作为示例时,我主要考虑的是读者。我会问“哪种语言能帮助大多数读者理解书中的概念?”重构不是一本特定于语言的书,它的建议可以用Java示例来解释,但重构适用于大多数语言。我选择Java是因为我认为如果用Java编写代码示例,大多数人能够理解。1997年是这样,但2017年呢?

我考虑使用多种语言,这将强调本书的语言中立意图。但我认为这会让读者更加困惑,最好使用一种语言,这样他们就可以习惯一种一致的表达形式。那么哪一种语言对读者来说最容易理解呢?这种语言需要在语言流行度调查中排名前六。它确实有助于有一个基于C的语法,因为大多数程序员会识别基本的代码结构。鉴于此,有两个语言脱颖而出。一个是Java,它仍然被广泛使用,而且易于理解。但我选择了另一种选择:JavaScript。

选择JavaScript对我来说是极具讽刺意味的,因为许多读者可能知道,我不是它的粉丝。它有太多笨拙的边缘情况和笨拙的习语。ECMAScript 2015(ES6)引入了一个相当好的类模型,这使得许多面向对象的重构更容易表达,但仍然存在一些令人讨厌的漏洞,这些漏洞从语言诞生之初就存在于语言的结构中。但选择它而不是Java的令人信服的理由是,它并不完全以类为中心。存在顶层函数,并且使用一等函数很常见。这使得更容易展示在类上下文之外的重构。

一本以网络为中心的书

万维网对我们的社会产生了巨大的影响,尤其影响了我们获取信息的方式。当我写第一版的时候,大多数关于软件开发的知识都是通过印刷品传播的。现在我从网上获取大部分信息。这对像我这样的作者来说是一个挑战,书籍还有存在的必要吗?它们应该是什么样子?

我相信像这样的书籍仍然有存在的必要,但它们需要改变。书籍的价值在于它是一大块知识,以一种连贯的方式组合在一起。在写这本书的时候,我需要收集大量的重构,并以一种一致且集成的形式组织它们。

但这个完整的整体是一个抽象的文学作品,虽然传统上由纸质书来代表,但在未来不一定需要这样。大多数出版行业仍然将纸质书视为主要的表现形式,虽然我们热情地接受了电子书,但它们只是基于纸质书概念的原始作品的电子表现形式。

在这本书中,我正在探索一种不同的方法。我认为这本书的规范形式是网站。纸质书是从网站上选择的一些材料,以一种适合印刷的形式排列。它并没有试图包含规范书籍中的所有重构,特别是因为我将来可能会在规范的网络书籍中添加更多重构。

我们的意图是,当你购买一本“重构”第二版的副本时,你可能会在书店以实体形式购买,或者以任何形式在线购买。你花这笔钱最重要的是永久访问网站。你可以阅读实体书,并在需要的时候访问网站。

这就引出了一个问题,电子书(如epubs和kindle书籍)应该扮演什么角色。有一个强有力的论点认为,它们应该包含网站上的所有信息,毕竟实体尺寸不是一个因素,而且如果我添加了新材料,电子书可以很容易地更新。然而,出版行业并不这么认为,他们期望电子书与实体书的内容相同,因此,至少目前,重构的电子书版本将遵循这一原则。

早期的备忘录 

保持相同的范围(2018年3月28日) 

我想强调的关于这个版本的一件事是,它并没有涵盖比现有书籍更多的范围。它在一定程度上偏离了纯粹以类为中心的结构,但我一直的目标是不要改变本书的范围太多。虽然有很多吸引人的领域可以探索,但我只有有限的时间和精力。所以我遵循了一条规则,即不允许第二版进入新的主题领域。即使只是试图复制第一版的内容,它仍然是两年的扎实工作。我不想增加我花在这上面的时间,毕竟第一版非常成功,所以我的目标是保持它的实用性,而不是试图创造一些新的东西。

我的总体计划是,从第一版中的每个重构开始,并询问需要做些什么才能使它在这个略微改变的上下文中保持相关性。在少数(令人高兴的)情况下,我可以几乎按原样使用重构,将示例简单地重写成JavaScript,然后就完成了。然而,通常情况下,它需要对机制和示例进行重大重新思考。有时这意味着原始的重构被类似的东西所取代。

很有可能,将来我会探索一些新的主题,并添加到网站上的重构库中。当然,我在第一版的时候也这么想过,但大部分都没有实现,所以要带着适当的怀疑态度看待这个想法。但我确实在2015年和2016年初探索了一些关于使用重构来帮助探索各种架构问题的文章。我很享受写作的过程,它们表明了我将来可以轻松使用的一种工具。

处理审查意见(2018年4月3日) 

我花了几天时间(是的,包括周末)处理这本书的审查意见。2月初,我在培生出版社的编辑将这本书的当前状态发送给几个人进行技术审查。这是写书过程中至关重要的一部分,任何作者都会犯错误,我犯了很多错误。审稿人帮助发现这些错误,并突出显示那些没有清楚解释的内容。

这不是这本书材料的第一次审查。当我开始写这本书的时候,我召集了一个小组的人来进行持续的审查。每当我完成一章或几个重构时,我都会把它们发给他们,征求他们的意见。他们的反馈帮助很大。但在某个时候,我需要有人退一步,对整本书进行新的审视,这就是最近这些审稿人介入的地方。目前,我正在处理四位审稿人的意见:威廉·查金、迈克尔·亨格、鲍勃·马丁和比尔·韦克(他也是我持续审查小组的成员)。

我喜欢逐章进行,先看第一章,查看所有人的评论,然后对整章进行处理。“处理”意味着阅读每条评论,并决定如何处理。每条评论都代表着审阅者的观点,有些可能建议修改,有些可能表达某个地方不清楚,有些可能是代码错误。通常我不会对评论做出任何反应,我可能会不同意某人的建议,也许是因为我觉得这超出了本书的范围。迈克尔(他之前为我审阅过书籍)给了我很多关于补充材料的建议,这些建议需要花费数年时间才能跟进,所以我不得不放弃大多数建议。但我并不介意,因为有时这些建议确实需要包含在书中,我很高兴有人提醒我将它们包含进来。

错误是显而易见的需要修复的地方,我经常惊讶于审阅者能发现细微的代码错误。我的自动化代码导入系统避免了许多错误,但自动导入系统存在漏洞,这些漏洞已经帮我避免了一些令人尴尬的错误。迈克尔在这方面特别出色,他一定在他的“湿件”中安装了几个编译器,这也是我认为他是一个优秀的审阅者的原因之一。然而,威廉·查金正在向他发起挑战,所以我觉得自己得到了双重祝福。

澄清往往是最难弄清楚的。有时审阅者只是说“我不明白”,有时则更间接——他们建议了一些暗示他们没有理解我的意思的东西。处理这些问题很困难,因为我必须判断这只是一次性事件,还是更深层次的问题。人们总是会对书中的某些部分感到困惑,试图解决每一个问题只会适得其反——书会变得更大,文章会变得很生硬,读起来很乏味。当多个审阅者遇到同样的问题时,这很有帮助,这样我就可以确信这是我需要修复的问题。例如,我在开头示例中嵌套函数的布局方式让三位审阅者感到困惑,所以我意识到我必须尝试不同的方法。

我一直很喜欢处理审阅评论。获得一些关于我所做的事情是否合理的反馈总是好的。这个阶段特别好,因为它迫使我退一步。近两年来,我一直沉浸在细节中,逐章地编写。现在我可以将材料作为一个整体来看待,但仍然可以深入研究以解决重要的细节。

重构(2018 年 4 月 5 日) 

当我写第一版《重构》时,它被收录到艾迪生-韦斯利的对象技术系列中。我从未将书籍系列看得太重,所以只是按照编辑的建议去做。从那时起,我创建了自己的系列(“签名系列”),并投入了相当多的精力来策划它,以便它只包含我强烈推荐的书籍。所以这本书自然地要移到我自己的系列中。

然而,这不是一个必然的决定。这个系列不是一个包罗万象的系列,而是关于我认为是编程技术方面的基础书籍。我将我最近出版的《NoSQL 精华》提交给了这个系列,但我拒绝了它——因为我认为它不符合这个系列的风格。这听起来有点绕口,但这里确实有一个流程。提交给该系列的每本书都会发送给该系列的所有作者,我会征求他们的意见。在这种情况下,他们帮助我决定拒绝自己。这一次,他们认为这本书很容易被纳入,这加强了我认为它很适合的感受。

审阅更新暂停(2018 年 4 月 6 日) 

正如我在之前的一份备忘录中所说,我很享受阅读审阅评论的过程。然而,我即将暂停这项工作。我即将出差,这意味着今天是我五周内最后一天坐在办公桌前。虽然我可以在旅途中进行一些写作工作,但我大部分时间都会忙于其他事情,无法投入任何精力。 (而且其中也有一些假期,我希望这能让我稍微恢复一下精力。)这是一个令人沮丧的休息,因为我真的希望能够完成书稿,以便更好地专注于其他事情。我原本希望到目前为止已经处理完所有审阅评论,但写作计划与软件开发计划一样糟糕(原因大致相同)。

回到我的办公桌前(2018 年 5 月 18 日) 

本周我终于在五周的旅行后回到了新英格兰的办公桌前。时间过得真快,但我不能抱怨太多,因为过去几周我在克罗地亚度过了一个很棒的假期。亮点包括斯普利特、杜布罗夫尼克、帕克莱尼察国家公园,尤其是普利特维采湖群国家公园

我原本希望在出发前完成书稿,但仍然有一些审阅评论需要修改。在离开前,我还收到了一批最后的评论。所以本周我第一次浏览了最后一批评论,现在只剩下审阅中未完成的任务。坏消息是,所有这些任务都需要一些努力才能修复,因为它们是在我无法快速修复的情况下变成待办事项的。好消息是我只有十四个待办事项。我希望能在下两周内完成它们,然后我就要再次上路了。

本周关于这本书的另一个话题是开始考虑封面。封面设计已经确定,因为它将成为我签名系列的一部分,但这意味着我必须选择一张桥的照片。我们现在正在努力解决这个问题,希望下周我能分享一下。

重写示例(2018 年 5 月 25 日) 

和上周一样,本周我一直在处理审阅评论,以便在开始制作过程之前完成书中的技术内容。上周我浏览了所有评论,完成了所有可以在一小时内完成的简单任务。剩下的就是那些复杂的任务,在游戏后期处理这些任务压力很大,而且我有一个(不可否认,有点自我强加的)截止日期在盯着我。

本周我的工作核心是重写两个示例。这两个示例都是一些审阅者难以理解的示例,所以我需要想出一些我认为更容易理解的东西。这不仅仅是修改文章文本,还包括重写代码。我发现代码示例是我写作中最难的部分之一。我试图创建一些足够复杂以展示主要内容,但又不至于过于复杂的示例。它们仍然是人为地简单化——任何现实的示例都过于复杂,大多数读者都无法理解——但我希望它们能与读者日常的经验产生共鸣。今天我花了大部分时间想出一个大约 50 行代码的示例。我认为它体现了我想要表达的意思,但当我对这段代码进行重构并观察我的文章如何与它配合时,我会学到更多。我乐观地认为它会奏效,但仍然存在相当大的不确定性。

早期的示例特别棘手,因为它是一段更大的重构示例的一部分,是本书未来开篇示例的一部分。这个示例分为三个阶段,审阅者指出了中间阶段的问题。我重新调整了重构的顺序,希望现在一切都清楚多了。有趣的是,这次重构围绕着一个我之前在开篇示例的第一稿中没有写过的重构(拆分阶段)进行。更改的本质是遵循现在已经写好的这个新重构的机制,我很高兴地看到,遵循这些机制似乎让重构变得更容易执行和理解。我书中的机制部分并不是重构的唯一机制,它们也无法在所有情况下都成为最佳机制。我的目标是让它们在大多数情况下都能很好地工作。所以我很高兴遵循这些机制帮助我完成了这个示例。

重写像这样的重构示例让我对 git 非常熟悉。我喜欢让我的所有代码示例“保持活跃”,这样我就可以更改代码,运行测试以确保它仍然有效,并标记其中的一些部分以自动流入书稿文本。我已经用代码示例做了很多年了,这使得生活变得更加轻松。但是,在重构中这样做很棘手,因为我对代码有一系列更改。为了应对这种情况,我将重构序列存储在一个 git 仓库中(必须与存储书稿文本的仓库分开),并将重构捕获为一系列提交。然后,我将代码导入书稿文本,并使用标签来指示提交的 ref 和代码片段的名称。当重写像这样的重构序列时,我会进行很多 cherry-pick 操作,我会对 commit master~7 进行更改,然后将我所做的所有重构更改 cherry-pick 到更改后的提交上。当它运行良好时,这真是太棒了,即使它没有运行良好,也比我处理第一版书籍时要好得多。

我还有最后一周的时间坐在办公桌前,然后我想宣布“完成”。目标看起来仍然可行,尽管这在很大程度上取决于我今天写的 50 行代码在我写关于与之相关的重构步骤时效果如何。

发布到生产环境(2018 年 6 月 1 日) 

随着 5 月份的结束,我达到了一个重要的里程碑,我的出版商称之为“发布到生产环境”。在传统出版的时代,这意味着作者将手稿交给制作团队。此时,我们预计书稿的核心内容不会发生重大变化。会有一些变化:比如书稿进入校对阶段,以及索引等工作——但这些变化不会改变书稿的本质。

在我的早期书籍中,我会将电子文件发送给皮尔森,然后在某个时间点,我会收到校对人员标记的更改的大量打印稿。除了查看这些更改,检查我是否同意它们之外,在书籍上架之前,我几乎不会再参与这本书的任何工作。现在,这个过程更加互动,校对人员和我将共享一个 git 仓库,我会查看差异以查看他建议的更改。但跨越重要桥梁的感觉仍然存在。我不会再重写任何示例,也不会添加任何重要的内容。在某种程度上,这本书已经完成了。(尽管,由于这是一本网络优先的书籍,我打算继续发展它的网络表现形式)。

我感到如释重负,尽管这本书还有很多工作要做,但这仍然是一个重要的里程碑,标志着我对这本书的关注将开始减弱。我并没有完全放松,因为我下周要去马德里参加两个演讲,而演讲旅行对我来说比去看牙医更令人反感。但它确实减轻了我的一些负担。

新封面(2018 年 6 月 13 日) 

当我们开始做签名系列时,封面设计师设计了基本的设计,其中包括为每本书留出不同的照片空间。我决定,这些照片应该遵循该系列所有书籍的主题。当时,我的妻子,一位结构工程师,正在设计桥梁;她后来从水平方向(桥梁和隧道)转向垂直方向(建筑物)。她参与桥梁设计的工作激发了我用桥梁作为书籍的共同主题。所以,每当有作者在我的签名系列中写书时,我都会让他们选择一座桥来装饰封面。理想情况下,这座桥应该与他们有一些个人联系。

在我的系列的第一本书(企业应用架构模式)中,我选择了波士顿的扎金桥。这个联系非常清晰——他们在同一时期建造了这座桥,就在我写这本书的同一时期。在我的第二个系列书籍(领域特定语言)中,我选择了铁桥——这与我成长的地方黑国有关,也是一座历史悠久的桥。

那么,重构这本书应该选择什么呢?我想到的一个想法是,我是否可以在重构和桥梁工程之间建立某种类比——但我与我认识的桥梁工程师的讨论表明,桥梁工程中没有任何东西可以与重构相比。所以,我的思绪转向了非专业的联想。在这种情况下,我开始思考我过去二十多年住在新英格兰期间多次造访的最喜欢的地方之一——阿卡迪亚国家公园。这立刻让我想到选择马车道上的众多漂亮桥梁之一。

但我还想到另一个与阿卡迪亚有关的可能性。在去阿卡迪亚的路上,我们穿过彭博斯科特河。在我写第一本重构书的时候,这条路穿过彭博斯科特河,使用的是沃尔多-汉考克桥,这座悬索桥是由著名的桥梁工程师大卫·斯坦曼设计的。然而,在本世纪初,他们发现这座有 70 年历史的桥需要更换,到 2007 年,这条路就改走新的彭博斯科特海峡大桥了。

在我们去阿卡迪亚的旅行中,我们停下来,让我拍下这两座桥的照片。我很高兴我们终于做到了,因为一年后,沃尔多-汉考克桥被拆除了。(很可惜,我是在阴天拍的照片。)

photo used for cover

虽然我无法在桥梁工程和重构之间建立任何类比,但我可以强迫自己,在重构书籍的两个版本和这两座桥之间建立创造性的类比。

虽然一些推特用户评论说重构书籍的第二版“重构”了第一版,但事实并非如此。(事实上,就像桥梁工程一样,我认为重构与书籍写作之间没有任何类比。)这第二版是旧版本的替代品,就像彭博斯科特海峡大桥取代了沃尔多-汉考克桥一样。沃尔多-汉考克桥展示了创新技术,降低了桥梁建设成本,就像重构书籍描述了一种降低软件系统建设成本的新技术一样。第一版书籍被我签名系列中的新版取代,而新的彭博斯科特海峡大桥与扎金桥的设计类似,扎金桥是该签名系列第一本书的封面桥。

两种读者(2018 年 6 月 27 日) 

在构建软件时,从用户的角度考虑软件非常重要。因此,我们有创建角色的概念,并使用这些角色来帮助指导软件系统的功能和用户体验。同样,对于书籍来说,我必须考虑我的读者,并对应该指导我的写作的角色有一些概念。

对于一篇作品来说,最明显的角色是学生读者——他对书中的主题知之甚少,甚至一无所知,他阅读这本书是为了学习这些内容。这是我的主要角色,我尽力去理解这个读者心中所想,以及如何才能最好地向他传达信息。

但还有一个同样重要的角色——老师。这个角色已经了解了书中大部分内容,甚至全部内容。她使用这本书来帮助指导更初级的开发人员。本质上,这本书是她帮助提高团队技能的工具。

有时她可能会直接使用这本书,告诉一个初级开发人员,他需要将一个特定的类更改为一个值对象,从而使用将引用更改为值重构。在更高级别上,她可能会关注一个代码异味。我听说过的一种技术是,团队负责人指定一个“本周的代码异味”,让团队识别并修复该代码异味的示例。这既可以改进代码,也可以教会开发人员如何识别和修复将来出现的类似问题。

即使这本书没有被直接使用,我希望它仍然以间接的形式派上用场。一个高级开发人员可能了解重构,但这并不意味着她知道如何教授它。教授一个主题本身就是一项技能,它在一定程度上独立于对该主题的了解或执行任务的技能。我经常遇到一些天赋异禀的从业人员,他们不善于向他人传授自己的技能。一本好书可以帮助这些领导者了解如何解释一个主题。将引用更改为值的机制部分并不是执行重构的唯一方法,但遵循这些步骤可以使一个熟练的同事更容易向一个新手展示如何执行它。

像这样第二版的一个有趣的结果是,大多数对这本书感到兴奋的人是老师读者,而不是学生读者。老师们很可能在很多年前,是第一版的学生读者。如果你也是这样的读者,请记住,这本书不会教你任何关于重构的新知识。如果它教你任何东西,那就是如何向你领导的人教授它。当你评估这本书对你是否有用时,不是看你从中学到了什么,而是它如何帮助你加速周围人的学习。

一些隐藏的英雄(2018 年 7 月 10 日) 

我认识的所有技术书籍作者都提到了他们对技术审稿人的巨大债务。我们都写过有重大缺陷的作品,这些缺陷被我们的同行作为审稿人发现了。我很少做技术审稿工作,部分原因是我认为自己不太擅长这项工作,因此我非常敬佩那些承担这项工作的人。审阅别人的书甚至没有微薄的报酬,所以这样做是一种伟大的慷慨行为。

当我开始认真编写这本书时,我创建了一个顾问邮件列表,以便从他们那里获得反馈。随着我的进展,我将新材料的草稿发送给这个小组,并请他们提供反馈。我要感谢以下人员在邮件列表中发布了这些反馈:**Arlo Belshee、Avdi Grimm、Beth Anders-Beck、Bill Wake、Brian Guthrie、Brian Marick、Chad Wathington、Dave Farley、David Rice、Don Roberts、Fred George、Giles Alexander、Greg Doench、Hugo Corbucci、Ivan Moore、James Shore、Jay Fields、Jessica Kerr、Joshua Kerievsky、Kevlin Henney、Luciano Ramalho、Marcos Brizeno、Michael Feathers、Patrick Kua、Pete Hodgson、Rebecca Parsons** 和 **Trisha Gee**。

在这些人中,我特别想强调我在 JavaScript 方面从 **Beth Anders-Beck、James Shore** 和 **Pete Hodgson** 那里得到的特殊帮助。

当我完成了一个相当完整的初稿后,我将其发送出去进行进一步的审阅,因为我想让一些新鲜的眼睛审阅整个草稿。**William Chargin** 和 **Michael Hunger** 都提供了非常详细的审阅意见。我还从 **Bob Martin** 和 **Scott Davis** 那里得到了很多有用的意见。**Bill Wake** 在邮件列表中做出了贡献,并对初稿进行了全面审阅。

我发现邮件列表的增量审阅和最终的全面审阅相结合,效果非常好。如果将所有审阅工作留到最后(就像我之前写过的书,包括第一版一样),那么我会在太晚的时候收到有用的意见。我能够及时采纳早期的意见,并在继续写作的过程中做出反应。最终的审阅仍然很有帮助,因为增量审阅者很容易失去对整本书的整体理解——事实上,当我深入研究写作时,我也很容易失去这种理解。让新鲜的眼睛审阅整个作品可以产生很大的影响。

完成校对(2018 年 7 月 25 日) 

我刚刚完成了对重构的校对审阅。在这个阶段,我完美无瑕的散文会被发送给某人,他们会检查它是否像我想象的那么精彩,并反馈一个更正列表。在我的情况下,这是一个相当长的列表。

作者对校对过程的反应各不相同。有些作者如果他们完美无瑕的文本中改变了一个字符,就会勃然大怒。其他作者则对稿件感到厌烦,所以他们会接受所有的修改。我倾向于后者,但仍然会审阅每一个修改——主要是为了确保校对者没有无意中改变文本的含义,对于这样一本技术书籍来说,这是一个真正的危险。

我发现这个审阅既有趣又令人沮丧。令人沮丧的是,到目前为止,我已经完成了文本的写作,不想再读一遍了。许多校对对我来说似乎很随意——改变一些标点符号或措辞,在我看来,这些改变并没有什么实质性的区别。例如,我从来没有真正理解分号的意义,所以几乎从不使用它们。但像这样的校对修改是为了读者,而不是为了我。Dmitry Kirsanov,我现在的校对者,说:“校对(当它不仅仅是纠正语法错误时)是一个关于语调的问题。作者并不总是能听到自己的语调,就像我们不能正确地听到自己的声音,并且经常对在录音中听到自己的声音感到惊讶(通常是不愉快的)。”

作者对校对者的反应各不相同,但不同的校对者也做着不同的工作。我感谢我合作过的第一个像样的校对者,因为她认为,她必须尽可能地保留作者的风格。我对她的工作的主要记忆是添加了很多逗号——不出所料,我不会在没有必要的情况下添加逗号。遗憾的是,我不能让她为我的书工作,因为她是英国人,而美国出版商认为英国人不可能按照美国标准进行校对。Dmitry 已经为我的最后两本书担任校对者,我也很享受他的工作。虽然他的许多修改让我耸耸肩,但其中许多对我的措辞进行了明显的改进(包括这句话中的一个)。有时,他会加入一个听起来比我更像我的修改,这既令人毛骨悚然,又令人惊叹。

我遇到过一些校对者,他们强调他们正在修改文本以使其“正确”,这种态度确实让我翻白眼。毕竟,“正确英语”的许多规则都是 19 世纪的约定,是为了区分受过良好教育的上层阶级人士和像我这样的平民。(例如,分隔动词不定式规则仅仅是为了模仿拉丁语。)

在一些情况下,我看到一个校对者校对了一个已经被另一个校对者校对过的文本,最终做出的修改与他们对未校对文本做出的修改一样多。(让我感到沾沾自喜。)

这个网站没有经过校对——你看到的是我的原始文本。我还没有看到很多关于它的抱怨,所以我很高兴能够省去校对阶段的麻烦。

修剪印刷版(2018 年 8 月 7 日) 

在我对第二版进行的所有修改中,也许最显著的一项是,我将其写成了一本以网络为首的书籍。我的意思是,这本书的规范表示形式是存在于网站上的,它优先于其他表示形式,例如印刷在纸上的表示形式。Pearson 正在进行设置,以便当你获得一本实体书时,你可以将其注册到 Pearson,并获得访问该书的网络版本的权限。作为这本书的次要表示形式,纸质版将包含较少的内容。此外,我希望将来在该书的网络版本中添加更多内容,当然,纸质版无法更新。

几周前,我不得不做出一个决定,哪些内容会出现在纸质书中,哪些内容只会在网络版中出现。我给自己设定的一个限制是,这本书的第二版不会比之前的版本更大。(这也是我在《UML精粹》中给自己设定的一个规则。)我之所以这样做,是因为我发现第二版有膨胀的危险。我能理解为什么——毕竟作者对一个主题了解得更多,想要把所有新东西都放进去——但更大的书并不一定就是更好的书。由于《重构》采用的是双重形式,而且主要是一个参考目录,所以增加尺寸不应该是大问题,但我仍然不信任一本厚重的实体书——所以我保留了这个限制。

第一版有 412 页(不包括参考文献和索引),所以我把它作为我的目标。我们做了一个初步的页面校对,新书有 440 页,所以我需要至少删减 28 页才能达到我给自己设定的限制。当我开始想办法在哪里删减时,我非常担心这个选择,但我很高兴地说,结果比我预想的要容易。

新书中有 63 个重构,我将它们分为两个优先级。然后,我拿出了优先级较低的重构,寻找那些在书中其他地方没有被引用的重构。这样就确定了 5 个重构,共 19 页——我可以很容易地从印刷版中删除它们。当然,我还有另外 9 页要删减。我可以删除更多重构,但我把目光放在了一个占了 10 页的例子上。这是“拆分阶段”重构的第二个例子,一个很好的例子,但并不是严格必要的,因为我已经有一个例子了。此外,这个第二个例子是我在 Java 中早期做的,而且不想用 JavaScript 重写。它将是印刷版中唯一的 Java 例子,所以删除它就相当于删除了一些看起来很奇怪的东西。

我们用这些删减内容重新构建了这本书,结果是 410 页。所以,虽然算术没有完全正确,但我还是在我的限制范围内。(我还应该重申:这五个重构将对所有书的拥有者开放,你只需要去网站上查看它们,而不是在纸上查看它们。)

我知道一些读者可能想知道,这五个被删减的重构是什么?我以后会点名——到目前为止,我还没有谈论第二版中有哪些重构,也没有谈论第一版中所有重构的命运。我会在以后的备忘录中谈到这些。

过去的两周非常忙碌,因为我不得不忙着完成一些与书籍制作相关的任务。我原本希望很快就可以结束这本书的工作,但现在我接受了这样一个事实,还有很多工作要做,部分是为了准备网络版。我将在以后的备忘录中详细谈论这些。

排版印刷版 (2018 年 8 月 24 日) 

在过去的两周里,我在重构书籍上的工作主要集中在整理印刷版的各种松散的结尾。现在我们已经到了制作工作交到 Alina Kirsanova 手中的阶段,她负责整理书籍的排版,以及校对。排版书籍意味着要关注每一页的外观,并且在分页方面会出现各种问题。

我在写作的时候,不太担心分页符。我最近发布的大部分文章都在网上,所以我不用考虑实体页面。但对于一本书来说,实体页面很重要。代码示例就是一个典型的例子。我不想在代码示例中出现错误的分页符,理想情况下,我希望我精心编写的函数不会跨页。所以 Alina 会查看每一页,确保分页符出现在正确的位置。为了支持这一点,我需要调整我的代码示例自动导入功能,以便她可以在需要的时候插入分页符。

行长也是她关注的另一个方面。当我查看我的源文件时,现在看到了新的 XML 标签:例如 <dk:nobr>clarity</dk:no-br>,用于指示我们不想拆分成两行的文本。这是使用 XML 而不是 Markdown 作为我的源文本的优势之一——Alina 可以很容易地为我的工具链可以传递给她的文本添加新的标记。

我还准备了参考页面:填写了参考文献,并为内封面生成了重构列表和代码异味表。接下来,我需要查看页面的最终校对稿,并处理 Alina 提出的关于排版的一些问题。许多作者更喜欢交出他们的手稿,然后就置之不理——我目前非常同情这种做法。但参与其中的一个好处是,我可以欣赏书籍排版的细致工作。

Safari 上的粗略版本 (2018 年 8 月 29 日) 

订阅了 Safari 在线书籍服务的人现在可以获得 第二版的粗略版本。这个版本已经过校对,但还没有校对或最终排版。

大多数人会对第二版感到失望 (2018 年 8 月 30 日) 

当我快要发布一本新书的时候,我的感觉通常是兴奋和恐惧的混合。兴奋是因为我正在向世界发布我花了几个月甚至几年时间创作的东西,我想看看人们对它的反应。恐惧是因为我正在向世界发布我花了几个月甚至几年时间创作的东西,我担心人们对它的反应。人们会喜欢它吗?所有这些努力都是值得的吗?

对于这本第二版,我的感觉更多的是接受大多数人会感到失望。

这并不是说我认为我没有在这里做好工作。就像我所有的写作项目一样,我在这本书上投入了大量的精力和时间。我认为结果是对我最自豪的写作作品的一次值得的更新。但即使是这样,我也预计这本书会收到负面评价。这是因为熟悉第一版的人会自然地将它与第一版进行比较,大多数人会发现新版不尽如人意——尽管我认为我已经改进了它。

人们熟悉第一版,已经习惯了它的缺陷,并且喜欢我决定改变的原始版本中的元素。我们知道,损失厌恶意味着人们对失去某件事的感觉是获得同等价值的东西的两倍。因此,新版中的任何改进都必须比任何感知到的缺陷好两倍,才能让我不亏——这是一个很难达成的目标。

除此之外,许多人不会将这本第二版与第一版进行比较,他们会将它与他们想象中想要在第二版中看到的东西进行比较。通常这些想象并不现实——我有很多想法,在我脑海中听起来很好,但当我试图写下来的时候却行不通。即使坚持现实的想法,也有很多。最终,我必须选择一条道路,即使我选择了最受欢迎的道路,它们也会有很大的分歧,以至于它仍然只会符合一小部分人的意见。

(我怀疑我在这里的感觉是其他作者共有的,这可能解释了为什么这么多作者在修订版或多卷作品的后续部分中挣扎。)

既然这种失望是不可避免的,为什么我还要费心做第二版?(在过去的几年里,我无数次问过自己这个问题。)答案是,对这本新版的真正判断不是它发布后的几个月内人们的直接反应。而是它是否在五年、十年、二十年后帮助人们了解重构。这本第二版的目标读者中,大多数人甚至不知道这本书,许多人还没有写过程序,大多数人永远不会关心第一版。对这些读者的影响是衡量这项努力是否值得的标准。遗憾的是,我需要很多年才能评估我过去几年努力工作的价值。

送去印刷 (2018 年 9 月 28 日) 

第二版的文件今天已经送去印刷厂了。这完成了我们制作印刷版所需的所有工作。再次感谢 Alina Kirsanova,她负责排版这本书,进行了校对(发现了一些特别令人尴尬的错误),并制作了索引。Pearson 的 Julie Nahil 担任本书的制作编辑,协调了所有这些制作工作。

我们预计印刷版书籍将在 10 月底或 11 月初出现在 Pearson 的仓库中。它们应该很快就会进入零售渠道。

但网络版可能出现一个小问题。我们不想在网络版整理好之前就发布印刷版,而我没有像我希望的那样有时间来整理它。我休了两周的假(在康沃尔徒步旅行,在伦敦看了一些戏剧,和朋友们玩游戏,还吃了一些令人愉快的奢侈食物),现在在接下来的两周里,我还要参加一些商务旅行。我现在已经将网络版管道的绝大部分元素整理好了,但要到 10 月中旬才能开始正式工作。希望它不会花太长时间就能完成,但因为我以前没有做过,所以我不知道会发生什么问题。除了它是软件,我们都知道软件是多么容易预测!

制作网络版 (2018 年 10 月 20 日) 

在我上一次更新中,几周前,我提到这本书已经送去印刷厂了,我想他们现在正在忙碌地印刷。从那时起,我对这本书的首要任务是完成网络版。虽然所有的写作工作都完成了,但我仍然需要准备文件并进行排版。我不能马上开始,因为我有一些 Thoughtworks 会议要参加:在亚特兰大决定下一个雷达,以及在北京举行的一次全球管理会议。

但本周我回到了我的办公桌前,能够再次开始工作。第一个任务是了解网络版是如何发布的。Pearson 有一个网络书籍查看器,它基本上会获取一个 epub 文件夹,并通过一个简单的网络应用程序进行投影。这样做的好处是,这本书的大部分内容只是网页,而我熟悉生成网页(事实上,这正是我在写作的大部分时间里查看这本书的方式)。但是,我确实需要整理一些必要的东西,包括生成适当的 epub 清单文件,以及修复在网页环境中有效但不在 epub 环境中有效的 html。

一旦基本框架到位,我需要应用正确的 css,例如确保删除的代码用删除线正确标记,生成目录和重构列表。有一些有趣的复杂情况,比如发现我用来突出显示代码的 span 类名被查看器用于其他用途。

但现在我离完成已经很近了(我的 org mode 检查列表显示 9/13 个任务已完成),所以我很高兴网络版将在下周我从多伦多的“范式转变”会议回来后不久完成。这意味着我们将在印刷版从印刷厂回来后不久开始销售实体书。

然而,我还没有完成。下一个任务是重新制作 refactoring.com,特别是目录,用新的重构更新它。我还想列出网络版中包含但在印刷版中没有的内容。

(我通常不喜欢说“快完成了”之类的话,但我已经有一段时间没有写进度笔记了,我觉得我应该给大家一个更新。)

书籍已印刷 (2018 年 11 月 19 日) 

关于本书最新进展的简要更新。书籍已经印刷完毕,正在运往皮尔森的仓库。我已经完成了网络版的相关文件,但需要在皮尔森的基础设施上进行测试。完成测试后,我们就可以发布书籍供大家购买。我们希望在下周初在 InformIT(皮尔森的网站)上发布。亚马逊应该紧随其后。感恩节可能会造成一些延误,所有那些火鸡会堵塞供应链。但我会在了解更多信息后通知大家。

已在 informit 上发布(2018 年 11 月 26 日) 

感恩节期间,重构在 informit 上发布。您现在可以直接在那里订购实体书和电子书。实体书正在运往亚马逊,预计在一周左右开始配送。亚马逊的 Kindle 版应该会在那个时候出现。其他书商应该很快收到他们的副本。书籍应该会逐渐流向国际卖家,但我无法确定这需要多长时间。

最新备忘录:与书籍面对面

2018 年 12 月 10 日

face to face picture

过去几周我一直都在欧洲,所以错过了重构送到家里的日子。现在我回来了,终于可以亲眼看到真正的书籍了。即使在做了这么多年的作者之后,看到实体书仍然让我兴奋不已。

这本书最让我印象深刻的一点是它与第一版相比了很多,

photo of first and second edition spines

这并不是因为页数大幅减少(新版是 416 页,而旧版是 430 页),而是因为纸张更薄。当我打开它时,我发现它竟然是彩色的。这当然不是什么惊喜,但仍然很引人注目,因为这是我的第一本彩色印刷的书籍。这对这本书来说尤其有用,因为它可以让我更好地突出重构过程中发生的更改。