经历了几个从商业角度来看或成功或失败的项目,都会发现代码、设计都会慢慢地、在不经意间腐化。并且有一个项目开始的时候,架构是通过精心设计的,也有较为严格的代码规范,而且经过静态代码检查来尽可能保证代码的质量,连code review都有一个可供参考的checklist。但半年一年以后,仍是会发现,不少代码都已经臃肿走样,处处都是复制粘贴,动辄好几千行代码的模块,能 work、但不 right的代码。html
getting it work is easy
getting it right is hard程序员
不由想问问代码和设计是如何一步步腐化的?设计模式
本文地址:http://www.javashuo.com/article/p-cmywjpng-cd.html架构
其实你们都据说过 clean code,但不必定真正意识到其重要性,且知道并不等同于作到,而时间更是一把杀猪刀,让程序员秃了,让代码烂了。函数
一个新项目开始的时候,你们都是满怀壮志,期待灵活可复用的架构,期待成功的产品。与此同时,敏捷开发告诉咱们不要过分设计,固然,自己也是很难预料到之后需求变化的方向,因而应该等到第一次变化的时候才去考虑如何重构以应对这一类型的变化。但问题极可能就会出如今这里。单元测试
也就是说,也许哪一天,当咱们须要加一个新功能的时候,会发现原来的设计和代码不是很方便增长这个新功能。固然,咱们不该该过多苛责以前的设计,由于之前没有预料到这个新功能,也就没有在这个地方引入抽象。这个时候有两种解决办法:第一种是重构术,就是加功能以前先了解、重构已有的代码,好比调整一下类的基础体系、抽象出基类、或者引入一个间接层以隔离变化。另外一种则是修补术,在现有的函数中加一个 if-else(或者 switch case)、在现有的类中加几个特殊字段。这两种方法都能解决问题,修补术治标,重构术治本,但显然,治标来得更快,治本对程序员的要求更高。测试
何时程序员会选择修补术而不是重构术呢?ui
也许这个程序员看过 clean code、refactor,精通设计模式和面向对象,也很是但愿维护一份漂亮的代码。但咱们知道,重构是须要时间的,并且还可能引入bug。也许重构耗费的时间就超过了用修补术 workaround 的时间,就短时间来讲,修补术的性价比是更高的。那么长远来讲呢,也许重构术的性价比更高?但是只顾眼前、及时行乐是人的本能,走捷径、偷懒是无时不存在的诱惑。固然,也许有追求的程序员会抵制这种诱惑,可是社会心理学告诉咱们,在压力、干扰面前咱们很难理智思考,自控力也会失效。时间、进度压力就是垂悬在程序员头上的达摩克利斯之剑,这压力可能让人失眠、让人头秃,写点垃圾代码彷佛也无可厚非。设计
何况,重构还可能引入bug,重构的前提是要有完备的测试机制,单元测试、功能测试、集成测试一个都不能少。但是,理想很丰满,现实很骨感,单元测试覆盖率每每不足,并且还可能依靠手动回归测试。把代码重构好了可能压根没人知道,没人来感谢你、给你点个赞,但万一重构出了bug呢,你们都会收到事故报告,说不定还会影响KPI?不求有功但求无过,Leader、经理是否定可重构的价值,也很大程度影响组员对于重构的积极性。代码规范
固然,增长新功能的也许是一个新手,新手加入团队后,通常就是从维护某个模块,实现一些小需求入手。新手有可能水平自己就不行,并且业务逻辑和代码都是陌生的,若是缺少完善的文档以及足够的掌握,新手是万万不敢重构的,修补术是最天然的选择,复制、粘贴、稍微修改一下、build、run,成功啦!又实现了一个需求!你知道,新人是急于证实本身的,快速的实现一个又一个需求是证实本身的最佳办法。
你有可能说,新人不是应该有个导师吗,导师得review新人的代码啊。首先,导师得懂这一块业务;其次,导师得愿意花时间指导新人。指导新人是否影响导师的KPI呢?带好了是否有奖,出问题了是否有惩?若是全凭导师自律,这个不肯定性就太大了。
上面提到的是新人,其实老手也可能写出“德不配位”的代码,好比一个需求,可能涉及到多个模块,有的模块是这个老手负责的,有的则不是。理想的状况下,各个模块提供好接口供老手调用便可,但某个模块的负责人很忙,没有时间,这个时候老手就会直接去修改相应模块。但是,可能因为老手特有的自尊、或者面子,老手每每不肯意去请教对应模块的负责人,而是按照本身的经验魔改出一段能够工做,但既不优雅、也不高效的代码。
因此说,因为进度压力、经验、态度等各类各样的缘由,代码中慢慢就会开始出现腐朽的问题。可怕的是,垃圾的代码给出了错误的示范,这种示范对于新手或者对于这个模块不熟悉的同事来讲都很强烈,也使得垃圾的代码、倍增的维护成本、潜在的bug被处处复制,美其名曰“借鉴”。破窗效应,让后来人写出垃圾代码的时候毫无意理负担,“之前就是这个样子的”,之前这里有个变量叫temp,我只是加了个变量叫temp1;之前这里就有switch case,我只不过加了一个case;之前的代码就很难读懂了,因而我copy的一份实现本身的逻辑。
何况,到项目后期,可能再也不那么挣钱了,可能最初写代码、制定规范的人已经再也不了,谁还会来关心这代码质量呢?
悲观的认为,代码的腐化是必要,只是时间快慢问题。