本节书摘来自异步社区出版社《程序员的呐喊》一书中的第1章,第1.6节,作者:【美】Steve Yegge ,更多章节内容可以访问云栖社区“异步社区”公众号查看。
1.6 神秘机器的笔记
程序员的呐喊
过去8年来(2004年6月起至今)我一直在写各种各样的牢骚,主要是一些和软件工程有关联的问题。
之所以这样愤青是因为我真的被一些“诡异”的世界观给搞糊涂了,持这些观点的人(在我看来)差不多占了所有我遇到过的程序员的一半,包括网上碰到的和现实里认识的人。
就在上个星期,我终于想明白了这个困扰了我快10年的问题,现在我知道它到底是怎么回事了。
今天这篇文章就是要以全新的理念来展示软件工程。这些东西其实一点就通。等你看到的时候肯定想抽自己一嘴巴,怎么早没想到!或者抽旁边的人。要么就是你已经有那个意识了,只不过没有显而易见而已。
以我30多年的从业经历来看,就算这种思维不是我首创,它也从未进入过主流。我敢这么说是因为放狗搜了十几次都一无所获。所以对这一点我相当肯定。
而我现在就要将它带入主流。看好了!
另外,接下来要传授给你的这种思维模式可能会立刻,而且永远成为你手上最有力的工具之一,特别是在和其他程序员交流,或是谈论他们的时候。
经典的TL;DR 1
好了,不吊胃口了。首先让我阐述一下论题。我多年来从亚马逊到Google牢骚不断主要就是因为这个。
(注:我的话和公司无关。这一点无须赘述。假如公司需要发言人,他们自会去雇用索伦之口那种人 2 ,保证大家知道他们可以代表公司发言。)
我的论题如下。
1.软件工程有自己的政治轴心,一端是保守派,另一端是自由派。(注:假如你没耐心读长篇大论的话,理论上你已经完成90%啦,可以不用往下读了。)
2.这里提到的“保守派”和“自由派”概念是针对软件工程而言的。不过在一定程度上他们和现实世界里的政治还是非常相似的。
不管有没有意识到,软件业里从事和编程相关工作的每个人都能在这根轴上找到位置。
换句话说,你要么是自由派程序员,要么是保守派程序员。或许偏中庸一点,又或许极端一点,但基本上都分布在轴心两端。
和现实世界里的政治一样,软件里的保守主义和自由主义同样是迥异的世界观。这意味着他们就像针尖对麦芒一样。他们的价值观、看中的事物、核心理念,乃至动机都是完全对立的。这种价值观的冲突充斥设计阶段、是实现阶段、诊断阶段,还有恢复阶段。就好像绿鸡蛋和火腿一样。 3
我认为认识并了解我们行业中保守和自由的区别是非常重要的。或许这无助于我们达成共识,否则也不用做什么区分了。只要是本质上不可调和的观点,任何争论都可以套用这个政治轴心。程序员基本上不会(大概也不可能)改变自己的核心价值观。
不过这套政治轴心的理论让我们得以利用大家都熟悉的观点和术语来界定分歧中本质的部分。这样就能更快地解决矛盾。只要能迅速将问题归结为某个大家都明白的政治问题,那么就可以省下试图说服对方改变想法的时间,直接进入解决问题的阶段,(和政治一样)这常常意味着讨价还价和妥协让步。当然了,还有一种手段,水门,你懂的。 4
真实世界里的政治和软件行业里的政治相关吗?
政治上的保守倾向会让一个人在对待软件上也趋于保守吗?到目前为止,我觉得我们只是在依靠直觉。而任何有科学依据的结论是都离不开研究的。
不过我的直觉告诉我,即便真的存在相关性,也不会很高。我怀疑政治上的左右和软件上的左右所产生的 4 种组合在编程界里大概各占25%,误差不超过8%。当然这只是完全没有科学依据的猜测,要是有真实数字的话,我很乐意了解一下。
之所以认为它们没什么相关性,是因为我觉得一个人的软件政治观主要受两股力量支配。
1.之前的编程经历——具体说就是那些让他们失败或大获成功的决策。
2.他们的老师、教授、导师、榜样,还有同事所拥有的软件政治观。
不过有些因素的确能增加政治取向和软件取向的相关性。比如地域和区域的影响——比如,自己就读的科技型大学位于红州还是蓝州。 5 另外,性格也可以让一个人拥有偏向传统的自由派或保守派的价值观。
无论如何,很多程序员在发现自己政治上很保守,软件上却很自由(或者反过来)的时候肯定会大吃一惊。
不是说两党体系是有缺陷的吗?
好吧,是没错啦。硬把政治观点这种具有微妙差别的东西套到一维空间上实在是过分简化了。比如,一些美国人觉得自己在经济上很保守,而在社会问题上观点却比较自由,所以并不存在坚定支持两党之一的情况。尽管研究表明人们很容易相信极端的观点,但这种所谓的“摇摆选票”却往往成为温和派赢得大选的决定因素。
而温和派在软件工程界里的影响力也同样不可忽视,所以后面我们会继续深入探讨。
不过就算在一维空间上,仍然能从左到右得到很分散的分布。和真正的政治一样,就算是稍稍右倾的观点,对极右的人来说也可能是让人绝望的自由派。我在后面举例的时候会给出几个现实世界里有名的编程语言问题。
不管怎么说,即便有点过分简化,我仍然觉得两党模型对政治和软件的教育是个不错的起点。它建立了一个很好的框架,方便以后进一步完善模型,当然这已经超出本书的范畴了。
那么到底什么是软件自由派/保守派呢?
不妨先忽略现实世界里一些特定的问题,把注意力放在现实世界的保守派和自由派所拥有的特质以及价值观上,你会发现其实本质的东西就那么几点罢了。而这几点东西也恰恰是软件政治里的基本。
我们先从比较容易说的保守派开始,然后那些不是保守派的自然就是自由派了。之所以这么说,是因为保守派通常具有清晰统一的价值观,而自由派则比较散漫,仅仅是为了对抗保守主义才联合在一起。无论是现实世界还是软件世界里的政治都是如此。
首先我们来看一下约斯特教授等人给保守主义下的定义: 6
“我们认为政治上的保守主义是一种意识形态上的信仰,主要(但不完全)是和有意识地调节不确定性和恐惧的心理有关。”
加尼教授等人在2008年的研究“自由派和保守派的秘密:性格、风格,以及被他们遗弃的东西”里,探讨验证了这个理论。
我希望你也觉得这个定义没什么好争议的。毕竟“保守的”这个形容词基本上和谨慎、厌恶风险就是同义词。金融上的保守主义常常(也是显而易见的)和年龄以及财富联系在一起。公司会随着时间逐渐变得保守起来,因为它们熬过了各种法律诉讼、技术失败、公共危机、金融风暴等危机。连蚂蚁和蚱蜢的寓言故事都告诉我们寒冬将至,要储存食物。
本质上,保守主义就是风险管理。
同样,自由派的观点常常和年轻、理想主义、天真无邪联系在一起。在企业里,创业公司往往是典型的自由派——部分原因是他们本来就是为了(在一定程度上)改变世界而存在的(而自由主义原本就意味着变化),另一部分则是他们必须全力以赴完成投资人设定的目标,所以放弃一点软件安全也就变得合理(不得已)了。
自由主义并不适合作为根本的动机,不过我们不妨把它想象成一种信仰,一切都是为了改变。商业化的说法就是为了改变世界。在软件行业里,自由主义主要是为了以最快的速度开发出新功能,同时又能保证系统的灵活性,这样开发过程就不会被拖慢或是受阻。
当然啦,保守派也是以此为目标的。不过他们的做法……很保守。灵活性和生产力仍然是动机,但是不再是主要动机。安全才是最重要的考量,性能常常也是软件保守主义者眼里非常重要的东西。
软件世界里自由派和保守派的根本分歧就在于:到底要在安全性上下多大功夫?这里说的并不仅仅是编译时的类型安全,还包括更广义的大规模系统上“防止小白误操作”的安全性。
下面我们用一些例子来说明这些本质上的分歧,保守派比自由派更看重这些理念。
软件在发布之前应该尽量修复所有bug。(标语:“不要调试!”)确保为所有的类型和接口建模,编写完整的测试,系统发布之前要有明确的规范。不然的话就有你好看的!
程序员应该回避错误。很多语言特性从本质上来说都是很容易出错和危险的,所以应该被禁止用在我们的代码里。没有这些特性我们一样可以进行开发,代码也会因此变得更安全。
程序员学不会新语法。公司里可以使用的语言数量应该受到限制,这样万一系统在半夜或是圣诞夜挂掉的时候,值班的人就不需要去临时抱佛脚学习新语法了。另外,我们也应该禁止那些能让你定义新语法,或许改变现有语法语义的特性。(常见的例子:禁止操作符重载,禁止元编程!)
产品代码必须通过编译器的安全检查。不能进行静态检查的代码通常是不可接受的。就算真的有必要,也必须事先得到中央委员会的同意。(例如,eval、动态调用、RTTI)。
数据必须遵循事先定义好的格式。关系型数据库必须满足第三范式,必须遵循UML或等价的格式定义。所有的XML都必须有DTD。NoSQL数据库和键值存储(一般来说应该避免使用)必须有单独的格式定义,标明所有允许的键,以及相应的值类型。
公共接口必须严格建模。数据绝不可以保存在字符串或是无类型的集合里。所有的输入输出实体都必须完整显式地定义为可以静态检查的模型,最好是面向对象模型。
生产系统里绝不允许存在危险或有风险的后门。想要通过调试器,telnet shell,或是任何接口连接到工作中的生产系统,去修改运行时的代码或数据应该是不可能的。生产系统里唯一允许开发的接口只能是只读的监控频道。
假如一个组件的安全性存在任何疑虑,那它就不能发布上线——不管团队怎么哀求哭嚎说没它没法继续工作。(我说的就是你,FUSE)。
快比慢好。没人喜欢慢的代码,所以代码的性能一定要好。从一开始你的代码就应该奔着最优速度去写,否则就有可能不够快。凡是那些据说比较慢的语言、DSL、库,都应该避免使用。就算能满足现在的需要也不行,需求(或者说调用者)总是在变化的,可能突然软件就会变得太慢了!
这些例子只是为了说明我的意思,实际情况要复杂得多。另外,也不是所有自认为是保守主义者的人都认同这些例子。不过除了少数例外,这些都是非常典型的保守派观点。
判断一种理念或技术属于自由派还是保守派,只要去检验一系列独立的“安全性条款”即可。假如大部分都符合的话,那么总体来说它就是倾向保守的。符合的越多就越保守。
下面列出了以上9个例子的自由派版本,权作比较。假如你愿意的话,可以把他们想象成《史酷比狗》里的角色。弗莱德会持上面的观点,而下面的例子则属于薛吉。
有Bug没什么大不了的。反正不管多努力,bug总是无法避免的,而生活还是会继续下去。优秀的调试器绝对是好东西,任何方法也不能像分步执行代码那样让你对自己的代码有深刻的认识。调试和诊断是高难度的艺术,每个程序员都应该去掌握它们。所谓的圣诞夜当机这种事情其实永远也不会发生——不然要代码冻结来干什么。有Bug没什么大不了的!(这一条大概是区分保守派和自由派理念的关键所在。)
菜鸟不可能永远是菜鸟。稳健的程序员生涯肯定离不开聪明地工作,保持学习的动力,富有创造力,知道怎么获取资源,以及拥有老道的经验。为了避免菜鸟失误(或受到伤害)就立下一堆规矩,完全是头痛医头脚痛医脚的做法。
在工作需要的时候,程序员的学习能力是惊人的。很多人都掌握了五线谱、盲文、手语等各种符号系统,甚至连大猩猩都能学会!所以根本没必要“保护”程序员远离新语法。只要有文档,有时间,他们自然能学会。
简练就是力量。代码应短小精悍。静态检查工具无法理解你的代码不是把代码写得又臭又长的理由,而是应该(比如,通过融合运行时数据)去把检查工具做得更聪明。
严格的数据定义只会妨碍灵活性,延缓开发进程。更好的策略是定义轻量级的数据定义,或者只定义一部分,甚至先略过它。因为在收集到大量数据,分析过大量用户案例之前,没人知道数据应该怎么定义。所以数据未动,代码先行才是正确的做法。
公共接口应该尽量简单,向前向后都兼容。建模时太过缜密的话,其实只是在猜测接口会怎么演化而已。这样反而顾此失彼,两头都无法兼顾,导致接口频繁修改,客户也不会高兴的。公共接口应该以极简为目标,能完成需求即可,增添新接口必须谨慎。
系统的灵活与否能决定一个客户,(或者合同)是归你还是被对手抢走。至于生产系统上的安全隐患,则可以通过日志、监控、审核等手段来缓解控制。事实证明,很多有最高权限后门和shell的大型系统(比如,一些数据库和网游服务器)都做到了在控制风险的同时具备世界顶尖水平的运行灵活性。
企业要敢于冒险,拥抱进步,警惕僵化。这和企业的规模没有关系:逆水行舟,不进则退。要保持竞争力,唯有不断有意识地去承担风险,接受随之而来的阵痛。灾难是无法避免的,所以你得做好准备,想办法从失败中再站起来。其实就算不会去冒险,这些手段仍然不可或缺。既然伸头缩头都是一刀,那还不如冒险一试呢!
过早优化是一切罪恶之源。让代码先跑起来再说,正确性比性能重要,而原型迭代又比正确性更重要。只有当客户将延时列为首要解决的问题时,你才应该去考虑分析性能,进行优化。
这就是薛吉和弗莱德的不同了。
和现实生活里的政治一样,软件自由主义者在保守派眼里就是一帮邋里邋遢,缺乏纪律,天真无邪,没有原则,彻头彻尾的“坏”工程师。而保守主义者在自由派眼里则是偏执狂,是只会散播恐惧、自欺欺人的官僚主义者。
重申一下,尽管我觉得这两个阵营永远不会达成一致,但是相互理解一下对方的价值观仍然有助于双方达成妥协。
最低限度,这种保守派和自由派的分别也能帮助彼此避开对方。我觉得一支和谐的团队最好是由单一人群组成,要么全是自由派,要么全是保守派,免得双方不停地发生理念上的冲突。这就好像每个地区的驾驶风格都不同一样——霸道一点没关系,大家都一样就行了。
照你这么说,安全工程师肯定是最保守的了,是吗?
错!事实正好相反。我提到它也是想说明在看待工作内容的时候,我们的直觉有多糟糕。
安全工程师非常关心风险评估以及攻击面(attack surface)管理,所以会给人以倾向软件保守主义的印象。
然而实际上安全工程师往往非常清楚谨慎和进步之间的利弊权衡,因为他们整天都在和软件团队打交道,而软件工程师通常都忙得要死,没时间去关心安全性(更别说相关知识的匮乏了)。安全工程师在熟悉实际情况后,能迅速做出切合实际的风险管理决策,而不会为了安全而保守。
因此很多安全工程师其实都是软件自由主义者,至少也是倾向自由派的。
Google的很多安全工程师也都是Ruby的粉丝,Ruby不但本身就是一门安全性很高的语言,同时也非常好用,表达能力很强,非常适合编写审核脚本等各种安全分析工具。我在Google的第一个项目就是用Ruby写的,通过安全认证还是很简单的。可是要得到我们那些非常保守的系统工程师的认可就真的比登天还难。
事实上几乎任何编程领域都可以分出自由和保守两个阵营。Web程序员、数据库工程师、协议工程师、服务系统工程师等各种编程的细分子类都能分出左翼和右翼来。
我很难想象有什么领域是完全倾向自由派或是保守派的,除了网站可靠性工程,这个从本质上来讲就是一个偏保守的职位外。至于其他领域,尽管乍一看似乎清一色(比如数据分析师,我一开始觉得他们肯定全是自由主义者),但后来都有接触到某个团队或细分领域是完全相反的情况。
所以我觉得这大概还是个人喜好的问题吧。肯定是的。行业领域不是决定性的因素,完全是性格使然。
有的人生来就是自由派,而有的人天生就是保守派,没什么道理可讲。
严正声明:在继续之前,我要发布一条重要的声明,我是一个死硬派软件自由主义者,甚至有点(但不完全是)自由极端分子。
这也(主要)是我会发那么多臭名昭著、争议性很强的牢骚,比如“名词王国里的执行”、“菜鸟的肖像”、“犀牛和老虎”、“代码的死敌”、“Scheme就是信仰”、“巴别塔”、“动态语言反击了”、“变形”、“Haskell研究员宣布了业界程序员也会关心的发现”等文章的原因。
我当然也会写其他东西。比如我正在写的“程序员的宇宙观”系列就来自不同的灵感,和软件政治学一点关系也没有。
而“通用设计模式”这篇东西则超越了软件政治学,无论是保守派还是自由派都能有效地利用其中提出的技术。另外,我也会写写电子游戏、日本动漫等其他话题。
不过我也清楚心里的自由主义对我的思维有多大的影响。就算在讨论管理的时候,我也自认为是一个自由派的经理,而非保守派。另外,尽管我年纪不小了,生活也算富裕,但我的政治观点在面对社会问题和经济问题的时候仍然是偏自由的。
不管怎么样,我会尽量在本文里公平准确地将双方观点都表述清楚。我也只能尽力而为,你懂的。最重要的是你要自己看清楚左右的区别,同不同意我对某一边的看法倒是其次。
只要有足够多人的同意软件工程上确实存在自由派和保守派的区别,我对不同技术和理念的左右区分看起来是合理的,那这篇文章就算没白写。哪怕个别细节上有不同意见也没关系,只要大体上同意我的观点就可以了。
那么……静态类型爱好者应该算是保守主义者了?
没错,的确如此。静态类型毫无疑问是软件政治观点的分水岭,更是保守主义世界观的特征。
站在保守派的角度,静态类型(不管是显式的还是推导的)都是现代软件工程里必不可少的组成部分。这一点是不容置疑的。这里完全没有商量的余地:它是公认的工程实践(Acceptable Engineering Practice)的基石。
在自由派的眼里,静态类型就是安全闹剧(Security Theater)的同义词。它存在的唯一意义就是让人“感到”安全。人们(还有机场)已经屡次证明,就算没有它,统计数据显示的安全程度仍然是一样的。不过人们就是需要它才会觉得“够安全”。
这个问题的分歧非常大——不管你怎么看问题本身,这一点你还是能看出来的。
我之前的很多文章都谈到过这个问题,所以这里就不再重复了。要是到现在我还没能说服你,再费口舌也没什么意义。我尊重你的意见。与此同时,也希望你能多了解一点我的观点。
对了,我应该提一下一个无关的(政治立场中立的)观点,两个阵营都同意:有静态类型的话,工具链的支持会比较好。时至今日,这还是一个无可争议的事实,而我会尽我一生的努力消灭这个差距。
过去4年来我一直在Google内部主导所谓的“格洛克计划”(Grok Project),或许有一天它会冲破高墙,走向世界。这个项目的唯一目标就是让所有语言、客户端、构建系统以及平台都具备同等功能的工具链。
(下面的内容包含技术细节,没兴趣的话可以跳到下一节……)
这个项目的目标非常宏伟,甚至有点狂妄自大。它通过规范与语言无关,或者说跨语言定义,进而标准化工具链里几个重要的部分来完成。这些部分包含了:(1)编译器和解释器的中间表示和元数据;(2)编辑器客户端到服务器之间的协议;(3)源代码的索引、分析和查询语言;(4)在构建系统、源代码文件和代码符号等各个层面上细致的依赖规范。
好吧,这还不是全部,但大致上就是如此了。
Grok 绝不是你想象中的“小”项目。我在上面会花费相当长的时间。这 4 年里,项目已经经历了好几个重要的阶段,从“寻找风投”,到“接受”,再到“谨慎地热情”,以及“天哪,好多内部甚至外部项目现在都离不开我们了”。最近我们的团队也膨胀了一倍,从6名工程师增加到12名。每年(甚至每季度)我们都能获得更大的动力,我们的代码索引也变得越来越丰富。
Grok不是保密项目。不过我们也还没有在公开场合下提到过它,至少现在还没有,因为我们不想太早把大家的胃口吊得太高。在此之前还有太多的工作要做,我们自己也要试用过以后才会考虑公开的事宜。
为了让这篇文章更有看点,我大胆假设,10年之后,实现一款优秀的工具链不再仰赖静态类型。
尽管到那时类型系统的争论依然不会停歇,保守派们也可能永远无法就到底哪种类型系统最能反映程序的行为达成共识,但至少我为之贡献了自己的观点。开发工具的质量应该不再属于争论的范畴。
划分
接下来我会提及一些技术、模式、设计、规范等,将它们划分到以下6种类型里去:“无关政治”、“保守派”、“中间派”、“自由派”,以及中间偏左和偏右。每个类型都会提到。事先声明,这可不是什么严肃科学。这样划分只是为下面更详细的例子做铺垫。
无关政治的例子有算法、数据结构、具体数学、复杂度分析、信息理论、类型理论、计算理论等。基本上所有计算机科学的理论都属于这个类别。这些东西偶尔会在学术界激起千层浪,但就算真有什么,也只是小范围里的局部冲突而已,没什么大不了的。总的来说,这些基本的数学理论都是不朽的东西,不管是自由派还是保守派都会全盘接受它。没错,包括类型理论。
保守派的例子有久经考验的类型系统,强制性的静态类型标注,非public的符号访问修饰符(private、protected、bewareofdog等) 7 ,完整严格的数据定义,all-warnings-are-errors 8 ,尽量采用显式操作DOM或是手写状态机的方式,编译依赖限制,API被标记为过时后应该立即生效,数字类型之间禁止判断相等(也就是说没有自动类型转换),强制异常,一趟扫描的编译器,软件事务内存(Software Transactional Memory),基于类型的函数重载,显式的配置优于约定,纯函数式数据结构,任何带有“演算”(Calculus)字样的编程。
中间派(或完全中立的)的例子有单元测试,文档,Lambda,线程,Actor模型,回调,异常,Continuation和CPS(Continuation-Passing Style) 9 ,字节编译,即时(JIT)编译,只有表达式(没有语句)的语言,多重分派(multimethod),声明式数据结构,文本化的数据结构语法,类型分派。
自由派的例子有Eval,元编程,动态作用域,all-errors-are-warnings,反射以及动态调用,RTTI,C语言的预编译器,Lisp宏,(大部分的)领域专用语言,可选参数,可扩展语法,向下转型,自动转型,reinterpret_cast,自动字符串化(stringification),不同类型之间的自动转换,Nil/null是具有语义、可重载的值(即可以表示空列表、空字符串等其他不存在的值),调试器,位段(bit field),隐式转型操作符(如Scala的implicit),60趟扫描编译器,导入整个名字空间,线程局部变量,值分派,以参数数量区分的函数重载,混合类型的集合,API兼容模式,Advice(AOP中的概念)和AOP(面向切面编程),约定优于显式配置。
中间派偏保守的例子有类型建模,关系建模,对象建模,接口建模,函数式编程(即函数没有副作用)。
中间派偏自由的例子有动态加载类和代码,虚拟方法分派,面向缓冲区编程。
哇,这么分门别类实在是太好玩了!虽然如上所列远不完整,但是我想你应该明白我在说什么了。
自然而然的,我们就有了下面的一些结论。
隐式通常都是自由派所追求的,而显式则一般属于保守派。
首先考虑性能的通常都是保守派,推迟优化的往往是自由派。
编译时绑定属于保守派,运行时绑定或者推迟绑定属于自由派。
并发和并行看起来似乎是很有争议性的话题,但其实和阵营没什么关系。
我很想继续划分下去,可是我们还有更高层次的东西要讨论,不妨先到此为止吧。
一些案例和分析
下面我要举出一些例子,你看了就会明白这种政治现象的影响有多深远。
案例一:语言
下面是一些很粗略的分类。注意,每种语言阵营下通常还要细分出自由派和保守派。不过总体来讲,语言的能力和擅长的方面决定了语言的选择,因此语言特性促成了它的文化。
这份列表仅仅让你有一个具体的概念。我只罗列了通用语言、DSL和查询语言的性质太过特殊,往往难以分类。
难以言喻的自由:汇编语言。
极端自由:Perl、Ruby、PHP,脚本。
非常自由:JavaScript、Visual Basic、Lua。
自由:Python、Common Lisp、Smalltalk/Squeak。
温和自由:C、Objective-C、Scheme。
温和保守:C++、Java、C#、D、Go。
保守:Clojure、Erlang、Pascal。
非常保守:Scala、Ada、Ocaml、Eiffel。
极端保守:Haskell、SML。
上面的分类是根据我自己使用语言的体验,加上它们各自社区的特点而得出的。你大可有自己的感观。不过我很难想象你会把任何一门语言上移或者下移超过两个位置。
值得一提的是,静态类型,乃至强类型和一门语言是不是保守其实没什么必然联系。这一点先按下不表。
另一点值得注意的是,自由和温和的语言都很流行,而语言越保守就越不流行。
我觉得这并不难理解:自由的语言上加一点保守的成分不会很难,反过来就不行了。
例如,在Javascript里避免反射、eval、自动类型转换、原型继承等动态特性的代码是很容易读懂的。你完全可以用写Pascal的方法规规矩矩地写Javascript,虽然它不具备静态类型标注,不过只用断言、单元测试以及一板一眼的方法来组织代码也能达到同样的效果。
可要是你想在Haskell代码里玩出一点动态的感觉,那要做的工作可就多得多了。Haskell的狂热爱好者已经实现了动态代码加载等很多表面上看起来很动态的特性,但是其中所付出的努力可谓艰巨。
更有甚者,如果你用保守的方法来用自由的语言,人们最多会说:“好吧,这代码看起来真无趣,其实用一点动态特性的话,你可以少写很多代码呢。算了,反正这么写也没错。LGTM。” 10
可要是在保守的语言里玩一点野路子,就有被大家鄙视的危险了,因为……你干嘛要用这么危险的动态特性呢?我下面聊Clojure的时候还会进一步聊聊这种文化现象。
最后一个有趣的地方是很多非常流行的语言只是温和保守——和那些非常动态的兄弟姐妹比起来,甚至有些还自认为是相当保守的。
这里我要再次强调C++、C#还有Java这样的语言之所以能在市场上取得巨大的成功,完全是因为它们知道怎么左右逢源,这一点和真正的政客是一样的。
向往自由的程序员可以把C++当成C来用,而偏爱保守的程序员则可以有各种静态类型建模的手段可以用,用到什么程度完全取决于他们需要多少安全感。Java呢?基本上也半斤八两。
同时具备“随心所欲”和“随手关门”两种思想已经被证明是获得市场认同的关键所在。营销也是一样,它的作用是要让自由和保守两大阵营都觉得它契合自己的理念。
现在市面上还有一种新型语言(如Google的Dart,还有新版的EcmaScript),专门针对中立人群(而且为了刻意讨好自由派和保守派)提供了可选的静态类型。理论上这是个不错的想法,不过操作起来我觉得还是要看营销做得到不到位。而这往往都很让人失望。
语言的设计者似乎都低估了营销的重要性!
案例二:科技公司
娱乐一下,我们来比较一下4家相似的科技公司的软件政治观。
(1)Facebook——诊断:极端自由。Facebook的规模已经很大了,可他们的行为处事仍然像是一家创业公司,而且到目前为止似乎也活得挺好。他们用得主要是C++和PHP,而且很喜欢炫耀自己的代码怎么在PHP和C++之间调来调去,而这大概是最糟糕的地方了。他们的数据都放在memcached里:只有键值对,没有数据库结构。他们把数据导出来放到一个后台Hive数据仓库里,然后用Hadoop来进行离线数据分析。每两个星期左右他们仍然会举办通宵黑客马拉松,反正他们的程序员大多都是单身男青年(至少我上次去参观的时候还是如此),股票的估值也还很高(我上次查价格的时候好像已经没那么好了)。作为一家公司,Facebook是非常紧密的,具有很强的执行力,十分注重程序员在网站上发布新功能的单兵能力,没有什么官僚主义。这对一家规模这么大、用户那么多的公司来讲是难能可贵的。保守派毫无疑问会厌恶蔑视他们。但是Facebook证明了不管具有什么世界观的程序员,只要联合起来,就能解决很多问题。
(2)Amazon.com——诊断:自由。以它的年龄、年收入、成熟的运营部门,以及财务方面的保守性来讲,这算是很令人意外的了。但事实上和早年相比,说它“自由”已经算客气的了。1998—1999年的时候它和Facebook几乎一模一样,唯一的区别是当时他们用的是关系型数据库,并且事先做了大量的关系数据的建模工作。哦,除了客服软件,那里用的是键值对的存储方式,否则无法灵活应对混乱不堪的更新发布。这是因为我几十年来身为自由主义者接受教化的结果。不管怎么说,即便公司为了工作生活的平衡做出了很多变化(特别是股价多次下跌和好多年工程师周转率都保持在很高的两位数之后),亚马逊的工程师依然保留了自由,像创业公司那样的核心价值。每个团队都自己管理数据,自己做决策,基本上像是独立运作的商业个体。亚马逊的发布和执行速度依旧比任何人都快,因为他们真的敢冒风险(可能导致大规模瘫痪的那种风险),为了及早发布,经常发布,敢于做出取舍。亚马逊证明了自己在成立15年之后,仍然能保持无人能及的创新力,灵感仍在。
(3)Google——诊断:保守。Google一开始是属于稍微有点自由的那种,然后就变得越来越保守了。Google只有在刚刚开始的时候才是软件自由的,那时候的搜索引擎是用Python写的。随着公司不断壮大,他们很快就转向了软件保守主义,而这完全是由工程师自己主导的。他们写了很多宣言警告太多语言所带来的危险,而仅有的几门语言里,也有严格的风格指南,限制使用那些“危险”或者“难以阅读”的语言特性。Google的JavaScript代码风格极端保守,充斥大量静态类型标注,eval更是被完全禁止。Python的风格指南禁止元编程等各种动态特性,搞得像是没有类型的Java一样。他们还严格限制很多C++的特性,而与此同时C++ 11每几周就会支持一个新特性。(C++ 11里有超过500个的新特性。)内部调查显示,Google工程师觉得妨碍特性升级和快速发布的主要障碍是官僚主义,周转率高,人事复杂。Google曾多次努力试图削减这种官僚主义,然而他们却一次又一次地被工程师自己给抵制回来(没想到吧),因为这些人已经变成了死硬的保守派,会主动(当然更多的是被动)抵制更具灵活性的方案和技术。过去5年里Google内部的技术转向绝大多数都是保守的。对于我这样的自由派人士来说,目睹这一切实在是太让人扼腕了。好在我为自己找到了一个双方阵营都觉得有价值的位置,在我自己的团队里,还能继续保持自由的风格而不受外界干扰。
(4)微软——诊断:难以言喻的保守。微软有两只下金蛋的鹅:Office和Windows。微软已经彻底退化成一个农民,只会保护它的鹅不受侵害。由于重新培训团队实在是划不来,因此它的客户根本别无选择,金蛋自然是有它的价值。可是正因为如此,微软也不再在Office或Windows上有什么创新。他们的贴牌厂商被压得利润非常薄。苹果占领了手持设备市场,而微软却在扼杀自家Windows Phone的最后一点创新,因为他们害怕这会吃掉Windows的核心业务。微软已经有15~20年没有在产品层面上有成功的创新了,所有的成功产品都是从竞争对手那里抄来的:IE、Xbox、C#、.NET、Bing、Windows Phone等不胜枚举。这些都是很好的东西,可惜都是别人的创意。微软的策略是拥抱,扩展,然后利用品牌压垮竞争——至少曾经如此,直到政府在2002年左右出手制止为止。现在这家公司自己都不知道自己要干什么了,更糟糕的是,他们失去了比尔·盖茨,换了一个疯子来当家。员工不断地离开,所有人都觉得自己内心有“存在感危机”,另外,部门之间从竞争变成互害也让人无法忍受。微软已经变成了一个右翼社团主义的辛辣讽刺:坐在门廊前端着枪诅咒路人,期待向政府行贿能让他们在等死期间再多混几年补助。过去7年间,我私下接触过不下400个现任和前微软雇员。我肚子里的八卦多得是啊……或许有一天我会说出来。
(5)奖励:苹果。诊断:未知,但是他们的营销太牛了,所以也没所谓了。不过我很有兴趣想了解它内部的软件文化。有人想爆料吗?穿马甲也行?AMA? 11
好啦,这也是个好玩的游戏。不过我们还得继续往下聊!就快完了。
特别案例:Clojure语言
我关注Clojure已经好久了,至少有一年吧。但是一直都不知道怎么组织语言,把想说的东西解释清楚。
现在我终于知道这么说了!
Clojure是一种新型的Lisp方言,能在JVM和.NET上跑,我曾有幸为《The Joy of Clojure》 12 一书作序。我曾经很兴奋地学了好几年Clojure,刚上手的时候用起来还是很顺手的。
可后来我发现Clojure社区可谓极端保守,对一门Lisp方言来讲这有点让人出乎意料。在广泛的认知里,Lisp一直都是自由语言家族的代表,而Clojure表面上似乎也是一门随心所欲的语言。它的表达能力非常强,拥有(咳咳)一堆自由度很大的新语法。和Scheme以及Python不同,它没有静态类型标注,也没有强类型建模,取而代之的是一系列很规范、易于组合的数据类型和操作。
可惜狐狸尾巴到这里就藏不住了。Clojure的社区里全是来自纯函数界的程序员,保守得要死:基本上都是Haskell或者ML这种类型(放地图炮了),正好发现Lisp的tree语言很对胃口罢了。因此在强大的表达能力后面,Clojure却是一个彻头彻尾的保守语言,其核心是要防范程序员犯错。
另外,这个社区非常循规蹈矩。在去年(还是前年?时光飞逝啊……)的Clojure大会上,就有一个重量级的发言人在那里讲述宏的害处,为什么要在现代Clojure代码里回避它。
我坚信只要你是懂一点Lisp的人,看到这里肯定会血气上涌。至少我当时的感觉是这样的。
当然从经典的软件保守主义角度来看,他的理由合情合理。有了宏就可以发明抽象出自己的领域特定语言,然后用户就必须依赖文档来理解这些抽象的作用和含义。这就意味着就算会Clojure也没用,你还是要依赖文档才能真正读懂别人的Clojure代码。那这和什么都不懂的菜鸟又有什么区别?这就让人心里打鼓了。因此保守派真正害怕的是由于自己不懂宏,突然老鸟变菜鸟。(作者注:很不巧这其实是误读了他们的立场,所以这个例子并不恰当。不过没关系,我仍然坚持自己的观点,那就是Clojure社区真的很保守,后来他们自己也在私底下承认了这一点。)
把个人名誉押在垃圾上面可不是件好玩的事情。现实世界里的政治保守派可是出了名的“顽固”,他们是死也不肯在自己的世界观上妥协的。因为他们把自己的名誉都押了上去。
所以虽然我挺喜欢Clojure的,然而内心深处坚定的自由基因最终还是让我和它分道扬镳。这对我和Clojure都未尝不是件好事。反正也没必要妥协嘛。
我的理念就是不要对这种事情有什么情感上的寄托。把问题归结为自由主义和保守主义之争,大家各自保留意见就行了。
这也有助于语言的设计者和社区更有针对性地推广营销。现在每门语言都宣称“大家都应该来用我”,其实我们都明白这是不可能的——就算真的是,至少我们也可以确定他们走的是中间路线,这其实是要冒风险的,冒同时被两派鄙视的风险。
而在保守派和自由派的世界里,语言设计师就可以更准确地描述自己,不用老是玩先画个饼把人忽悠进来再说的把戏。例如:“任何极端保守的程序员都应该用Haskell!”
措辞方面我们可以再斟酌,你明白意思就好。
收官
原本我还想多举几个例子的,只不过我发现自己已经在喝第3杯(编辑注:第4杯)酒了,说不定随时会倒。
所以还是赶快收官吧!
有一点很关键,我想提但是一直找不到机会。那就是:要是我叫你(软件)保守派,千万别太敏感。
我一直很担心那些政治上左倾的程序员只要一听到“保守”这个词就会立刻把它和……呃,美国当今政坛上各种右翼保守主义所代表的东西联系起来。就是种族主义、性别歧视、宗教原教旨主义、反对同性恋、鼓吹战争,还有猎熊那种东西 13 ,你懂的。
我没说这些都是“坏的”,至少没有在这篇文章里说。我想说的只是任何正常人都不会想和那些极翼分子扯上哪怕一点点关系。看出 3(编辑注:4)杯酒能带来多少细微差别了吧?但是我可没指责他们的观点。真没有,至少没在这儿。我只是注意到这些观点被赋予了浓重的政治色彩,而且最近在美国政坛上和“保守主义”这个词紧紧地联系在了一起。
所以请千万不要把现实世界里的政治观点和通常意义上的“保守”联系起来,在这里它的意思仅仅是“厌恶风险”而已。
在编程上趋于保守是一件很平常也很正常的事,用不着通过猎熊来证明自己。我其实还挺期待在编程界里看到人们自称自由或保守的。我的意思是,人应该维护自己的信仰,而且我相信我们已经在这么做了,那么给信仰一个方便的称呼应该也不是什么难事吧。
更委婉的说法肯定会出现的,拭目以待吧。
不管怎么说,请告诉我你的想法!任何观点和评论都欢迎,包括和熊有关的!
特别感谢Writer’s Block Syrah为这篇自断职业生涯的文章所做的贡献。
(特别给我的Google同事:没错,这篇东西的确是打算公开发表的。再次申明,我不是索伦之口。)