首发于迷思
在提高代码能力这事上,没有银弹

在提高代码能力这事上,没有银弹

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。 - 《道德经》

转眼间女儿到了学琴的年龄。我对乐器,纯是叶公好龙,家里摆着钢琴,小提琴,手风琴,自己却连五线谱也不识,所以无法督促丫头练习,于是这重担落在了老婆身上。老婆是个虎妈,严厉起来毫不含糊,说练不完琴不许吃饭,就不许吃饭,丫头撒泼打滚,哭天抢地,姥姥红着眼圈在旁劝阻都无济于事。这种时刻,我自然是于心不忍,明面里却必须和老婆保持高度一致,所以只能默默地滚到一边,安安静静扮个风轻云淡的土肥圆 —— 心里还是会忐忑:这么搞法,不会把娃儿的兴趣折腾没了吧?

然而我的担心是多余的。丫头周六学琴,往往周六和周日最苦,哭嚎也是这两天最甚。这是因为学了新的曲子,她还不熟,经常弹错,弹错就要重弹,老师布置的作业要弹很久很久才能过关。到了周二周三,她渐渐熟络了,指下生风,哭嚎声越来越少,周四周五就游刃有余了,多数情况都能开开心心地弹完。因为妈妈的严厉,她起初吃了不少苦头,但渐渐苦尽甘来,尝到了那种「直挂云帆济沧海」的爽快。在最痛苦的时候,她大哭着叫唤「妈妈我再也不想弹老师布置的作业了」,可在一月一度的「家庭演奏会」上,她还是会喜滋滋地,满满成就感地向远在国内的亲人们展现她的能耐。

好多同学在后台问我,代码的能力怎么练就。其实是一样的理儿。多练,多读,多写。

软件开发的教育作为一门非常年轻的学问,仅仅走过了几十年,和钢琴教育数百年的历史相比,是沧海一粟。钢琴有成熟的培训和认证体系,软件至今还是撞大运。其实想想钢琴和软件有很多相通之处:学钢琴需要先学习一门指法,和一门语言(五线谱);学代码也需要先学习一门指法,和一门语言(比如 python)。钢琴的 hello world 是 「哆来咪发咪到来」,软件的 hello world 是,额,hello world。练好了钢琴的基本功,你可以按照某些需求,创作出曲子来;练好了代码的基本功,你也可以照着需求,写出合适的代码来。

可是写代码并不需要像练钢琴那样,讲究把基本功练得谙熟,各种知名的不知名的曲谱练过一圈,一级一级打怪升级,直到所谓的钢琴十级才算出师;往往一门语言或者一个框架,了解了如何使用基本的结构,程序员们就按捺不住,开始上手了。函数不会用,有 google 哩,代码不会写,找 stackoverflow!于是对代码所服务的对象而言,写代码成了一项高风险的活动:我们极其依赖代码的作者碰巧是个能力不错的人,她能在一边完成高质量创作的同时,还可以夯实自己的基本功。

比如说一个简单的任务:遍历一个 list,解析出里面的 tuple,然后将其插入到 priority queue 中排序。

一个有多年经验的软件工程师的做法是(假设用 python 实现):

  1. 大致想想就开始撸袖子写代码;
  2. 囧,不大记得 map 的用法了,究竟第一个参数是 function 还是 iterator,让我先在 ipython 里试试 —— oh,原来第一个参数是 function,看我这记性;
  3. tuple 用得少,如何取 tuple 里面第二个元素,这我得 google 一下 —— ah,原来可以 destructure,赞!(顺便鄙视一下 php)
  4. python 有 priority queue 的支持么?我没用过嗳,没事,祭出 stackoverflow —— python 真心棒,连这个都有现成的 heapq,stackoverflow 这段代码正好是我要的,才五六行而已,直接 copy & paste。一下子就写完了,yeah!(顺便鄙视一下 php)

憋笑,我敢打赌这是不下半数工程师的日常。事实上,这个例子并不是我瞎编的,而是我在过去一年的面试中,大多数所谓「资深软件工程师」在面试中的表现:在很多基础的函数上卡壳,不得不 google。这并不算太糟糕,我见过从第一行代码一路 stackoverflow 到最后一行的。

我不知道文字行业是怎么面试的,如果一个面试者现场写段文字还要查字典,翻《古诗词大全》,能过关么?

我们究竟该怎样正确地写代码?

在「创作」新的代码之前,我们就应该已经对如何写代码了如指掌 —— 语言的基础知识,经常使用的类库都不该成为障碍。整个撰写代码的过程是流式的,就像作曲一样,思维飘到哪,手指就落在哪,一气呵成。当然,这有赖于平日里刻意的练习:不知道如何使用 map?OK,分别给定一个 list,dict,tuple,用 lambda 和不用 lambda 将 map / filter / reduce 各处理一遍。

听着很熟悉,是不?小宝的钢琴作业老师就是这么布置的:左手哆咪骚哆咪骚练十遍。这「哆咪骚」就像咱们的 map 函数一样,是基本功。

那位说了,这么做成材期长,成百上千的类库,永无止境的版本升级,每个都练十遍咱程序员伤不起,不现实。

你看,程序员就这么傲娇,三个月培训一下就能拿相对的高薪(硅谷的现实),还要让我做这枯燥的练习,凭什么?

那么我们折中一下,当我们撰写上述的代码时,起码把忘记了怎么使用的函数在 REPL 里好好练习一下;再把从 stackoverflow copy & paste 的代码自个写一遍,里面涉及的类库,函数,在 REPL 里多多练习练习,以至于下次再遇到同样的需求,不至于还要网上寻找答案,这不过分吧?

愿意这么做的依然是少数。

经常跑马拉松的人往往以赛促练。能够以赛促练的人,首先得有大量的训练基础,才能承受一轮又一轮相对密集的比赛。有了这个基础后,比赛进一步将自己的身体调节到合适的节奏,夯实心肺,锤炼肌肉,同样起到了练兵的效果。如果拿跑马拉松类比,我们在日常工作中做的每一个大 feature,都可称得上一次比赛,如果平时不好好积淀,这时而过就显现了:别人一个 sprint 高质量完成的东西,你两三轮 sprint 还做得磕磕绊绊,代码活脱脱是 stackoverflow 的剪辑册。

从直观的感觉来说,软件开发应该比跑马拉松更容易以赛促练,甚至,以赛代练 —— 你做的每一个 feature,都能帮助你夯实你的技能。当然,这个前提是你每周都有大量的代码量来兜底。写的代码多了,总会重复使用一些重要的函数和类库,于是,正确使用它们的能力得到了强化。可惜,对很多很多的软件工程师来说,这是个伪命题:

  1. 你一周其实真实代码量并不大。你的大部分时间被消耗在了维护一个大型系统上,平均一周写不了两三百行代码(注意不是 diff)。别忙质疑这个数字 —— 我在 Tubi TV 两年,从零到一做了三四个系统,node 和 elixir 合并在一起,满打满算也就是四万行代码,两年一百周,平均每周撑死了四百行代码。
  2. 即便你代码量不小,如果你负责的 scope 很小的话,写多了也是重复劳动 —— 就像练字,别人是一千个字每个练五十遍,你是一百个字每个字练五百遍,同样是五万的量,下的功夫一样,效果却大相径庭:别人亡口月贝凡已经练得谙熟,你还在比划个十百千万。

在提高代码能力这事上,没有银弹,有的只是像钢琴训练那样的 deliberate practicing。没有 practicing,你会败在 1) 上;practicing 够了,但不够 deliberate,你会败在 2) 上。

所以还是那句话,多练,多读,多写,撒一层土,夯实,再撒一层。工作给不了你的,台上没工夫练的,你要在业余时间,在台下,把它找补回来。这才是代码能力提升的奥义。

谢谢欣赏。

编辑于 2017-11-20 10:38