技术重构

前同事离职,我接手他的项目,到现在为止,缝缝补补敲敲打打接近2个月(包括十一休假)。中间有大量的技术重构情节,于是总结和思维拓展一下关于重构的话题。当然,接下来不会讲技术细节。

项目背景是要将原来一个程序从本地版移植成在线版,说白了就是从本地读数据变为发web service从服务器拿数据。这么说其实这个项目本身就是一个大的“技术重构”,因为程序的关键点在于拿数据的方式不太一样,大部分的业务逻辑是可以复用的。当然由于在线版取消了SD卡,所以需要考虑性能和磁盘空间的问题,比如展现数据的列表就需要加上分页的功能,所以部分的表现层逻辑也需要相当的修改。编程语言是面向过程,特定平台的移动开发方式也是逻辑和界面混合编程,再考虑服务器端的编程,这确实不是一个简单的工作。

接手原来的同事的项目为什么也需要技术重构?坦白讲,前同事离职期间比较赶工,加上在原来的代码基础上修改,而且项目的需求又不太明确,所以很多情况下做出来的东西像半成品 — 表面上一个普通的bug,实际分析后可能需要重写相应模块才能从“根本”上修复掉这个bug。苦不堪言,为什么苦?不是因为重写模块多么复杂,而是表面上的这一个bug给客户的管理层,公司的管理层,以及自己带来了“一个bug应该马上可以修复掉”的期望,但重写相应模块甚至重新设计相应的技术架构又需要相对较长的一个时间并且没有产出!这对于软件服务公司来说“没有产出”是很让人hold不住的事情。奋战了将近两个月,这个项目基本稳定了。

下面关于技术重构总结一下:

哪些情况可能需要技术重构?
1. 需求变更时。
如果之前设计的架构可扩展性足够好的话当然是幸事,但大多数情况下你碰到的架构是为之前的需求量身定做的(有时候是技术局限)。需求一变,在我们的平台上甚至界面一变,逻辑层的代码也得变动。嘿嘿,工期估计的时候多谈点技术方面的原因争取多要点时间吧。

2. 代码评审后。
为什么说Code Review是王道呢?在Google所有的代码必须经过Review才能check in,可见一个人的思维有时候不是完美的。写代码前的设计Review(如果有的话)当然是好的了,不过相信我大部分人设计之后会在编码阶段更改,甚至和之前的设计完全不同。于是,迭代式代码评审就显得尤其重要了。

3. 二次开发时。
这个类似需求变更,不过可能不是原来的模块,而是你在原来的模块上新加模块。原则是尽量让新加模块配合原来的模块而不去修改原来的模块,不过做好心理准备去读别人的代码,去重构别人的代码。

4. 修复缺陷时。
正如片头举的例子,有时候一个bug,看起来很简单,但是如果想从根本上改掉这个bug而不带来其他regression bug,大胆重构吧。

5. 产品维护时。
此类应该是综合了第1种和第4种情况,大规模技术重构一旦发生,维护期便被拉长,偶尔维护期的加班也会发生。这也从另一个角度解释了为什么软件的维护费用很高了:)。

技术重构时可能会遇到的压力:
1. 时间线压力。
重构,就是大改。所需要时间会超过工期预算时的预期,于是时间线压力变转变为你需要花费更多的时间,在deadline不变的情况下,加班就发生了。

2. 技术不确定压力。
当碰见难题预计要发生重构时,脑中就已经有上面讲的时间线压力了。在如此时间线压力下,人容易患得患失自己的产出。“重构需要好多时间,赶紧抓紧时间写代码吧”– 慢着,您在设计重构时考虑周全了吗?本意是想重构别人的明显有问题的代码,结果自己的设计也有问题导致最后出现更为灾难的后果。敌军再多也需要坐怀不乱,静如处子,才能动如脱兔。

3. 管理层压力。
假设有这么个场景,你手头上有4到5个bug,你看出来其实这都跟前面糟糕的设计有关,于是改变策略从“针对bug来修复”到“一次性技术重构”。通常来说技术重构需要时间,你可能2到3天都专注于新架构的设计上和实现上 — 注意,这2到3天从管理层看来是,“一共才4到5个bug,都2、3天了一个bug都没改掉,你在干嘛?” –  不能怪管理层,这种压力是必然的。管理层的眼中只盯结果,2到3天结果没变,而项目又离deadline更近了,你一人在那里技术重构,鬼知道会不会碰上第二种压力让重构失败。所以,重构务必成功,否则真的要跟客户道歉了。

技术重构遇到压力阻力后会发生的事情:
1. 针对缺陷表面修复缺陷。
工程师迫于上面说的几种压力,干脆不技术重构了,就针对bug来fix bug。你不是说这个值显示不出来吗,那我加个全局变量搞定它;你不是这边跳屏逻辑有问题吗,我再加个全局变量搞定它。。。。。。搞来搞去,可能问题是修复了,但是软件内部实现就惨不忍睹了。一旦再次发生需求变更,嘿嘿,你有可能会在代码不显眼的地方发现一处注释“当时只有我和上帝知道这块的逻辑,但,现在只有上帝知道了”

2. 有些缺陷怎么也修复不了。
因为技术架构有问题,所以技术实现在某些看起来很小的bug上就是修复不了。比如UI上某处数据显示错误,在QA那边报一个字段显示错误,但实际上这个字段是一系列数据计算的结果,中间的某些数据因为糟糕的设计取不到。。你懂的,除非技术重构否则你修复不了这个简单的“UI显示错误”。

3. 时间线一拖再拖。
缺陷怎么改都改不完,改完了发现又多了些缺陷,尽管不断的加班,但是时间线一拖再拖。让我想到一个笑话,产品底层framework有问题你在上面去换公司CTO换产品班子有什么用?你懂的。

结论:
1. 出来混,迟早要还的。
该重构时还得重构,别留给以后的人了。就学某位美国总统说的,“麻烦到我这里为止”。

2.Jobs:让时间线见鬼去吧,我们需要一个好的产品。
是产品本身重要,还是时间线重要?当你的产品不足以好到苹果的水平时,客户不会为你的时间线延迟买单。