日期:2014-05-20  浏览次数:20933 次

十年总结(13):开发不息,重构不止
对我过去感兴趣的朋友们,请看十年总结系列文章

---

在经过RUP和XP两种思想的冲撞之后,我发现想要借助一个什么理论来获得工作绩效的提升,基本上是不可能的,
RUP也好,XP也罢,都不是看看书,照猫画虎就可以解决软件开发过程中的问题的。

还是应了那句话:软件行业没有银弹。
从宏观方面来看,项目在开发方面面临的问题是类似的:延期交付,质量不易控制,需求反复等等,
但每个项目又有其独特的人员构成、技术架构以及用户环境。
因此,只能说:软件开发的管理,没有放之四海皆准的规范,我们可以定目标,但实现目标的手段应该多样化。

实施XP一段时间,除了我和军军,还有军军介绍过来的一个同学一起做过结对编程,做过测试驱动开发以外,
但推动团队中的其他人参与XP的最佳实践难度非常大。
这些难度主要来自于人,人的配合度,以及人的能力。

在配合度方面,XP需要所有参与者都对这种思想有高度的认同感,然而不是每个人都对软件开发充满激情,
也并非每个人都追求完美,很多人只是将工作当成养家糊口的手段,按部就班的做事儿,甚至有些被动的承担任务,
这就已经与XP对质量不懈追求的基本目标背道而驰。

从能力角度来看,XP中没有严格的岗位划分,设计与开发是紧密融合的,
每个人都要会做需求分析,会设计,会编码,会测试,
你不能只了解自己负责的一小部分功能,而是必须随时做好接下新的任务准备。
就拿TDD(测试驱动开发)来说,没有很强的软件开发经验,是很难先行写出测试代码的,
写出了测试代码再去写功能代码,就意味着你已经对模块的输入、输出、处理逻辑、边界、异常等了然于胸了。

所以XP团队需要一个导师,不停的统一大家的思想,我就是这个导师,但后来XP的最重要支持者军军离开了公司,
一个人传承一种思想很孤单,也很无力,搞得我也没有太大的兴趣再深入推动XP了。

但不管怎么样,做这些事情的过程,让我学到不少技术以外的东西。
随着时间的推移,我逐渐把XP和敏捷建模的具体实践抛弃了,保留了我认为最核心的两条:
1、积极参与和有效沟通
2、对代码质量的不懈追求
这是我日后工作中的基本信念,也是对我的团队成员不断强调的原则,这就是我的团队文化。


正是对质量的不断探索,让我接触到“重构”理念,其实我觉得重构是实践敏捷的必然结果和必由之路,

为了增强软件的可扩展能力,传统的软件研发思路是尽量加强设计,越详细越好,最好把编码这块的人都当成傻子,
设计出来了,负责写代码的人严格按照设计规格来编码就OK。
设计中要预先设想未来可能出现的各种情况,这一方面容易造成浪费,另一方面可能会导致过度设计。

而敏捷思想则希望代码本身是容易改变的,每一次设计过程都不做过多的预测,看似有些“鼠目寸光”,
实际上却从另外一个层面对代码的可扩展能力提出了要求:
1、代码可读性。要让别人很容易搞懂代码的意图,以方便修改。
2、低耦合。以便修改的时候尽量缩减影响范围。

以上两点讲起来,可以有非常多的内容,不过这一篇已经有些跑题了,不多说了。
以上内容是基于上一篇延续出来的感慨,就此打住了。
总之我在软件开发管理方面现在属于无门无派,非正亦非邪,真的是很“草根”。

---

重构,就是在不改变代码原有功能的基础上,提高代码质量。

2004年的下半年,徜徉在大师们的思想中,真的感觉很惬意,
《敏捷建模》和《重构-改善既有代码的设计》这两本书,都是翻了几页就毫不犹豫买下来的,再加上《Thinking In Java》,
这三本书是到04年为止,我在技术方面看的最认真,也最有收获的几本。
我一直觉得,书不贵在多而在于精。

《敏捷建模》让我知道做软件开发还可以有一种更加灵活的方式,给了我一个可以去追寻的境界,
而《重构》给了我工具和指示,让我可以向大师的境界攀登。

《重构》这本书分成两部分,前面讲原则,后面讲手段,
作者将需要改造的代码成为Bed smell,真的是很形象,不好的代码,有点像“一块臭肉毁了一锅汤”的意思。
这本书蛮厚的,其实真正能够记下的都是原则性的东西,从后来的工作中体会到,最常见的Bed smell有:
1、重复代码。
我觉得这是优质代码的头号公敌,通常是大量复制、粘贴的结果。
这厮带来的最大问题:相同的逻辑分散在多处,导致修改困难,容易遗漏

2、过大的类或者方法
一个方法如果很长(通常超过两屏),则要理解其逻辑将非常困难,
重构时通常要将处理步骤梳理出来,每步一个子方法,主函数变成一个很清晰函数调用序列。
如有必要,可以对子方法进一步重构,直到每个方法只解决一个问题。

3、不合理的类封装
一个设计最初一般是合理的,但随着后续的修改,会不断的向已有类上增加方法,导致本来健康的类变得臃肿,
因此,每隔一段时间,应该重新规划方法的分布,比如在类之间迁移,或者抽象出新的类来。

4、魔鬼数字
int i=0;
int j=1;
如果不加额外的注释,谁能明白0和1的意义?
魔鬼数字的说法早已有之,是影响代码可读性的一大毒瘤,处理方法为:用常量替换之

出了魔鬼数字,还有一种魔鬼逻辑,比如:
if ((status==RUNNING || status==STARING) && (freeSlot.size()>RESERVED)){
//Do Something!
}
以上的if条件虽然没有出现魔鬼数字,但这个逻辑有些复杂,也是需要读代码的人费些心思去算计的,
通常条件判断式如果包含两项以上的表达式,这样的条件建议重构成一个方法:
if (canAcceptMore()){
//Do Something!
}

private boolean canAcceptMore(){
return (status==RUNNING || status==STARING) && (freeSlot.size()>RESERVED);
}

5、不合理的命名
不合理的变量名也会大大影响代码的阅读,变量名、方法名、类名、包名都要认真考虑,一般遵循如下原则
意义准确,且不随便将一个变量转作它用
风格统一(Java官方的约定就挺好的)
用词统一(同样代表缓冲,不要一会儿Buf,一会儿Cache,要么都缩写,要么都全拼)


6、冗长的参数列
函数拥有超长的参数列,通常也是增量修改的结果,这时候要考虑
要么,将参数抽象成一个独立的对象进行传递
要么,考虑一下这个方法是否有更合适的归宿
要么,可以看一下这个方法是不是完成了太多的逻辑而需要进行拆分



以上只是一些皮毛和最常见的情况,重构是一门艺术,需要在实践中慢慢体会,但最重要的,是要有这个心。

---

总结:

工作这么多年,学了很多东西,一直最怕的是把简单的问题复杂化,技术领域这样的例子数不胜数。
我觉得学习需要一种境界,张无忌学太极是最经典的例子,一开始还能记得招数,回忆几遍,就忘得差不多了,
学习进入这种境界,才能在如今技术、名词、思想满天飞的时代,不被乱花迷人眼。

比如Spring,刚出来的时候扛着轻量级框架的大旗,可大家看看现在的SSH,哪里还有“轻量”的影子?
上手就有很大的难度,更别说精通了,到底是简单了,还是复杂了?

敏捷建模也是,其核心思想就是敏捷,而基于此构建的种种思想和框架,岂不是给自由的灵魂套上了枷锁?

设计模式也是,最初只有24种经典模式,我们尚且不能运用自如,
现在恨不得模式满天飞,大脑不是计算机,不擅长背诵,
当信息量超出我们的记忆能力的时候,这些信息是否有价值,甚至说是否有害?

重构其实也一样,你只需要记住这本书名《重构-改善既有代码的设计》和它改善代码的原则即可,
至于其中的上百种重构手段,没有天才的记忆力,就不必背诵了吧?


最后,说一句,养成良好的编程习惯很重要,不要因为你是在做试验而不注意代码的质量。

------解决方案--------------------