V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
scarlex
V2EX  ›  程序员

重构代码一般从哪些方面入手?

  •  
  •   scarlex ·
    scarletsky · 2013-09-06 15:10:35 +08:00 · 5996 次点击
    这是一个创建于 3883 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近想重构以前的代码,但不知道应该从哪些方面入手。
    有木有人可以给点经验?
    35 条回复    1970-01-01 08:00:00 +08:00
    davepkxxx
        1
    davepkxxx  
       2013-09-06 15:21:24 +08:00
    模块化
    cxe2v
        2
    cxe2v  
       2013-09-06 15:42:26 +08:00
    从评估重构的代价入手
    flowerains
        3
    flowerains  
       2013-09-06 15:44:13 +08:00
    重构是世界上最恐怖的事情
    bengol
        4
    bengol  
       2013-09-06 15:51:00 +08:00 via Android
    profiling
    sethverlo
        5
    sethverlo  
       2013-09-06 15:52:28 +08:00
    没人说要从先补完测试入手么…………
    davepkxxx
        6
    davepkxxx  
       2013-09-06 15:53:58 +08:00
    @sethverlo 补完测试就没时间重构了
    sethverlo
        7
    sethverlo  
       2013-09-06 15:57:42 +08:00
    @davepkxxx 最近才觉得测试其实挺重要的,特别是对于重构来说
    davepkxxx
        8
    davepkxxx  
       2013-09-06 16:05:18 +08:00
    @sethverlo 重构完毕之后再测试,因为重构的时候代码结构都是不稳定的。
    scarlex
        9
    scarlex  
    OP
       2013-09-06 16:32:28 +08:00
    @davepkxxx 模块化一直都有,只是觉得添加新功能的话,旧代码会变得比较那啥。
    @cxe2v 目前项目不算太大,就是想重构一下某些功能的代码,让那些代码变得更加灵活。
    @sethverlo 做完功能基本都会写测试。
    wangccddaa
        10
    wangccddaa  
       2013-09-06 16:43:22 +08:00   ❤️ 4
    最近一直在做这块的事,我来谈谈自己的体会
    1 首先要了解整个系统的结构
    如果在不了解系统的大体的结构情况下做重构,这个相信意义是不大的。
    2 为什么要重构?
    是系统的效率太低?还是代码有大量的重复,模块间的耦合严重,甚至类间的关系依赖性太强?找出病因才好对症下药,重构需要有针对性。
    3 合理的重构计划
    一个小的APP可能很好重构,但是当有一个有几万源代码的系统中全部做重构是不明智的,可以分阶段,按功能模块逐个做重构,要不然时间跨度太大容易导致身心疲惫。
    4 重构中的一些体会
    兼容:兼容以前旧的数据,这个对于web 程序来说还好点,对于客户端来说就比较麻烦了,当一个新的版本发出的时候,并不是所有的用户都很乐意升级的,一旦旧的版本的程序crash 很多用户可能就不再使用你的产品了。
    扩展:如果这一块做不好,下一个程序员在使用你新设计的模块时候还得继续重构,重构的意义也不大,一方可以展望未来可能有的功能,预留好接口,另一方面是:抽象。

    UI和业务逻辑的分离:在系统版本稳定后发现很多时候我们是在修改UI ,业务逻辑修改的一般不是很多。MVC 这个设计模式还是还有道理,view 和Control 尽量分开。

    大量重复的代码:我们可能发现很多时候一个功能有很多分支,只是有稍微一点差异,可能就要写两个函数来区分下,但是两个函数中可能大部分代码是一样的。我们可以把相同的代码抽取出来成为一个子函数。
    还有一个场景是这样的:有时候程序的行为需要变动下,但是处理这个行为的类都是在各个Class 中处理的,这样我们就需要做个找出执行这个行为的函数,并修改,很麻烦,这个时候如果将这个行为抽象出来,由统一的一个Class来管理是不是更好。

    使用宏,枚举等:很多时候我们的程序中出现很多的数字,比如0,1 ,199 ,1024? 其他程序员第一眼看到一般都不知道什么意思,即使通读一遍程序后也很可能和原作者理解的产生偏差,这种情况下使用宏来说在合适不过了。特别是在多出使用这个数字或者 string 的时候。

    设计模式:我认为她给出解决我们经常遇到一些问题的方法,但是为了使用设计模式才进行重构的话有点勉强。

    本人新手,仅个人拙见,轻拍。
    scarlex
        11
    scarlex  
    OP
       2013-09-06 16:53:17 +08:00
    @wangccddaa 感谢你的经验 :-D
    darasion
        12
    darasion  
       2013-09-06 22:49:20 +08:00   ❤️ 1
    先清理垃圾,删除历史遗留并且无用的东西。
    然后再看代码结构,就清晰了。
    nil
        13
    nil  
       2013-09-06 22:55:37 +08:00   ❤️ 1
    两个动机:
    convention,代码风格上的,重构受强迫症折磨;
    新需求,调整一下代码结构方便添加,修改功能。
    另外,测试,步步为营很重要
    ldehai
        14
    ldehai  
       2013-09-07 00:43:53 +08:00   ❤️ 1
    先检看的不顺眼的搞起来。每次重构只改动一个问题,然后测试,通过后继续找下一个。
    dongbeta
        15
    dongbeta  
       2013-09-07 00:51:32 +08:00 via iPhone
    重构过很多个系统。

    简单来说,首先读懂原始代码,搞清楚人家那么做的理由,这个阶段要心怀敬意。

    然后进行代码清理和模块化,此时要忍住别添加东西。

    最后再按照模块逐个逐个替换,以系统稳定为先。

    替换完毕之后,就看你的新架构的扩展性了。
    dongbeta
        16
    dongbeta  
       2013-09-07 00:52:46 +08:00 via iPhone   ❤️ 1
    还有,重构期间,除非非常必要,否则不要对旧代码不要做改进类的改动。
    zhangdawei
        17
    zhangdawei  
       2013-09-07 13:03:02 +08:00
    曾试图重构c语言嵌入式系统的部分功能,发现太难入手,好说难做。
    最后顺其自然不管了。
    banxi1988
        18
    banxi1988  
       2013-09-07 13:08:06 +08:00   ❤️ 1
    怎么没有人推荐这本书:
    重构:改善代码的既有设计
    Mutoo
        19
    Mutoo  
       2013-09-07 13:47:24 +08:00
    “@scarlex:做完功能基本都会写测试。"

    噗,看到这句我就笑了……所有的TDD的书里都有句话叫“测试先行”
    feuvan
        20
    feuvan  
       2013-09-07 15:24:51 +08:00   ❤️ 1
    重构很多时候就是上套新代码用新bug代替旧bug
    慎重考虑重构。
    Akagi201
        21
    Akagi201  
       2013-09-08 09:32:48 +08:00
    @dongbeta 有同感, 想把相同功能移植过来, 测试ok了, 再添加和改进
    zhanglongyang
        22
    zhanglongyang  
       2013-09-08 09:44:01 +08:00 via iPhone   ❤️ 1
    我们最近一周都在做重构,我们面临的问题是由于耦合度太高导致在现有代码基础上无法有效添加某个新功能,我们的思路是通过这个新功能的需求为驱动去解耦。一个比较重要的体会是:重构过程中要不断设定比较具体的目标。
    venson999
        23
    venson999  
       2013-09-08 22:25:35 +08:00   ❤️ 1
    任何没有测试的重构都是瞎改!
    Ricepig
        24
    Ricepig  
       2013-09-09 05:04:33 +08:00
    @Mutoo 然后需要“测试的测试”先行,然后再是“测试的测试的测试”更先行,然后子子孙孙无穷溃也
    Mutoo
        25
    Mutoo  
       2013-09-09 08:57:04 +08:00
    @Ricepig 你这个观点和“一尺之竿,日取其半,万世不竭”一样没有什么意义,TDD只是让程序变得比没有测试更靠谱,比测试后行更优美而已。这样就够了。

    按你的观点,TCP三次握手可以引伸出无限握手,然后推导出网络传输一点都不靠谱的结论;
    vietor
        26
    vietor  
       2013-09-09 09:02:36 +08:00   ❤️ 1
    重构代码,有可能费力不讨好,换一批人,又会觉得以前写的是SHI。

    依据我的经验,都是“方法”替换,逐步“向上推进”的,绝对不能“大删大改”。步骤谈一下:
    1)找出,没有被调用过的方法,删掉。
    2)找出,C-c C-v明显的代码,合并到一个方法中。
    3)将功能相近的函数,封装到一个“新类”中,逐步替换“旧类”的引用,直至最后删除。

    当然,根据使用语言的不同,还有一些不同的细节:
    1) C#这些能够在一个文件中存放多个类的语言,我可能将一个整体功能放入一个文件,文件可能很长。有人批评过我的做法,但它有一个好处就是让“功能”更加“集中”和“独立”。对于这种“模块”是有选择要求的:“足够独立”,比如一个HTTP服务器模块。
    2)如果可能,还是采用“显而易见”的语言特征。如,在避免在C++中使用lumbda;C#能够用callback表达的,就不要用Event。
    Ricepig
        27
    Ricepig  
       2013-09-09 16:39:11 +08:00
    @Mutoo 哈哈,开个玩笑。不过,TCP的三次握手是保证在“绝大多数”情况下网络靠谱,如果要严格说起来,网络传输确实一点儿都不靠谱呢。哈哈
    winnie2012
        28
    winnie2012  
       2013-09-09 16:45:31 +08:00   ❤️ 1
    弄一本《重构》看看就OK了,一般是指坏味道
    wenjixin
        29
    wenjixin  
       2013-09-09 17:23:05 +08:00
    不要重构
    egen
        30
    egen  
       2013-09-10 00:11:21 +08:00
    不要因为看代码不顺眼而重构
    luikore
        31
    luikore  
       2013-09-10 00:58:04 +08:00   ❤️ 1
    不管是升级依赖的库版本, 还是重构, 或者优化, 先要有测试, 有了测试怎么玩都可以. tdd 更容易保证测试和实现是两套不同的 mind set (测试是用户视角, 实现是程序逻辑视角), 以及实现不冗余. 但就算是测试后行, 也胜过没有测试.

    如果说没时间写测试, 那只有两种可能:
    错误估计了需要花费的时间, 你的"重构"是能搞完, 但是之后还有一大堆 bug 等着修.
    或者是之前缺乏测试, 浪费在修 bug 上的时间已经太长了, 造成了恶性循环.

    测试容易落入的两个误区:
    1是有些语言(先天缺陷, 尤其是java, c#)和环境(设计模式粉的架构)很难搞自动化的功能测试和集成测试, 所以很多人只写点皮毛的单元测试了事 -- 这样的测试用处就很小了 -- 但就算很难写, 写出来以后就是沉淀在那里的价值了. 多数老公司还有很多专门的测试人员去手动做集成/验收测试, 那么你重构以后必须让测试人员去各种点一遍...
    2是测的东西体现了太多关于实现的知识, 不得不使用很多 mock 和 stub (多见于后行的测试). 测试时最好换位思考, 从使用者角度去想问题, 或者直接换个人写测试.
    sivacohan
        32
    sivacohan  
       2013-09-13 10:58:36 +08:00   ❤️ 1
    @vietor 有些时候还会把一些函数展开成C-c C-v 目的是减少依赖的复杂度。
    hunter
        33
    hunter  
       2013-09-13 15:58:28 +08:00   ❤️ 1
    熟悉整个业务流程,抽象出来模块交互行为,订立接口规范,评估现在的代码和目标代码间的差距,估算出来时间。开始重构。。。
    williamx
        34
    williamx  
       2013-09-13 16:12:19 +08:00   ❤️ 1
    从合并代码,修改变量的名字,提取函数开始。
    pipi32167
        35
    pipi32167  
       2013-09-14 13:30:26 +08:00   ❤️ 1
    不写测试的结果就是作死。。。你知道的,不作死就不会死。。。

    补测试,模块化重构。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3334 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 00:05 · PVG 08:05 · LAX 17:05 · JFK 20:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.