代码重构的艺术

来源:互联网 发布:开淘宝店 编辑:程序博客网 时间:2024/06/06 01:43

最近在看一些软件工程和构建方面的书籍。俗话说,书读百遍,其义自见,看得多了,自然也就有一些知识可以拿得出手分享一二了。

由于我在写代码的过程中往往很追求代码的优雅和简洁,因此我着重阅读了代码重构方面的知识,现在对代码的重构也算略有体会了。接下来我将结合我所吸收到的知识与我自己的一些理解和观点来阐述一下代码重构的艺术。


先来说说代码重构是什么吧。

重构一般是指把代码优化,便于再修改和开发的一种过程。重构并不是说,我把原来的代码全部推翻,重改架构,不是的,那叫重写,不叫重构。重构更像是装修,重写是推倒重盖,不知道这样解释是不是比较形象了呢?

那我们为什么需要重构呢?

一般的底层码农编程理念不够扎实,加上,分工合作的原因,总会写出一些烂代码,难以修改,这才需要进行重构。

我要着重提出的是:重构不是万能的,更不是用来装逼的!接下来我想解释一下在什么时候我们才需要进行重构,以及重构究竟是为了做什么的。

因为我看到网上总是有很多人标榜我重构代码几千行改到几行之类的,我觉得那是噱头,为了装逼而装逼的。重构的首要宗旨并不是为了简化代码的,重构的本质是为了清除烂代码的,只是在代码层面做修改,并不触动架构。也就是说,你原来的架构就很烂的话,重构并不会有所改善重构以后,代码效率并不会比原来过程型的代码快,甚至更慢。

那么对于需要重构的代码,我们该如何进行重构呢?

重构最简单的思路一般有两个:分,合。

分指的是把现有的业务逻辑简化,并不是实际简化,而是从代码结构上简化比如我一个功能需要1000行代码,干的10个事情,现在我把这10个事情都分出去,做成10个模块,然后做一个封装,这样,最上层的代码量就急剧减少了,逻辑也变的简单了。但是这不是随便分的,一般一个基础的底层处理的模块,一个模块只做一件事。什么是底层处理模块,比如分割字符串这个功能,就是底层模块,可以让任意模块调用,而且比较简单,这就是基础底层模块的要求。由于把一些公共的模块分离了,代码中直接调用这些模块,简化了代码,也减少了代码量。一般来说,代码如果超过一屏,就考虑尽量分离模块了。

一般说来,重构都是基于面向对象框架下的。因为一般过程型的代码,优化比较麻烦,不是面向对象的,分解起来会比较麻烦。一般来说,分层分的越细,结构越明晰,但是代码效率越差,因为继承封装可能比较多的缘故,所以一般要做一个平衡。公共调用的模块或者类,使用比较多的模块,一定要分出来。

举个例子吧,比如我要写一个自定义的格式化时间的函数,能够把一系列的时间函数,能用到的集合在一个类里。比如格式化时间函数,比如计算时间差的函数,如果就是孤单的一个函数,可以放到一个基类里。我觉得最好所有的函数最好都封装在类中,一个没有单独函数的框架,重用性一般能大大提高。基于类的好处,是可以轻易定位函数所在的位置,一般类名和文件名是需要保持一致的,看到类的前缀,就可以定位到类的名称和文件,但是如果是单独的函数,定位起来就比较麻烦。

重构的好处和意义,就是帮助程序拥有一套良好的规范。我们都知道,一个好的框架,需要有公共函数,还需要有私有函数,不然容易产生函数名重复等种种问题。一直执行一套良好的规范的程序,一定是比较容易维护和比较容易看懂的。不遵守规范,即使重构,难度也比较大,一些质量相当差的代码甚至没有改的价值,重构纯属浪费时间,所以重构前,需要判断,代码用不用重构,太差的话不如重写了。

极限编程流派中有一个观点,就是代码质量不重要,开发速度最重要。我也觉得这样是有道理的,因为先做出成果再debug给我们的正向激励是大得多的。并且就我现在所处的学校环境来说,同学们写出来的代码还不至于会发生差到只能重写如此这般的惨剧,有一些代码甚至还十分的巧妙和效率。但是经过我上网浏览到的一些奇葩段子,我才发现,原来世界这么大。

说有一个程序员用一天的时间写了一个刷单程序,需要展示出需要刷单的列表。这个程序并不复杂,但不知道为什么,执行起来特别慢,一个页面需要几十秒甚至刷新不出来
然后贴出了他的代码。我看了下代码,这个程序一次刷新就需要嵌套查询数据库上万次!一个列表查询上万次!列表要显示需要刷单的人信息,需要显示已经已经接单的人信息,有一些附加信息吧,结果,刷单的表没有冗余,需要关联用户表,他都是嵌套查询,所以刷单列表里嵌套查询用户信息,用户等级又是一个表,所以用户信息里嵌套查询等级名称,这样几十种数据嵌套来嵌套去,居然一个页面查询上万次!

高尔基曾经说过:好程序的优点大致相同,烂程序的缺点也大致相同。(不他并没有这么说过【捂脸】)比如:

1.不断重复的代码。

举个例子,对数据库的CURD操作,纯过程代码,如果没有分离出模块来,那每调用一次就需要再写一次相同的代码。而这还不是最关键的。我改了一处的代码,势必要改另外所有地方的代码,因为逻辑一致啊。但是分离出去模块后,改一处就可以了,减少了工作量,代码量也减少了。

2.人为的刻意复杂

很多人爱秀技术爱装逼,把一个逻辑搞的特别复杂。我继续拿添加商品的逻辑做例子吧。添加商品,需要添加id,需要添加搜索条件,需要同步更新缓存,需要生成页面,把这一堆逻辑写到一个页面里,成百上千行代码,怕不怕?尤其是多层嵌套的if else,嵌套上三层五层,估计看着就晕。

再说一个段子吧:有个程序员看到一段代码,大骂起来,这是哪个傻逼写的代码啊,这么乱啊!回头仔细看了下,是自己写的。

有的时候这确实是个真命题:你写的代码你不一定能看的懂。

对于如何针对嵌套,如if else之类的,去优化代码结构,,我自己是这么做的:单层的if else,直接写就可以,短逻辑直接用三元表达式(a?b:c),而不是if。长一点的简单逻辑,直接用数组表示。再复杂一点的,用switch语句,至于更复杂的,可以利用函数或者设计模式的方式解决。总的来说,嵌套一般不超出2层,一旦超出,就必须引入其他解决方式。要养成“看到if就不舒服的病”。
分的模块多了,有的时候怕也是不好找,所以必须要让每个模块名称都是望文知意。必须要养成英文单词的驼峰式命名或者其他统一的命名规范,绝对不可以用拼音或者是简拼。还是举刚才的例子。zdydgshsj(),鬼才看得出来这是什么函数;zidingyidegeshishijianhanshu(),就算你看的懂,但你多次调用这个函数不觉得手抽筋么?customFormatTime()相对来说看到就会明白意思了,或者是customizeFormatTime()更正规些,函数写多了后,my_FormatTime()更有利于归类些。但是不管怎么样,总算能看明白含义。如果你还是嫌函数名过长的话,可以使用部分通用的英文缩写。比如表单相关的,frm可以作为前缀;数据库相关的,db可以做前缀;文件相关的,file可以做前缀。这样整体看起来就更美观和易用了。

但是重构也绝对不是一见到长代码就必须要拆了。如果是一片孤单的代码段,没有引用,没有公共模块,简单的一个逻辑,但是代码段比较长,就没有必要分了,因为它和别的模块,别的方法都没有交集,自然没有优化的必要了。
总的来说,重构的经验很多都来自于对编程的深入理解,理解越深,写的代码越优雅,执行的效率越高。


啊,头一次写长文干货,一口气写了这么多字,好鸡冻(≧▽≦)/

0 0
原创粉丝点击