2.8 重构起源何处
我曾经努力想找出重构(refactoring)一词的真正起源,但最终失败了。优秀程序员肯定至少会花一些时间来清理自己的代码。这么做是因为,他们知道简洁的代码比杂乱无章的代码更容易修改,而且他们知道自己几乎无法一开始就写出简洁的代码。
重构不止如此。本书中我把重构看做整个软件开发过程的一个关键环节。最早认识重构重要性的两个人是Ward Cunningham和Kent Beck,他们早在20世纪80年代就开始使用Smalltalk,那是个特别适合重构的环境。Smalltalk是一个十分动态的环境,你可以很快写出极具功能的软件。Smalltalk的“编译/连结/执行”周期非常短,因此很容易快速修改代码。它支持面向对象,所以也能够提供强大的工具,最大限度地将修改的影响隐藏于定义良好的接口背后。Ward和Kent努力发展出一套适合这类环境的软件开发过程(如今,Kent把这种风格叫作极限编程[Beck,XP])。他们意识到:重构对于提高他们的生产力非常重要。从那时起他们就一直在工作中运用重构技术,在正式的软件项目中使用它,并不断精炼这个程序。
Ward和Kent的思想对Smalltalk社群产生了极大影响,重构概念也成为Smautalk文化中的一个重要元素。Smalltalk社群的另一位领袖是Ralph Johnson,伊利诺斯大学乌尔班纳分校教授,著名的GoF [Gang of Four]之一。Ralph最大的兴趣之一就是开发软件框架。他揭示了重构对于灵活高效框架的开发帮助。
Bill Opdyke是Ralph的博士研究生,对框架也很感兴趣。他看到了重构的潜在价值,并看到重构应用于Smalltalk之外的其他语言的可能性。他的技术背景是电话交换系统的开发。在这种系统中,大量的复杂情况与日俱增,而且非常难以修改。Bill的博士研究就是从工具构筑者的角度来看待重构。通过研究,Bill发现:在C++的框架开发项目中,重构很有用。他也研究了极有必要的“语义保持性(semantics- preserving)重构”及其证明方式,以及如何用工具实现重构。时至今日,Bill的博士论文[Opdyke]仍然是重构领域中最有价值、最丰硕的研究成果。此外他为本书撰写了第13章。
我还记得1992年OOPSLA大会上见到Bill的情景。我们坐在一间咖啡厅里,讨论当时我正为保健业务构筑的一个概念框架中的某些工作。Bill跟我谈起他的研究成果,我还记得自己当时的想法:“有趣,但并非真的那么重要。”唉,我完全错了。
John Brant和Don Roberts将重构中的“工具”构想发扬光大,开发了一个名为Refactoring Browser(重构浏览器)的Smalltalk重构工具。他们撰写了本书第14章,其中对重构工具做了更多介绍。
那么,我呢?我一直有清理代码的倾向,但从来没有想到这会如此重要。后来我和Kent一起做个项目,看到他使用重构手法,也看到重构对生产性能和产品质量带来的影响。这份体验让我相信:重构是一门非常重要的技术。但是,在重构的学习和推广过程中我遇到了挫折,因为我拿不出任何一本书给程序员看,也没有任何一位专家打算写出这样一本书。所以,在这些专家的帮助下,我写下了这本书。
优化一个薪资系统
——Rich Garzaniti
将C3系统移至GemStone之前,我们用了相当长的时间开发它。开发过程中我们无可避免地发现程序不够快,于是找了Jim Haungs(GemSmith中的一位好手),请他帮我们优化这个系统。
Jim先用一点时间让他的团队了解系统运作方式,然后以GemStone的ProfMonitor特性编写出一个性能度量工具,将它插入我们的功能测试中。这个工具可以显示系统产生的对象数量,以及这些对象的诞生点。
令我们吃惊的是:创建量最大的对象竟是字符串。其中最大的工作量则是反复产生12 000字节大小的字符串。这很特别,因为这些字符串实在太大,连GemStone惯用的垃圾回收设施都无法处理它。由于它是如此巨大,每当被创建出来,GemStone都会将它分页至磁盘上。也就是说,字符串的创建竟然用上了I/O子系统,而每次输出记录时都要产生这样的字符串三次!
我们的第一个解决办法是把一个12 000字节大小的字符串缓存起来,这能解决一大半问题。后来我们又加以修改,将它直接写入一个文件流,从而避免产生字符串。
解决了“巨大字符串”问题后,Jim的度量工具又发现了一些类似问题,只不过字符串稍微小一些:800字节、500字节,等等,我们也都对它们改用文件流,于是问题都解决了。
使用这些技术,我们稳步提高了系统性能。开发过程中原本似乎需要1 000小时以上才能完成的薪资计算,实际运作时只花40小时。一个月后,我们把时间缩短到18小时。正式投入运转时只花12小时。经过一年的运行和改善后,全部计算只需9小时。
我们的最大改进就是:将程序放在多处理器计算机上,以多线程方式运行。最初这个系统并非按照多线程思维来设计,但由于代码构造良好,所以我们只花了三天时间就让它同时运行在多个线程上。现在,薪资的计算只需2小时。
在Jim提供工具使我们得以在实际操作中度量系统性能之前,我们也猜测过问题所在。但如果只靠猜测,我们需要很长的时间才能试出真正的解法。真实的度量指出了一个完全不同的方向,并大大加快了我们的进度。
[1] 一种有名的麦芽酒。——译者注
[2] 数据库重构的经验也已经由Soctt Ambler等人总结成书,相关内容请参考《数据库重构》(http://www.douban.com/subject/1954438/)。——译者注
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。