程序员和拉条子



做拉条子是个苦力活,能把拉条子做好的程序员,写程序也不会差到哪里。

定谱

在做之前,你要么手边有本菜谱,要么心中有谱。你「看得见」,「闻得着」还未成形的美食:色泽如何,汤汁几成 —— 仿佛她们就在嘴边,向你招手;写程序前,你的谱就是你的设计,你清晰地知道 goals / non-goals,知道完工那一刻程序的模样。读菜谱是个苦力活,你要了解谱者的意图,知道所需的工具,材料,谋划行事的顺序,确保执行时一气呵成;设计也是个苦力活,你一遍遍在纸上模拟,在胸中演算,这样到了真正写作的时候才能「手之所触,肩之所倚,足之所履,膝之所踦,砉然向然,奏刀騞然,莫不中音」。

备料

做拉条子的材料很繁琐:面条需要靠面粉和水来配;配菜有:西红柿,青椒,洋葱,胡萝卜;小料有姜,蒜和葡萄干;佐料自然少不了油盐酱醋。这些东西都是别人做好提供给你,即插即用,否则做个拉条子还得自己种麦子磨面粉,这日子便没法过了;写程序也一样,讲究生态圈,一个程序员再牛逼,没有各种库的支持,原材料不够齐备,也无法多快好省地写代码。

在备料的时候,你需要考虑工期。客户在那嗷嗷待哺,你可不能窝在厨房里研究材料研究个三五小时。此时,即便你是个制面大师,也得收敛和面的冲动,去超市买上一把品相不错的手擀面。拉条界的人精明果敢,眼睛紧盯着目标如何完成,所以喜欢现成的材料;而程序界的人一根筋,总觉得自己最牛逼,动不动就傲骨侧漏,跟自己较劲:没有洋葱(库)就自己种,或者手边即使有洋葱,但嫌洋葱卖相不好,也非要自己重新整一个,美其名曰:reinvent the wheels。所以做过拉条子的过来人,写程序时会考虑集成第三方工具,绝对不会什么都自己做。

当然,不是什么时候都有手擀面卖的,这时你不得不自己去做,但做有两种做法:鱼和渔。前者考虑当下,解决具体问题,全手工和面和拉面;后者着眼未来,买个和面机和压面机,按照功能说明使用即可,一劳永逸。写程序也是如此,你要考虑是特殊问题特殊处理呢,还是特殊问题抽象化,制造出(购买)解决这类问题的机器处理呢?to build,or not to build,this is a question。

开工

料备齐了,接下来是开工干活。做拉条子,就是把手擀面化作热腾腾的面条,各种材料制出香喷喷的配菜,然后二者混合的伟大过程。整个过程从材料到成品,需要一系列的转换(transformation);而写程序,是完成一个系统,把输入经过一系列的转换,化作输出。

我们看:切菜是个 map 的过程,一根根胡萝卜,一颗颗青椒,被一个叫「滚刀」,或者「推刀」的工序 map 成一堆堆胡萝卜丁,或者青椒丝,随即它们和 map 成丝的牛肉块洋葱,map 成块的西红柿一起,先后入锅,接受 reduce 的过程。

嗯,炒菜是个 reduce 的过程。一份份材料或单独,或组合,被一个叫「翻炒」或者「爆炒」或者「焖炖」的工序 reduce 成一个个半成品,最后这些半成品们,再被 transduce 成配菜,和煮好的面条一起,被 flatMap 成一盘盘大家喜闻乐见的拉条子。

写程序更是如此。map / filter / reduce,基本上,你 90% 的代码都在干和这相关的事。

干活不能蛮干,讲究流水线作业(pipeline),才能事半功倍:何时切菜,何时切肉,何时下油,炸花椒,入姜末洋葱,何时炒肉,何时炒青椒,何时烧水下面等等。你必不会在菜完全炒熟之后才烧水做饭:你会在灶台上,开启两个进程,一个处理炒锅,一个处理煮锅,它们有各自的流水线,但在某一点交汇(thread.join)。每个进程虽有固定的优先级(烧水的时候,炒菜是优先级最高的),但一些突发的事件(比如水开了,或者水要溢出来了)可以抢占你的处理能力。

写程序也是如此,一个程序基本上就是一个大的 pipeline 化作一系列小的 pipeline 然后不断 pipe 下去,直到 CPU 拿到一条条指令,放入自己的 pipeline 中执行。pipeline之间需要同步,你可以通过 lock,callback,CSP,actor 等等方法进行同步。

异常

干活的时候,和写程序的时候,总需要面对异常处理。萌蠢的大厨总是会把自己的手砍伤,被开水烫伤,被火烧伤,当这些异常发生时,如果不能淡定地挂起当前的进程(比如说关火),而手忙脚乱地处理,那么会产生更大的后果。写程序的时候,如果没有 let it crash(erlang)的勇气,最好乖乖地,滴水不漏地处理异常,否则异常一层层 bubble,最后给你一个毫无理由的错误,你都没法解决。

需求变更

做拉条子的时候很少会遇见烦人的需求变更。如果顾客在你菜炒了 2/3 时说:欧巴,伦家不喜欢青椒,换尖椒好不?就算对方是九五之尊的娘娘,也可顶上一句:不早说,就这么着了,爱吃不吃!

不过偶尔熊孩子会冲进厨房让你给她转陀螺。这种小的范围蔓延(scope creeping)式的需求变更会吞噬项目的进度,让拉条子出锅的时间延后。

写程序,呵呵,也是很少会遇见讨人厌的需求变更。那是因为。。。

我给你讲个忧桑的故事。

话说东胜神州有个傲来国,以软件立本。因为软件的需求变更太多引了众怒,程序员们发动了占领华二街的运动,一度引发大家对世界和平的隐忧。国王一看这还了得,连忙下旨,凡产品经理者,只要对某个程序员进行需求变更 1024 次,程序员就可以拔下他的一颗牙。天性平和的程序员们默默地接受了。不料该旨意执行仅一个月,便被迫终止。原因是全国 78% 的产品经理都被拔光了牙,还有 2% 没被拔光的,是因为他们青春期多长了几颗智齿,还没来得及拔。。。

相比之下,剩下 20% 的产品经理毫发无损。因为程序员们厚道,抄起老虎钳子,瞄了半天,对女性还是下不了狠手。国王一看,这敢情好,立即大量从女儿国招募产品经理。圣旨改为:只要对某个程序员进行需求变更 1024 次,产品经理就必须和程序员共进一次浪漫的烛光晚餐。从此之后,世界和平了,需求变更从会影响人类前程和命运的核武,变成月老。据说傲来国新人都要一拜天地,二拜高堂,三拜需求变更了。。。

(本故事纯属扯淡,你要牙被打光了对号入座找程序君麻烦就是找抽)

天赋和努力

最后讲讲天赋。做拉条子不需要太多天赋,正如写程序不需要太多天赋一样。相比天赋,它们更需要努力练习,再辅以足够的思考,摸着其中的门路,也就是所谓的「道」,就可以随心所欲。就像庖丁跟文慧君所述那样:

臣之所好者,道也,进乎技矣。始臣之解牛之时,所见无非全牛者;三年之后,未尝见全牛也。方今之时,臣以神遇而不以目视,官知止而神欲行。依乎天理,批大郤,导大窾,因其固然。

如何得道?我也不知道。不过,我觉得跟程序君一起订阅「程序人生」,一同思考和练习,总归是没错的。:)


作者:陈天
链接:http://zhuanlan.zhihu.com/prattle/20634880
来源:知乎


回到

顶部