原文连接:http://www.debuggingnow.com/blog/2009/12/some-thoughts-on-large-scaled-software-refactoring.html
做当前这个项目也快一年半了,回头看看,前一年时间是在做重构,而后一年时间则是在打造一个新的产品。这里稍微总结一下做重构时所学到的一些东西吧。
重构其实可以是不同目标的,有些人重构是为了让代码更合理,美观;而另一些人则可能是为了实现某个功能;重构也是有不同程度的,有的可能只是在函数、类级别做些修改,而有些则是要对整个的架构,模块做变动;同时重构的投入也是有很大不同的,有的只是在遇到不好的代码或设计的时候才进行修正,而有的则会专门组建一个团队花一大段时间来做重构。
对基本概念的精确定义是一切讨论的基础,我这里讨论的重构是"为了实现某个功能而专门进行的大规模的代码改动"。
架构设计,你能看的多远
简单一点来说,我们要做的,就是把一个软件的UI代码与核心功能彻底分开,然后把核心部分做成一个单独的产品。当然,这种所谓的表现层与业务层要分开的道理是谁都懂的,当初的架构里也的确加入了这些概念,但是由于没有严格要求,也从来不会把核心部分单独拿出来跑,经过近十年的开发,代码中核心层对UI的依赖已经相当严重,有静态的,源代码编译上的依赖,也有动态的,运行时的依赖。这个时候要抽取其核心功能,无疑是相当困难和费时的(代码量以百万行记)。看看现在网上的一些开源CAD软件,很多就是一开始就有明确的Core-UI划分,并且可以运行在核心模式或者UI模式。如FreeCAD。想想如果当年的架构师能够想到这一步,从一开始就明确划分,可以肯定的是:一、后期无需花费那么多人力物力;二、其质量,设计会好很多。
当然,这个其实也不一定是远见不够,一旦和商业利益结合起来考虑,很多好的设计是不得不被放弃的。举个例子,你的产品只是面向Windows用户的,而项目组里都是Windows程序员 - 为了更快更好的推出产品,你应该不会考虑跨平台吧 - 可是十年后,老大们决定向Mac进军了~~~所以说,这一块也是尽人事,听天命吧。
工作模式
一定要开出一个单独的branch来。这样你就可以关起门来"为所欲为"了,不会影响到其他team。这里为所欲为指的是:
因为是很大的code base,你的某处修改可能在另外一处导致编译错误,或者你用script做的修改面特别广,而在本机做一个完整的build可能要半天(对的,即使用了IncrediBuild),那就check-in之后让服务器帮忙去build,你可以继续工作了,有几个build error,没关系!
每次check-in之前,不用跑那些自动化测试之类的。
当然,这种自由在很多情况下是不提倡的,但在这里,却非常大的提高了效率。
另外,因为重构的改动量是非常大的,所以要经常的与main或者trunk branck进行sync,把单次变动控制在一个可以接受的范围内。
如何保证质量
上面讲到我们可以不跑自动化测试而check-in,那么如何保证质量呢。
首先,你一定要有自动化测试 - 基于代码的单元测试也好,基于script的功能测试也好,只要是自动化的,并且覆盖率足够那就ok了 - 在做重构,尤其是大规模重构的时候,没有自动化测试那简直就是找死。
因为我们是在自己的branch上工作,只要保证回到main/trunk的时候没有regression就可以了,中间是什么状态,我们要求不是很高。一般的做法是:
- 每周会跑一下smoketest和一些相关的acceptance test,防止一些重大问题。
- 每次和main/trunk sync之前,我们都会花大概4天左右的时间来做"automation triage" - 把所有的自动化测试的case都跑一遍,拿到report之后逐个分析 - 或者逐批分析,因为很多failure都是一样的。
这种做法极大的提高了效率 - 要知道,要把所有的case跑完,需要几十台服务器一起跑3天~~~
如何管理代码
重构涉及到很多文件的移动与分拆,需要注意两个地方:
一个文件是怎么一步步改动过来的是非常重要的信息 - 你可以方便的查到谁在什么时候改过这个文件,怎么改的。移动,或者分拆文件是非常容易因为疏忽而丢失历史的操作。一定要正确的使用SCM工具来保持此信息,比如perforce里就要用intergrate,而不是简单的add。
这里涉及到从branch到main的intergration,你在branch上把一个文件移动了并做了修改,而在main上同样有人做了修改,做intergration的时候,你很容易丢失别人在main上的修改,因为其对应关系并没有被建立起来,也就无从merge了。我想不同的SCM工具应该都提供了解决方案的,比如perforce就可以在其branch spec中来说明其对应关系。
重构的方法
工作期间拜读过《重构----改善既有代码的设计》,上面讲了许多不错的改善设计的方法与步骤,但是基本没用上。因为关于设计,我们对哪种情况,如何修改之前都已做了研究并有了方案,而那些步骤感觉稍显罗嗦,不是很适用。Visual Assist提供了个重构的模块,在一般规模的代码里用用还可以,但是对于有很多个solution的代码就无能为力了。况且这些只是涉及到源代码的重构,我们还有工程/DLL的重构。
我们采取的方法是:针对不同的情况,写perl脚本来自动化一些任务。举个简单点的例子:我修改了一个方法的名字,脚本就会搜索所有的代码,自动check-out需要修改的文件,并替换新名字。记得当时写了许多perl脚本来自动化对perforce的调用,VS的调用,对代码,工程文件的修改等等。
一些细节
- interface的使用
我们的重构工作对于接口可以说是无所不用其极,而正是大量的使用接口才让这种已经耦合很紧的代码的UI-核心的分离成为可能。比如某个核心层的操作完成之后是调用UI的刷新代码,而把这个刷新操作移到外面又是相当困难的,此时用接口就是比较好的做法:
pInterface->UpdateUI();
当然还有一些其他的使用接口的方式,但归根结底都是为了分离实现。
- 使用vsprops
我们用的是Visual Studio,上百个项目都有其各自的设置,而其实很多设置都是差不多的,完全可以把那些一致的设置放到一个vsprops文件中,让每个vcproj文件都引用它。能在很到程度上提高一致性与简洁度。MSDN有其详细的介绍。
- 虚函数与rebuild。添加,删除虚函数,尤其是基类里的虚函数都会破坏原有的虚表,因此除非rebuild所有可能引用到的代码,不然就会产生很奇怪的函数调用,具体可以看这篇:关于虚函数那点破事。
做这种大型软件的重构,让我学到比较多的是:
- 面对一些大型的软件系统不会犯憷,会比较有自信。
- 养成自动化的习惯,一些大量的手工操作,会很枯燥,很费时,做的很容易出错而且没有成就感,但是把目标转换一下:写个程序把工作自动化,上面那些问题是不是都没了:)
相关推荐
重构的一些想法 重构必须建立在良好的版本控制基础上;重构在多数情况下应该是个体工作;重构的时候必须保证测试的完全进行;重构需要良好的设备的配合;重构的过程应该有勇气放弃或者继续,而不能停在原地;重构...
- 《人月神话》提倡将大型软件项目分解为小的、可管理的模块,每个模块由一个或少数几个人负责,这样可以提高开发效率,减少错误,并方便后期的维护和扩展。 5. **项目管理策略** - 书中讨论了项目管理的各种策略...
- **模块化原则:** 将大型软件系统分解为较小的、独立的模块,每个模块负责实现单一的功能。 - **封装原则:** 模块内部的具体实现细节被隐藏起来,只对外暴露必要的接口。 - **信息隐藏原则:** 通过封装机制隐藏...
首先,Visual Studio (VS) 是微软提供的强大IDE,其中Resharper是一款非常受欢迎的插件,它可以增强VS的代码智能提示、重构和代码分析功能,显著提升开发效率。虽然它是付费软件,但其价值在很多开发者眼中远超价格...
- **增量式开发:**通过逐步添加功能模块的方式构建软件,适用于大型或复杂项目的开发。 - **原型化开发:**先建立一个简单的原型,然后根据用户反馈进行改进和完善。 #### 第2章 设计思维与创新 **设计思维概述:...
以下是一些关于这个主题的关键知识点: 1. **存储过程**:存储过程是预编译的SQL语句集合,它们被存储在数据库服务器中,可以视为数据库中的可执行对象。存储过程的主要优势在于提高了执行效率,因为它们只需要编译...
### 云计算软件架构详解 #### 一、云计算的变革力量 云计算,作为一种革新性的计算模型,正在彻底改变我们的设计、构建和提供应用程序的方式。它不仅提高了应用程序部署速度,促进了创新,降低了成本,还增强了...
**英文原版** 表明这本书是未经翻译的原始版本,这通常意味着读者可以接触到作者最原始的想法和表述,对于深入学习面向对象领域的专业人士来说是非常有价值的资源。 ### 部分内容解读 在提供的部分内容中,我们...
- **极限编程(XP)**:UP也可以整合来自其他敏捷方法学的最佳实践,如XP中的测试驱动开发(TDD)、重构和持续集成。 #### UML在项目中的应用示例 以骰子游戏为例,UML的应用步骤如下: 1. **定义用例**:首先...
然而,对于某些特定场景下的项目,如大型分布式团队、重构成本过高的应用等,则不适宜采用XP方法。 #### 四、XP的具体做法 XP的方法论主要包括以下几个方面: 1. **启动阶段**:客户与开发团队紧密合作,共同确定...
12. **代码规范与重构**:遵循编码规范以提高代码可读性,重构技术以改善代码结构。 通过深入研究"Ideas-master"中的内容,开发者不仅可以学习到Java编程的实用技巧,还能了解到项目管理、软件工程的最佳实践,这...
UML是由对象管理组织(OMG)发布的一种标准化建模语言,它不仅推动了面向对象技术的发展,还将其应用范围扩展到了业务流程重构等领域。 **1.1 什么是模型?** **1.1.1 模型是对现实世界的简化和抽象** 模型是指为了...
件中地位,下面是我自己的一些想法: 建筑和软件某些地方是可以来比喻的 特别是中国传统建筑,那是很讲模式的,这些都是传统文化使然,比如京剧 一招一式都有套路;中国画,也有套路,树应该怎么画 法?有几种画法?艺术大家...
重构是程序员的一项核心技能,它不仅能够帮助提高代码的质量,还能增强软件的可维护性和扩展性。重构涉及修改现有代码而不改变其外部行为的过程,通过这种方式可以改进代码结构、消除冗余并提高效率。 #### 2. 工作...
使用PlantUML的大型软件解决方案的体系结构建模 在不同图中具有与单个源实体相同的模型元素 根据常见的PlantUML描述模式创建arc42架构文档 保持架构描述接近源代码->架构作为文本 允许架构元素的模块化和松散耦合->...
4. **技术创新**:开源软件鼓励创新,新的技术和想法可以迅速融入到项目中,促进技术进步。 总结来说,JarIndexer 是一个利用 Apache Lucene 实现的 JAR 文件索引工具,它简化了在大量 JAR 文件中查找特定类或包的...
面向对象的系统更加灵活,可以适应变化的需求,尤其适合大型、复杂、且需求易变的系统。 - 结构化开发方法优势在于流程清晰,管理简单,对开发人员的要求较低,适合于那些需求相对稳定和明确的项目。结构化方法往往...