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