代码改变世界

写程序时该追求什么,什么是次要的?

2009-05-29 15:14  Jeffrey Zhao  阅读(25222)  评论(38编辑  收藏  举报

就我看来,一段程序,最该关注的是“逻辑表现”,次要的“性能”等问题的优化。当然,肯定也会有需要追求性能的场景,不过这并不是“追求”出来的,而是在大量经验累计情况下做出的正确决策。就算在那种情况下,“逻辑表现”还是非常重要的。

“逻辑表现”的意思,就是如何用程序清晰地体现你的逻辑。每个程序的目标都是解决某个特定的问题,解决问题便有思路,这个思路用程序表现出来便是逻辑。与初中高中证明数学题一样,逻辑清晰,并把它表达出来是最终的目标,而现在也只是把原本写在纸上的文字,通过代码表现出来而已。

写代码,其实也是用一种特殊的语言——程序语言,而不是文字来表达一段意思。我们平时写文章需要注意分段,分层,分条理,写程序也是一样。可能由于水平有限,你一时还无法写出华丽俊秀的文字,但是写文章的首要目标还是“清晰”,要让别人明白你的意思。写程序也是一样。在写程序时,你不应该总想着用什么技巧,追求这些技巧所带来的好处。

老赵承认,每个技巧都是有其作用的,否则就是“笑话”,谈不上“技巧”。不过有得往往就有失,某段技巧必然有其缺陷。例如在之前“数组元素交换”一题中,有朋友认为应该不使用额外变量来交换两个元素,也就是:

array[j] = array[i] + array[j];
array[i] = array[j] - array[i];
array[j] = array[j] - array[i];

他认为,这段代码节省了额外的空间,在内存紧张的情况下很有必要。但是老赵认为,这里的损失了可读性。对于一段标准的交换代码,每个人都知道它的目的,而正在读这篇文章的您,是否可以立即反应出上面三行代码的作用?

在编程领域有一个道理被广为传播:make clean code fast远比make fast code clean要容易,这里clean无疑是“清晰”的意思。因为代码清晰,我们可以找出其性能瓶颈,然后有针对性地加以优化。要知道把一个调用10000次的过程优化了20%,比调用10次的过程优化80%(假设两个过程原本消耗接近)要明显的多。

就拿那位朋友的观点,内存紧张时该怎么办。可能他的做法的确有所节省吧(不过高级语言中的“节省”,对于最终编译后的结果又是两码事)。不过在内存紧张的时候,首要做的应该还是设法探究最耗费资源的地方时什么,然后加以优化。因此,可能会对某个问题重新设计其数据结构,例如压缩数据存放方式,共享数据空间等等,而不是设法节省一个字长的内存。那么如何可以能方便瓶颈的发现呢?

清晰。

当然,上面这段代码并非不可使用,只是如果您真要这么做,请把它封装为一个子方法:

private void Swap(int[] array, int i, int j)
{
    array[j] = array[i] + array[j];
    array[i] = array[j] - array[i];
    array[j] = array[j] - array[i];
} 

一旦你把这段逻辑给分离了,在代码里只适用Swap方法了,那么程序也会一下子变得清晰起来。而且在这时候,这三行代码也变得容易理解了,别人也可以一眼看出它的作用——因为方法名已经说得很清楚了:交换。

所以,我们在写程序的时候,不如仔细想想,如何把变量名、方法名或参数名取得清楚一些,如何把程序的逻辑表现地清晰一些,如何把你的意图更好的告诉别人。

剩下的细节优化,什么内联子过程……就统统交给编译器去处理吧。