王益,蚂蚁集团研究员,开源项目SQLFlow 和 ElasticDL 的负责人。他从10岁开始写代码。曾经用自己焊接的电路板扩展“中华学习机”来把自家的老式“威力牌”双筒洗衣机改造成了自动洗衣机;用Apple BASIC语言和6502汇编混合编程写了人生中第一个游戏;高中自学了大学所有计算机课程,参加计算机水平测试,先后获得了“程序员”、“高级程序员”、“系统分析员”认证。王益从事 AI 基础架构工作十三年,先后在全球多家*互联网公司任职,亦曾在硅谷和北京两地创业。
王益还是知名开源项目SQLFlow、ElasticDL的负责人,虽已“高龄”,但仍对代码充满热爱,并经常写代码。以下是他的观点:
和每个程序员一样,我的十三年职业生涯里,每一天都在和 code review、design doc、bug reports 打交道。我在中国和美国互联网公司之间切换了多次,也在北京和旧金山两个机场间往复飞行了多年,其间唯一不变的是 —— 每天都要和写得不够好的技术文字战斗 —— 有我自己写的,也有同事们写的。
科学之母
为什么这么悲催呢?我有一个反思。我小时候听过老师们的很多谬论。最荒谬的是“学好数理化、走遍天下都不怕”。并列第一的还有“数学是一切科学之母”。很多年以后,我靠数学拿到了博士学位,然后发现身边很多学好了数理化的朋友们,在硅谷被印度同事干得一败涂地。而真正堪称科学之母的,是“逻辑”和“理性”,并不是数学。如果要清晰表达理性,需要的是语文。
因此,我宁可说“语文才是一切科学之母” —— 写不清楚论文的研究生都毕不了业,根本没资格研究科学。类似的,不能清晰表达逻辑的程序员,说不清楚自己的想法和贡献,没法得到晋升;甚至因为 deisgn doc 写不清楚,没法吸引同事一起做一个项目,也就无法带头;甚至没法吸引领导的注意和认同,无法立项。于是只剩下中年危机。
很多中国程序员没法加入到开源项目中来,自以为是因为“英语不好”。我的观察是,大概 15% 是因为英语技法问题,85% 还是因为逻辑梳理不清楚,换成汉语一样写不好。而我,虽然高考英语 148 分,也仍然在后来的求学生涯里经历了四年发不出一篇论文的精神折磨。
这里没有看不起谁的意思 —— 核心问题出在我们经历的教育*上 —— 当偏科理工成为理所当然,那就真的只培养螺丝钉,培养不出来领头羊了。
试举一例
看官怕不信我的危言耸听。那么我们试举一例。这是我负责百度 PaddlePaddle 项目期间,一位绩效很不错的年轻同事在一个 design doc 里的一句。
We propose an approach to prefetch parameter from Parameter Server while distributed training so that Fluid would training a model including the large parameter which could not be stored in one trainer's memory.
英语词法和语法问题:
prefetch => pre-fetch
would training => would train (其实这里的核心问题是逻辑问题,并不是虚拟语气的语法问题,下文详述)
parameter => the parameter(单数名词前需要有冠词)、或者 parameters(改成复数形式)、或者 the parameters(复数名词前也可以用冠词强调特定性)
逻辑问题:
Fluid 是 PaddlePaddle 的一个子项目。我们做 Fluid 不是为了训练某一个模型,所以 a model => models,用复数泛指不同用户训练的很多模型。
including the large parameter。数学上,一个 parameter 就是一个数字,用计算机表示就是 64 bits,不会 large 也不会 small。这里逻辑上把 parameter tensor 和 parameter 混淆了。可以说 a large number of parameters,也可以说 a large parameter tensor。
could not be stored in one trainer's memory。首先,PaddlePaddle Fluid 里的术语里,一个 trainer 是一个进程;而进程并不拥有 memory,所以不存在 trainer's memory 这个概念。这里作者想说的是进程的内存地址空间。不过行文逻辑和内存的地址空间也没有什么关系 —— a large parameter tensor 之所以存不下,就是因为一台机器的物理内存小,而不是某个特定进程的内存地址空间太小 —— 实际上,内存地址空间往往大于物理内存容量。
其次,这里 could not be stored in 只是说”不能被放进“,而没有说原因 —— 作者想说原因是”太大了所以放不下“ —— 这里的因果关系用英语表示可以说 too large to fit in the memory —— 可惜作者并没有表达出来,于是读者可能误会”不能被放进“的原因,比如”为了高效计算 parameter tensors 所以需要将其放进 GPU memory 里”。
当时一位在百度硅谷研究院工作的印度同事在 code review 这个 design doc 的时候帮着修改了一下:
We propose an approach to pre-fetch the parameters from a parameter server during distributed training so that Fluid is able to train models with parameter tensors that are too large to fit in the memory of a node.
这里我想强调的是:上述分析里,关于逻辑的文字量远多于关于英语的文字量。很多不完美的技术写作都是逻辑问题。
解决之“道”
写作是一门艺术。Donald Knuth 说人类的智慧分为几种境界,其中艺术是最高境界。
第一重境界叫技术(techniques)。对于一个问题,能给出一个解法的人就算达到这个境界了。这样的人叫 technician(技术工人)。
大部分程序员是这个级别的。
第二重境界叫科学(science)。经历了很多问题,提出了很多解法之后,技工可能会总结出一些规律,称之为理论(theory)。每个 theory 的出发点是一些抽象描述物理世界的公理(axioms)。比如欧式几何这个理论有五个公理,就是记录在欧几里得老师的《几何原本》(Elements)里的。从公理出发,大家可以按照逻辑可以导出很多推论(theorems)。很多推论恰好也符合对物理世界的描述。比如沿着欧式几何的公理,大家推导了两千多年,一些推理帮着人类把阿波罗发射到月亮上还能活着回来 —— 数学真是tmd一个巧合啊 —— 没事没事,语文才是科学之母。这里我要严正声明,这不是玩笑 —— 20 世纪人类最伟大的科学发现是哥德尔定理。用俗话说,就是沿着逻辑推导,推着推着一定会发现一个推论和之前的某个推论是相悖的,比如一个说老王家的鸡是公的,另一个说老王家的鸡是母的。所以,真的,用数学计算出来的阿波罗轨迹能把人安全的带回来,真是一个奇迹 —— 说它是公的,它恰好就是公的。
什么样的程序员可以算是 scientist 呢?给定一个问题,能分析设计出最优解法的,而不是随便给一个解法了事的。
第三重境界叫哲学(philosophy)。小学思想品德课制造的一个误区是让人以为哲学是文科,其实哲学是理科。理工科的硕士研究生毕业之后的学位是 Master of Science。而博士研究生毕业之后就是 Ph.D. 了 —— Philosophy Doctor(哲学博士),也有人说是 permanent head damage,也有道理,不是悖论。哲学是归纳了很多 theory 的人归纳出来的原则(principles),说的是怎么思考问题,可以归纳出好的 theories —— 别从公理出发刚推了没几步就出现悖论 —— 这tm多尴尬)。因为哲学是指导人们归纳 theory 的,所以我们说哲学原理(principles)是帮助我们拓展人类知识边界的工具。
什么样的程序员可以称为哲学家呢?有一套哲学思想叫 Unix Philosophy https://en.wikipedia.org/wiki/Unix_philosophy 。看进去就明白了。
第四重境界叫艺术(art)。Paul Graham 有一本书叫《Hackers & Painters》,说的就是最高境界的程序员和画家一样。徐悲鸿画的马,大家都说好!而且每个人都能说出一些好的理由 —— 比如简练却生动、比如线条刚柔相济、比如动感十足。既然人人都能说出来的评价标准,恐怕算不上 theories,估计可以算 techniques。徐老师无疑是大家!他也明白自己不同寻常,可是他却没法把自己的高才总结成一些 theories 或者 techniques,让徒弟照着弄就能画出一样好看的马。艺术家的直觉(英语叫 gut feeling,直译为猪肚和肥肠的感受)只可意会,不可言传。汉语里的“道可道非常道”,这个道不是 principles 而是 arts。老子不是哲学家,而是艺术家啊。
有些程序员,每次碰到一个难题,其猪肚和肥肠的都会有一些感受,照着这灵感做,总是没错,基本就是最优选择。如果他不是蒙的,那么他就算一个艺术家了。
写作技法
写作虽然是最高境界 —— 艺术,可惜作为一个程序员,语文并非我的专长,我只能算技工。我有几条技法,类似于欣赏徐悲鸿大师的画的时候说出来的那些评价标准,在此分享给大家,抛砖引玉,仅供参考。如果有高人能指正,升华成 theories 甚至 principles,可谓善莫大焉,提升了当代基础教育水平。
首先,篇章结构上讲究 层层递进。
作为一个知识分子,应该理解这个世界是分形的(fractal)。要说明一个事儿,得从大面儿上先把逻辑理顺。每个逻辑环节可能需要补充 evidence,每一层 evidence 是递进的一层境界。就像剥洋葱,一层一层往里剖析。
从行文上看,一篇文章各个章节的标题,应该存在逻辑关系。读者只看标题,就能明白文章大意。如果感兴趣,则看每一段的首句。这些首句连起来是递进的第二层,更详尽的逻辑。如果对某一段的首句感兴趣,再看其中的内容。
其次,文法上请讲究:环环相扣、滴水不漏。
环环相扣的意思是:相邻两句之间要有因果关系;相邻两段要有因果关系;相邻两节要有因果关系。因为因果的衔接就是逻辑。
滴水不漏的意思是:逻辑推理不可跳跃,不可以默认读者知道某一环节所以跳跃。如果要保持行文的精简 ,应该通过递进来做到,而不是跳跃。
然后,句法上讲究:尽量用短句,不要长句;尽量用简单句;不要从句。
相传白居易作诗要给老婆婆们读。反复修改到老妪能解,才发表。这倒是符合一条哲学原理,Occam's Razor,也是我的专栏名字。用汉语说叫“删繁就简三秋树”。我读书时崇拜 Bertrand Russell 的行文 —— 颇多从句,但却无力模仿 —— 不知怎么保持每个从句如此简短,而且用从句把逻辑编制得密不透风,同时保持繁简相宜。为免邯郸学步,还是学习白乐天老师吧。
句法的第二条技法是:一定要用主动语态,技术行文不可用被动语态;每句要有主谓宾 —— 汉语里被动语态比比皆是,英语里被动语态是用来表达强烈情绪的 —— 一个程序员怎么可以有情绪?面试官放水了吧?
最后说词法。规则最繁复。但是注意几条,差不多也就覆盖了常见问题的十之七八。
章节标题里的单词要 capitalize。但是 and 这些词不要 capitalize。迷迷糊糊搞不清楚的可以借助工具 https://capitalizemytitle.com/
专有名词要按照作者的写法来写。没有道理。
TensorFlow 的 F 要大写。Kubeflow 的 F 是小写。为什么 —— 没有为什么?因为他们的发明者一拍脑袋就这么定了。
单数名词前要有冠词。复数名词前可以没有冠词。但是也可以有,来表示特指。
一个缩写在文中第一次出现的时候,一定要有全称。比如 Machine learning (ML) is like chicken ribs.
言归正题
上文中颇多玩笑。但是写作是非常严肃的事情,是人生必备的技能。今天开源软件开发成了一种新的商业模式。MySQL 曾经是第一个开源商业项目,买了一亿美元。今天的开源项目的估值百亿美元者比比皆是。来自五湖四海的程序员,完全通过 code review 的方式合作,创造了 Linux 和很多其他重塑了人类社会形态的技术(Android、Chromebook、data centers)。在这个大教堂向大巴扎转型的时代里,一帮老死不相往来的程序员,完全通过写作实现 proposal、design docs、code review、和 issue tracking。从这个角度来说,语文是人类文明之母也不为过。
历史上每一个伟大的人类文明的语文都是逻辑。中国的科举,比的不是诗词歌赋,而是策论。策(战国策的策,也是湖南经视著名节目越策越开心的策)就是娓娓道来,也就是上文中的“环环相扣”;论就是推理严谨,也就是上文中的”滴水不漏“。诗词歌赋小说演义都属于杂书;不好好学习的人才看的,比如三国、水浒、西厢记、金瓶梅、金瓶梅、还有金瓶梅啦。藏传佛教有因明学。因就是因果,明就是说明白逻辑关系。古希腊就不用说了,整个社会制度建立在逻辑辩论之上。我们小学时学过一个为了练习发声,把小石子放在嘴里练习辩论的演说家。如果不记得名字了,他叫德摩斯梯尼。小石子只是他练习的一个小环节,为了具有说服大众的雄辩能力,他早年师从伊萨攸学习修辞,后来教授修辞学。今天的西方世界视古希腊为其文明源头;现代西方*制度仍然参照古希腊的制度建立。美国总统大选的路演和候选人辩论都是对德摩斯梯尼那时的规则的模仿。策论和因明是美国公立小学从学前班就开始的教育。我娃在疫情之前每周要做一个presentation。小屁蛋儿们的小手握不住鼠标,没法做ppt,都是手绘。疫情失学之后,她经常无聊地爬在后院枇杷树上和篱笆墙外遛狗的行人越策越开心。
以上,谨策。祝大家开心!
以上转载自SQLFlow专栏:https://zhuanlan.zhihu.com/p/151675013。