重写?重构?

今天看到Gu Lu的Blog《知乎回答:入职后发现项目组代码异常混乱,是去是留?》中谈重写还是重构的问题,说的很好, 读了很有些感触。重写与重构的抉择问题存在于很多公司,尤其是创业企业。下面说说自己的意见:

先说结论:如果是功能单一的某模块,重写问题不大,而复杂系统在绝大多数情况下,都不赞同推翻重写。

原因如下:

  1. 复杂系统的推翻重写需要投入的开发资源很大,周期很长才能见到效果。对企业来说这是一种孤注一掷的赌博,风险很高。
  2. 而且重写期间,旧有系统得不到根本改进,公司要冒着长时间内业务需要的技术支持无法得到改善的风险。
  3. 还有,看到过的推翻重写的复杂系统,很多没什么好结果。不少重写出来的东西同样百病缠身,甚至还不如原有系统。

做出重写或重构的决定很容易,但真正让一个系统能有提高,真正让一个团队能更进一步,需要的是一些更深层次的改变。

 

  1. 重构应该贯穿代码开发的始终
    好的代码是改出来的,代码需要不停的重构, 重构应该贯穿代码开发的整个阶段。很多人能在创业初期迅速开发出能工作的系统,但他们把这期间的遗留的问题称为技术债务,总希望能抽出专门的时间来解决它。这种事自己也做过,但现在不赞同专门抽时间重构,而是认为重构应该贯穿开发的始终。这之间的差别貌似很小,其实是开发方法上的本质差别。
  2. 自动测试
    当面对的是一个很庞大复杂的系统, 很难在短期内通过简单的阅读代码就彻底读懂它。这时你的一些改动如果没有测试去做检查,那弄不好就会造成系统的一些很严重的问题。 这个问题在代码缺乏良好的风格,缺乏良好的架构情况下会更突出。但如果手工测试的话,过程会很漫长,会造成整个系统迭代速度极其缓慢。而且手工测试本身也是有不低的错误率的。 复杂系统的重构必须要有自动化测试做保障。单元测试的技术已经很成熟,而seleniumappium等测试工具的出现则为为浏览器,app等终端产品UI的自动测试提供了很好的手段。robot framework等测试框架的出现,则为搭建自己的测试系统提供了很好的支持。而云技术发展,则为搭建可自动缩放的测试系统提供了很好的基础。 当几百个测试用例可以在半个小时就全部跑完的时候,重构的迭代速度会大大加快,而且会是有质量保障的速度。
  3. 可测试性
    代码的可测试性大家谈的不多,很多编程名著里见不到他的踪影。代码的可测性可能在开发简单系统,比如单机软件时还不那么重要。但在开发复杂的系统时,当你需要重构它的时候,可测试性的重要性怎么强调都不为过。 当你重构出现问题时,可测试性好的代码应该能让你迅速发现问题,定位问题。可测性不好的系统,自动测试的意义会大打折扣。至于什么是可测性,大家可参看同济大学的朱少民老师写的一个非常好的ppt:谈软件可测试性,这里就不重复了。可测试性不只是有利于在开发阶段调试代码,在生产环境中,可测试性好的系统也有助于迅速发现定位问题,减少问题造成的损失。
  4. 其他
    1. 持续集成
      有了持续集成,你就可以从打包,到测试,到生产环境部署都可以全自动化完成。 一旦发现问题可以立刻自动回滚。
    2. 在线生产环境监测
      应该建立一套生产环境监测系统,并不断完善,一旦发现问题立刻发出警报, 甚至能自动做一些自动应急修复错误。

 

做好上面几点,重构就可以放心大胆的进行。否则重构也是很冒风险的,这也是为什么很多公司都有些大家都不敢动的老代码的原因。

说到底让团队能做好重构工作,是要在团队里建立一种开发文化:

  1. 产品快速构建,小步快速迭代
  2. 重视测试,重视软件工程

===========================================

曾经做过很成功的一次重构,在半年后旧有代码已经很少,几乎90%以上都是新代码,系统性能和稳定性都大幅提高。有可能从半年后的视角,会觉得这是一次重写,但这其实都是每天一点点重构带来的。整个重构的过程系统不断稳步提升,整个改变平滑顺利。除了重构代码的工作,还做了不少别的:

  1. 当时重构工作开始的第一天,就安排专人开发自动测试系统
  2. 后来又开发了生产环境的监控系统
  3. 给系统增加了不少专用的监测接口
  4. 当时业务人员遇到问题常常直接捅到开发这边来,后来给系统增加了一个接口,能迅速帮助业务人员定位是使用错误还是系统错误,如果是使用错误是具体什么错误。增加这个接口后,从业务那边过来的技术支持压力一下少了很多。这也算是增加了整个系统的可测试性。
  5. Gulu文章中提到的幽灵替补,灰度发布的方法都用到了

也有些方面没做好:

  1. 当时的持续集成一直想做,但因为各种原因一直没做起来,真正持续集成是在现在的公司才做到
  2. 当时的自动测试系统只能做基于Web API的测试,UI自动测试做了尝试,一直没真正做起来。这也是到了现在公司才真正知道怎么做。
  3. 柔性服务的思想很好,当时没想到,希望以后能试试。

 

7 Comments

  • By greatghoul, 五月 25, 2015 @ 7:22 下午

    为以前的几次重写行为感觉羞愧。

  • By Andy Lin, 五月 30, 2015 @ 9:50 上午

    找个时间和你当面聊聊这个话题。 :em69:
    “很多公司都有些大家都不敢动的老代码的原因。”
    – 这一点上可能还有:组织政治的因素,
    1. 动不动,这是开发/管理/市场 三个角色博弈的结果。
    (如果遇到一个自称可以做架构师的管理人员,请慎记不要试图说服他。 :em51:
    2. 老旧代码的坏疾累加,会在追后阶段影响到市场,
    如客户投诉bug 多,产品无法快速根据市场需要增加新功能。 这些缺点会反转过来影响代码。
    3. 有些大公司总自诩“工程师文化”,可能是因为工程师是最早识别出这些问题的人。

    Andy Lin

  • By oldmonk, 五月 31, 2015 @ 12:02 上午

    不用愧疚,多尝试才能找到适合自己的路

  • By oldmonk, 五月 31, 2015 @ 12:03 上午

    组织政治因素确实会有,现在休假,回去好好聊聊

  • By XiaoHui, 六月 17, 2015 @ 10:08 上午

    说得很对,许多时候,重构出来的东西,比原来的BUG更多。
    不断测试、迭代,对中小型系统来说可能是最好的办法了。

  • By 哈哈姐, 七月 10, 2015 @ 7:20 上午

    英杰有时间联系我。

  • By oldmonk, 七月 10, 2015 @ 9:25 上午

    已回email,请查收

Other Links to this Post

RSS feed for comments on this post. TrackBack URI

Leave a comment

  • :em48:
  • :em32:
  • :em34:
  • :em14:
  • :em72:
  • :em37:
  • :em53:
  • :em56:
  • :em25:
  • :em39:
  • :em04:
  • :em13:
  • :em38:
  • :em20:
  • :em41:
  • :em31:
  • :em16:
  • :em45:
  • :em21:
  • :em43:
  • :em12:
  • :em71:
  • :em11:
  • :em23:
  • :em46:
  • :em66:
  • :em47:
  • :em02:
  • :em49:
  • :em54:
  • :em27:
  • :em36:
  • :em35:
  • :em15:
  • :em05:
  • :em26:
  • :em44:
  • :em06:
  • :em64:
  • :em01:
  • :em55:
  • :em70:
  • :em28:
  • :em40:
  • :em67:
  • :em18:
  • :em63:
  • :em09:
  • :em10:
  • :em62:
  • :em69:
  • :em03:
  • :em08:
  • :em33:
  • :em42:
  • :em52:
  • :em51:
  • :em68:
  • :em30:
  • :em65:
  • :em59:
  • :em29:
  • :em07:
  • :em50:
  • :em17:
  • :em24:
  • :em57:
  • :em22:
  • :em19:
  • :em60:
  • :em61:
  • :em58: