编程,更多?更好?更快?
最近,读到一个故事,是下面这样的。
在一次陶艺课上,老师在第一堂课时说,他会把班上同学们分成两组。教室左边这组,他们这门课的成绩将会以最终完成的陶器作品数量来评定,而右边那组,则会以最终完成的陶器品质来评定。
进一步说明,其评定过程是这样的:这门课的最后一天,老师会带来一杆天平称,用来称量 “数量” 组的成果。如果 50 磅及以上,得 A,40 磅及以上得 B,30 磅得 C,如此类推。而 “品质” 组只需要提交一件(仅一件)他们组认为最 “完美” 的作品即可,如果老师也认为很不错,就可以得 A。
时间很快过去,到了该交作业的日子。一个很有趣的现象出现了,“数量” 组如预期一般拿出了很多作品,但质量最好的作品却也全部是由 “数量” 组制作出来的。按 “数量” 组的评定标准,他们似乎应该忙于粗制滥造大量的陶器,但他们每做出一个垃圾作品,都会吸取上一次制作的错误经验教训,再做下一个作品时得到改进。而 “品质” 组一开始就追求完美的作品,他们花费了大量的时间从理论上论证如何才能做出一个完美的作品,而到了最后拿出来的东西,似乎只是一堆建立在宏大理论上的陶土。
更多当我读完这个故事,陷入了沉思,感到编程和制作陶艺是如此类似。《黑客与画家》书里讲,编程和画画近乎异曲同工,其实很多这种类似工匠型的技艺都有其相似之处。
很多人小时候都画过画,是的,我小时候也爱画画。看见一幅图,拿上一只笔就可以开始临摹。后来有了美术课,开始写生,看见了,就能画出来。但现在我却不再画画了,为什么?因为,现在我再回头看曾经画过的画,简直就是一坨 “狗屎”。后来,长大了,成年了,读完书、考上大学,工作后,再想拿起笔去画时,发现还不如小时候画的,所以我不再画了。
为什么那时候(小时候)明明画得不好,却可以不停得去画。也许这个问题有很多答案,但我想其中之一必然是:那时候,我们并没有给自己施加任何的限制,没有追求完美的作品,没有追求画画的意义,而仅仅是在探索与学习。一幅接一幅的画,仅仅是这一次比上一次有所进步,我们就会开心的大呼小叫。
某一天,我们长大了。我们知道了,画画是一种技艺,甚至是一种艺术。我们见过了真正可以称之为艺术的画作,我们也知道了如何才算是正确的画画,所有这些让我们感到,曾经的那支画笔已经重到让我们不敢再轻易去拿起。
那些成名画家的作品,如果按时间顺序来排列展示,我们会发现每幅画所用的技巧,都是建立在上一幅作品学到的东西之上。如果某幅作品特别出众,你往往能在更早期的作品中找到类似的版本。
而编程这门技艺,也完全是一个类似的过程。我很庆幸我在初学编程时,就像我小时候刚拿起画笔,我只是在不断通过编程训练来解答一个又一个书本上得来的困惑。后来,则是不断写程序来解决一个又一个工作中的问题。那时,看到书上探讨各种优雅的代码之道,编程的艺术哲学,我却完全不知道如何通往这座编程的 “圣杯”,看着自己写出的蹩脚代码,然后继续不断重复去制作下一个丑陋的 “陶器”。
而过去十多年的编程经验印证了开头的故事,在通往「更好」的路上,必然要经过「更多」这条路。
更好编程路上,如果一开始就像 “品质” 组的同学那样去追求完美,也许我们就会被定义 “完美” 的品质所绊住。
编程的问题是,一开始我们并不知道什么是编程的正确方法,无论我们在开始动手编程时看过多少有关的编程理论、方法、哲学与艺术的书。这样反而让我们没有什么约束,只管去盯住你要用编程解决的问题,把问题解决,把任务完成。
曾经,还在学校学习编程时,有一个期中课程设计。我很快完成了一个这个课程设计中的编程作业,而另一位同学,刚刚看完了那本经典的设计模式书。他尝试在用书里学到的新概念来设计这个编程作业,并且先又用 UML 画了一大堆交互和类图,去推导设计的完美与优雅。然后兴致勃勃的向我(因为我刚好坐在他旁边)讲解他的完美设计,然后我若有所悟,觉得里面确实有值得我改进的地方,准备吸收一些我能听明白的东西,重构一遍已经写好的作业程序。
后来,这位同学在动手实现他的完美设计时,发现程序越写越复杂,交作业的时间已经不够了,只好借用我的不完美的第一版代码改改凑合交了。而我这在第一版代码基础上,又按领悟到的正确思路重构了一次,交了作业。而巧的是我的第一版代码,又流传到了另外几个同学手上,几乎也就改个名字就当成作业交了。但是,我们那门课的老师有一个专门识别类似作业程序代码的程序,检查出了相似度极高的那几个同学的作业,都是我的第一版代码,结果所有人都被打回重做了一遍,而我暗自庆幸,还好我又重构一次。
编程,其实一开始哪有什么完美,只有更好。之后,工作了,我做了大量的不大不小的项目,然后发现这些项目都有很多类似之处。每次,即使项目上线后,我也必然重构项目代码,提取其中的可复用代码,然后在下一个项目中使用。循环往复,一直干了七、八年。我想,很多程序员都有类似的经历,而把这件事干得最有名且极致的是江南白衣的 SrpingSide(一个以 Spring Framework 为核心的,Pragmatic 风格的 JavaEE 应用参考示例,是 JavaEE 世界中的主流技术选型,最佳实践的总结与演示。) 开源项目。
在这个过程中,我渐渐成型了属于自己的编程价值观:没有完美的解决方案,任何方案总是有这样或那样一些因子可以优化。一些方案可能面临的权衡取舍会少些,而另一些方案则会更纠结一些。但所有的方案,我都做了取舍。
好不是完美,好是一个过程。
更快当做了足够多,并且到了足够好的时候,自然能做到更快。
影视作品里,总是用一种敲击键盘的快来表达黑客高手编程的快。但实际编程最大的瓶颈在头脑,而非手指。如前,程序员反复提取、重构与优化的代码,最后就成了自己专属的工具箱和脚手架。遇到类似的问题、场景,要么直接就能复用,要么稍微改改也能使用,这样才能做到快。
所以,为什么会有不要重复发明轮子的说法,我们要把宝贵的思考力用在更新的问题上,而非已经解决的问题上。为什么需要尽早并经常性的重构代码,扔(重构删除)掉一些代码,就是扔掉负担,然后走的更轻松,留下(重构复用)另一些代码,让未来走得更快。