当前位置: 首页 > 科技观察

说说重构3000行代码变成15行代码

时间:2023-03-19 00:09:24 科技观察

如果你觉得这是个头条,那我恳请你耐心看完文章的前半部分,然后得出结论。如果你觉得可以戳到你的G点,请点个赞。当我将3000行代码重构为15行代码时,我刚毕业,就加入了现在的公司。公司是做数据中心环境监控的,里面充斥着嵌入式、精密空调、总线、RFID等概念,我一个都不懂。还好公司用Delphi写老客户端,因为太慢了,后来想出了一个Webform的替代品。恰好我对Asp.Net很了解,我对业务的无知并不妨碍我被称为公司的程序员。也有适合小公司的小公司。人少,进去不久就负责代码开发。当然,我也会搞这个数据中心智能管理系统。这个系统非常庞大,最神奇的是它支持客户端配置,然后动态生成网页,可以通过Socket实时监控数据(那时候真的不懂网络编程)。对当时的我来说,这真的是高、大、高!!当时在了解了整个系统半个多月后,已经可以调试写一些简单的页面了。在维护系统的过程中,时不时需要扩展一些功能,于是接触到了下面这个类:看看是不是当年最流行的三层架构的产物。对于初出茅庐的小白来说,这是多么专业的文件头注释,和反思。这个构造函数可以是静态的还是私有的?第一次接触这么高大上的代码,瞬间跪了!但是,我写的类太多了,感觉越来越别扭,就是下面的代码:每增加一个表,除了改变接口、DAL、BLL之外,还必须在工厂类中增加一个方法,我累得手都抽筋了。即使有当时公司的G工程师推荐给我的神器——东软代码生成器,几次粘贴复制也让我觉得无比繁琐,有时候敲键盘有点累。点,并改正复制的代码,你妹,这就是程序员该做的事吗,不,绝对不是!我想起了一句至理名言:当你觉得程序中的代码重复时,就应该重构。是的,在这句话的指引下,我开始折腾,决定挑战一下这个高大上的代码。事实证明,思想的力量是无穷的。那么,如何修改呢?仔细观察后发现className的生成和返回的类型非常相似,只是一个是类名,一个是字符串。两者应该是可以关联的。于是google了一下(当时GFW还没有横行),隐约找到了“反射”这个词。深入了解后,我确信可以完成。接下来,是回报的类型。返回的类型不固定,但是好像很有规律。。。好像在哪里看到过这个。顺便说一句,C++课程中提到了模板,所以我再次谷歌搜索,发现泛型在C#中使用,而不是在C++中使用模板。学习了泛型和反射,参考了网上的一些文章,摆弄了下面的代码:没错,就是它,三层架构时代最流行的工厂类。。。看原文滚动更多十几屏的代码变成了十多行代码,真是爽到骨子里,好干净!唯一让我担心的是,刚进公司的时候,帮公司申请软件著作权需要大量的代码。软件的大小是根据代码行数来评估的。也减少了,我会立即被解雇吗?我不敢向我们的老板展示我的优异成绩。好在这段代码不仅没有出现任何问题,还避免了同事在添加新类后总是复制代码,却没有修改正确的问题。大大提高了效率。虽然我不敢大张旗鼓地公布自己的劳动成果,但是这次成功的修改已经彻底把我引向了代码重构的不归路。看到这里,大家应该知道这个案子是不是真的了吧。相信2008年入行的coder们,见过这种类似的代码的不比我少。那么,我想告诉你什么呢?在编程的过程中多思考编程是非常重要的。请多看经典书籍,从小处着手,慢慢重构,尤其是在处理大型系统的时候。当重复出现时,你应该考虑重构。粘贴复制你的代码越少,你的系统就越稳定。下面分析一下前辈们为什么要写上面的代码。我总结了以下几点:因为我用的是动态代码生成器,生成代码方便,所以也没多想。三层架构的概念理解了,但是没有深入思考就拿来应用。遇到重复的代码,就没有重构的概念。这是思想的问题——思想比能力更重要。直到现在,还有很多人在使用它。代码生成器,那么我们应该如何对待这个问题呢?在我看来,代码生成器确实可以为您节省很多工作,但请谨慎使用。除了一些重复性的工作实在是没办法,其他大部分都可以通过框架解决。比如像三层架构,真正需要用到代码生成器的是Model类,其他的都可以在框架中完成。所以你要尽最大努力去思考如何减少你在框架中的重复性工作,而不是依赖代码生成器。另外,如果您还在使用相关的代码生成工具,请重新定义“东软代码生成器”的代码模板,自己写一个模板;或者使用CodeSmith完全开发自己的代码生成,因为东阮提供的代码模板真的很乱,比如下面的代码:for(intn=0;nGetDevices(stringdev){Listdevs=newList();intstart=0;for(inti=0;i0){varasmCache=newDictionary();foreach(varbundleinbundles){try{if(!asmCache.ContainsKey(bundle.Category))asmCache.Add(bundle.Category,Assembly.Load(bundle.AssemblyName));varhandler=(ITaskHandler)asmCache[bundle.Category].CreateInstance(bundle.ClassName),false,BindingFlags.Default,null,newobject[]{this,bundle},null,null);_taskHandlerBundles.Add(bundle,handler);}catch(Exceptione){NLogHelper.Instance.Error("加载bundle[Name:{0},Assembly:{1}:Class:{2}]异常:{3}",bundle.Name,bundle.AssemblyName,bundle.ClassName,e.Message);}}}}修改MainEngine代码classMainEngine:IEngine{privateNewFuncClassnewnewCls=newNewFuncClass();publicMainEngine(ConfigSettingsconfig){RegisterTaskHandlerBundles();}publicvoidStart(){_taskHandlerBundles.Start();}publicvoidStop(){_taskHandlerBundles.Stop();}}OK,现在我们来看一下如何实现原来的新功能:只需要按照规范新建一个类,继承ITaskHandler接口,实现接口的方法即可。最后在XTGL_ServiceBundle表中添加一条新记录就可以了。我们再来看看这样做的好处:新增的类只需要按照规范编写即可,对MainEngine代码完全没有影响。您甚至可以在新的Dll中编写此MainEngine代码。新功能的业务类与原有代码解耦,非常方便新功能的业务测试,无需考虑对原有框架的影响。新功能的业务类与架构完全分离。我们只需要在改写代码的时候保证接口的稳定性,无论我们如何改写系统架构,都可以立即复用原有的业务功能代码。重构的目标之一就是将框架与业务完全分离。有兴趣深入了解的同学可以学习反射、Ioc和插件式编程。学习单元测试,培养重构意识。可能上面说了这么多,但是还是有很多人不懂重构。没关系,在这里我教大家一个快速入门的方法,就是单元测试。什么是单元测试,请自行google。单元测试的要求是什么?就是要求你尽可能让每个方法都可以测试。尝试使您的方法可测试是培养重构意识的有力工具。在让你的方法可测试的过程中,你会发现你要不断地修改你的方法,让它尽可能简单,尽可能上下文无关,尽可能传递方法参数的输入.输出可以完成相关功能,让依赖类尽量改为接口而不是实例。最后你会发现,这就是重构!而且在不知不觉中,你的重构能力会得到很大的提升,你的编程水平也会有很大的提高!看到这里,有经验的程序员会问,你是在鼓励我使用TDD吗?不它不是。TDD(测试驱动开发)鼓励测试驱动开发。单元测试用例代码是在开发之前编写的,测试代码决定了需要编写什么样的产品代码。这是一种比较高级的开发方式,但是在编程实践中,我觉得过于繁琐,很多中小企业都难以实施,更何况是我们个人开发者。在这里我提倡大家通过单元测试来培养自己的重构意识,可以说是一种后驱,用来提高自己的重构能力和重构欲望。你可以把我的方法称为“TDR(Test-DrivenRefactoring)——测试驱动重构”。当然,如果你在开发前有意识地让方法可测试,那么你写出的功能就会是比较优质的代码。当你的功能都是高复用的功能时,你会发现写代码其实就像搭积木一样,可以将一个大需求分解成无数个小功能,快速实现需求。下面是一个非常大的方法中的一段代码。如果您知道如何使这段代码成为可测试的方法,那么恭喜您,您已经开始了。所谓重构如果你有耐心看到这里,你应该知道我不是头条党,这篇文章可能叫《如何在编程中应用重构的思想》更合适,但我不想用这么严肃的标题。很多编程初学者,或者有多年编程经验的人,都觉得读懂别人的代码非常困难,而重构更是难上加难。他们要么对代码叹息,要么推翻它。但是,如果我们有重构的意识,熟悉编程过程中的一些代码调整和优化的技巧,重构的能力自然就会养成。重构其实很简单:打好基础,多看优秀的代码,避免复制粘贴。如果您看到重复代码,您应该有意识地消除它并减少您对代码生成器的依赖。处理现有代码时尽量使用重构而不是重构写,在重写之前,必须先重构,并尽量使所有方法都可测试。如果你坚持这样做,过一段时间就会感觉自然了。重构的目的是让你的代码更加精简、稳定、可复用,最大程度的分离功能和业务。在重构的过程中,你阅读代码的能力、写出优秀代码的能力、系统架构的能力都会稳步提升。你将成为一名优秀的程序员指日可待。