CATEGORY / Development

代码之初,性本丑?(中)

Permanent Link: http://wutiam.net/notes/144

代码之丑(三)——switch陷阱

可能是因为篇幅关系,这篇文章里的例子不够有代表性,而且还有越改越没有可读性和可维护性之嫌。曾经我在公司的一个比较有历史的程序里看到过一段伟岸的 switch/case 代码,每个 case 下的代码各不相同且长短不一也就算了,可能你无法想象的是,它里面竟然有几千个 case,总共 10000+ 行的代码!你没看错,一个函数一万多行!这就是从一开始放任 switch 陷阱,经过漫长地演化得到的后果。

其实我并不认为该把 switch/case 当作唯恐避之不及的恶魔,它只是一把双刃剑,就像没必要一味地反对使用 if 一样。在正确的环境下正确使用它的话,只会提高可读性,但如果滥用它(就像 C++ 很多其他特性那样),那的确是一场噩梦。

对于本身结构很简单的逻辑,使用 switch/case 能很好地保持其可读性(显然比一堆的 if/else 好,更不用说多态了),而且也正因为其逻辑简单,条件不多,也不会对系统性能产生明显影响(代码并非越短越快就越好,它首先是给人看的,顺便附带了能让机器执行的功能)。而对于我上面提到的超大的逻辑结构,倒是可以用多态或者状态机来解决,定位问题显然会方便不少(假如这个逻辑架构本身没法改变的话)。

代码之丑(四)——代码找茬游戏

“代码重复是 bug 之母”,没错,这就是传说中的 DRY 原则(Don't Repeat Yourself)。可悲的是,现实开发中,重复的代码比比皆是,无论是大拿还是小菜鸟,因为这是人的本性,在拷贝代码的时候说服自己,写完功能就把这儿重构掉,然而一旦功能完成,就不想再动这块代码了,否则做完了重构还得重新测一遍,太麻烦了。三个月后,因为业务逻辑的改动或者 bugs,另一位同事只改了其中一个代码的拷贝(他可不知道你的这些小秘密,甚至其实你自己也已经不记得了),完蛋了,又要花上一整天的时间来查到底出了什么事。可有几个人能坚持为以后的自己负责呢?“说不定再也不会暴露出来,先管它呢”。

唉。

人会犯错,想偷懒,本来都不可怕。对于大多数程序员,引入交叉 code review 机制,真是一个不错的选择,毕竟总是做得比别人差是很难堪的。但对于少数缺乏羞耻心的人来说,真没什么好办法,如果我是老板,别让我的团队被一颗老鼠屎糟蹋了。

代码之丑(五)——不受欢迎的大心脏

先局限在该文的例子说说,这个代码的问题得根据其真正的用意来定。如果它真的是为了克隆 oldRule 的所有属性并加入到规则池中去,那更好的做法应该是为 ColdRule 类提供一个拷贝构造函数:

rules->Add(new ColdRule(oldRule));

能封装到自己内部的操作为什么要让外面了解这么多细节呢。但如果它的目的只是把 oldRule 中的一部分属性设给新的 rule,然后“可能”还要做些额外的设置(或者只是保留构造函数中的初始化设置),那就又得斟酌有没有必要提出一个公共函数来封装这份操作,以及这个函数是放在类内呢还是放到一个公共文件里了。

这就是我想说的,写代码很大条的确不是个受欢迎的性格,但有些代码的业务逻辑实在太繁琐了,它就是需要几十个步骤来完成,每个步骤还会有若干个分支,而这本身又只是一个很小的功能点(比如读取 DDS 图片文件头),为了代码“优雅”所付出的成本远高于其价值,那这样的重构是否还有必要呢?我个人认为很没有必要,倒不如花点小力气,写些注释,加些换行,把这块又长又复杂的代码弄得阅读起来顺溜些,总比把各个小秘密藏得到处都是好多了。

2 Comments / Trackbacks / Pingbacks

Leave a Reply

:) :wink: 8-O :lol: :-D 8) :-| :mrgreen: :oops: :-o :-? :( :twisted: :cry: more »