原文连接: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所有可能引用到的代码,不然就会产生很奇怪的函数调用,具体可以看这篇:关于虚函数那点破事。
做这种大型软件的重构,让我学到比较多的是:
- 面对一些大型的软件系统不会犯憷,会比较有自信。
- 养成自动化的习惯,一些大量的手工操作,会很枯燥,很费时,做的很容易出错而且没有成就感,但是把目标转换一下:写个程序把工作自动化,上面那些问题是不是都没了:)
相关推荐
经典软件重构 经典软件重构 经典软件重构 经典软件重构 经典软件重构
讲解软件重构的PPT,包含重构的代码,重构技术还是很重要的。
关于软件工程中的软件重构.pdf
自己整理的一个软件重构ppt,供大家参考!
王家林的软件重构最佳实践,史无前例的经典之作。
从C语言开发的角度讲述了软件重构的方法和原则,内容通俗易懂,例子精心挑选,入门学习软件重构的难得资料。
软件结构可以因为各种各样的原因而被改变,如进行打印美化、性能优化等等,但只有出于可理解性、可修改、可维护目的的改变才是软件重构(Refactoring)。
关键词:软件重构方法;软件维护;程序转换;行为保留;程序结构改善;基本重 构方法;复合重构方法;Java语言接口;面向方面范型;横切关注点;方面挖掘; 静态模型;动态模型;逆向软件工程;对象状态模型.
FPGA软件重构验证方法研究.pdf
西南科技大学软件设计模式与重构大作业-心算大师游戏(高分作业)
重构是以各种方式对设计进行重新安排使之更灵活并且/或者可重用的过程。效率和可维护性可能是进行重构最重要的理由。
重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt重构ppt
任何一个傻瓜都能写出计算机可以理解的程序,只有写出人类容易理解的程序才是优秀的程序员
重构重构重构重构重构重构重构重构重构重构
软件工程与软件重构.pptx
软件重构世界软件定义未来.docx软件重构世界软件定义未来.docx
软件重构思想 CMMI讲师PPT 软件重构v2
CT扫描三维重构软件说明书,叫你如何真确的使用CT扫描三维重构软件,一步到位非常简洁,你一定会喜欢的
本书凝聚了软件开发社区专家多年摸索而获得的宝贵经验,拥有不因时光流逝而磨灭的价值。今天,无论是重构本身,业界对重构的理解,还是开发工具对重构的支持力度,都与本书最初出版时不可同日而语,但书中所蕴涵的...
基于FPGA和DSP的星载软件动态重构设计.pdf