《程序员的呐喊》是Google一位老程序员的经验总结,文中展现了他对各大语言如Java、C/C++、Lisp、Python、Ruby、Perl等的极端观点,比如大力吐槽C++,极力推崇C、Lisp、Ruby。他的观点只是他个人经验所得,也不一定符合实情,仅供参考,有任何想法都可以说出来一起讨论。
说明:本人写作能力笔记做,所有的段落归纳转载于以上博客
http://blog.csdn.net/lanxuezaipiao/article/details/47333895
程序员和司机一样,总是自我安慰说等到需要的时候再去学新技能也来得及。但是在内心深处他们都明白,其实当需求出现的时候就已经太晚了。因此现实情况是这样的,旱鸭子会和水保持距离,司机会绕开泥泞的路段,而程序员会躲在舒适区里,搭建围栏把自己保护起来,然后祈祷世界和平。
me:趋利避害估计是大多人的都会做的,以前的我也是会躲在舒服的地方,不思进取,享受安逸,但是当你发现外面的事件在变的时候,同一公司的同事离开后去了百度和360大的公司,你会发现这这样的想法太过危险,趁着年轻还是要多锻炼下自己
当时04年亚马逊正饱受其庞大代码库的困扰,我曾经一度认为它的代码库失控是因为语言问题,后来才意识到企业文化是主因。首当其冲的是,亚马逊的主流语言里有两门非常哆嗦的语言C++中和Java,外加一门精练的语言Perl。但是Perl正受到排挤,渐渐退出主流。我觉得这是因为Perl程序员能用更少的人力完成和Java/C++程序员同样的工作量,所以要是比人多的话,他们注定是赢不了的。根据我们的估算,亚马逊的代码量比它的功能数量膨胀得更快。第二个因素是,亚马逊的很多技术问题完全可以用自定义领域语言(DSL的方式来解决),比如大规模的查询、分布式计算、产品配置等,他们写了太多不必要的代码了。我后来跳到Google,发现他们为这些完全一样的问题专门编写了强大的自定义DSL。这证实了我心中的疑虑,亚马逊的工程师在这些问题上和无头苍蝇没什么两样。我敢说这句话误伤的概率极低。最后一点就是,和绝大多数公司一样,亚马逊非常抗拒用新语言来解决问题。他们会避免使用表达能力更强的通用语言,比如Ruby或Erlang。他们也几乎从来不会想到自己去写DSL。
me:庞大的代码库会让你在开发中越来越痛苦,开发效率会越来越低,在效率上也会慢慢的出问题,拥抱创新,使用新的技术和语言来解决它擅长的问题,才是王道。就比如 web 开发使用perl php这样的语言 速度更快,使用es作为搜索
为什么C是必修课?
一个原因是现在的电脑都是冯诺·伊曼结构的,而C以精悍的语法展现了冯·诺伊曼机的能力,其他类型的机器也是存在的,比如Lisp机。还有一个原因就是,Unix是用C写的,不仅如此,包括Windows等在内的几乎所有的操作系统都是用C写成的,因为它们全部属于冯诺伊曼机操作系统。你觉得自己还有其他选择吗?至少在操作系统领域里,任何与C迥异的语言都发挥不出硬件的实际能力,至少这句话放在近一百年里都是对的这些系统都诞生于这段时期内。
计算机编程语言里没有所谓的“亲近生侮谩“,只有在掌握更优秀的语言前提下,才会懂得怎么批判自己最熟悉的那门语言。因此,要是你不喜欢我批评C++,我建议你去了解一下更优秀的语言是什么样子的,然后你才有资格否定我的话。不过到那时你就不会来否定我了,我忽悠成功了。那时你不会再喜欢C++,可能会有点生我的气,忽悠你讨厌自己之前最爱的语言。所以你还是别管我说什么了。C++很出色,非常优秀。别在意我的话。它是门很棒的语言。
me:作者是有多么讨厌C++啊!“亲近生侮谩“的意思是当你对一个人或事物越亲近越熟悉,你就会越讨厌越忽视TA。而作者认为计算机语言里不会发生这种事情,除非你知道了其它更优秀的语言。我赞同这个观点。
亚马逊的伟大元老们只用两种语言:C和Lisp。显然,他们都是Emacs的拥趸。
me:的确很多编程界的大佬都爱这两门语言,比如《黑客与画家》的作者。
杰米·扎温斯基曾经写过一篇非常有名的文章来批判Java有多糟糕,但他还是这样写道:“先说好的地方:Java没有free(),我必须承认这一点,其他锦上添花而已。光这一点就足以让我忽视其他缺点了,不管它们有多糟糕。有鉴于此,本文接下来的内容都可以说无足轻重。”杰米的这篇文章写于1997年,那时的Java还在襁褓之中,如今Java早已今非昔比,他当时抱怨的有些东西现在都已经修复了。但也不是全都改好了。就语言层面,Java仍然算不上优秀。但正如杰米所言,它“依然是今天最好的语言,远远比我们在实际工作中用的那些彻头彻尾的垃圾语言要好得多”。不过Java也缺了一些C++的优点,比如(在栈上)传引用、typedef,宏,还有重载操作符。这些东西并非必不可少,但是需要的时候就很方便。对了还有多重继承,说得我都开始怀念从前了。假如你要用我自己的“固执己见的精灵”来反对多态,那么我还可以举出更多为什么多重继承是必需的例子。有时间我们可以讨论一下“火焰剑”或者“盗贼披风”的问题,你就会明白接口是多糟糕的东西了。几年前,高斯林自己也承认,要是有机会重来的话,绝对不会考虑接口。而这正是Java的问题所在。
me:Java好在垃圾自动回收,坏在臃肿不堪,语言本身设计的不好。
总之,Ruby对Perl充分实行了拿来主义。Ruby的作者Matz(我没记错的话,他的本名是松本行弘,不过通常都自称“Matz”)甚至可能有点借鉴过头了,连些不好的东西也拿了过来。好在不多,只有一点点而已。基本上Ruby照搬了Perl的字符串处理和Unⅸ集成,语法完全一样,只此一点,Perl的精华就全都有了。这可以说是开了个去芜存菁的好头。接着Matz从Lisp那里吸收了列表处理的精华,从Smalltalk那里拿来了OO,迭代器则是取自CLU,基本上各个语言里的优点都吸收进来了。所有的这些东西被完美地糅合在一起,你压根注意不到斧凿的痕迹。
me:Ruby本质上就是各种语言精华的大杂烩,去芜存菁,作者精通这么多语言的精华非常值得敬佩。现在的框架也是的,都是互相之间借鉴精华,按需索取,无可厚非。
Python本来是有机会一统江湖的,但是它有两个致命的缺陷:一个是空白符,另一个是死脑筋。所谓空白符的问题就是Python的嵌套是通过缩进来完成的。它强迫你用特定的方式来缩进,这样大家的代码看起来就是一样的了。可惜,很多程序员都讨厌这个规定,感觉好像被剥夺了自由一样;他们觉得胡乱排版和和编写那种精简到一行没人看得懂的小程序是自己的权利,而Python却侵犯了这一点。Python之父吉多·范罗苏姆之前也出过几次昏招,虽然不如拉里那么惊世骇俗,但也真的是够小儿科的了。比如,Python原本是没有词法作用域的。可问题是它连动态作用域也没有,虽然说动态作用域也有自身的问题,但至少还勉强可以用。Python最早只有全局和局部(函数)作用域,所以虽然它拥有一个“真正的OO系统,可是—个类却连自己的实例变量都没法访问。你只能给每个实例方法带上一个self参数,然后通过self来访问自己的实例数据。所以你在Python里看到一堆self ,哪怕你忍了空白符,这些self也能把你给逼疯了。
me:用空格缩进的确让人不爽,不过提升了规范性。不过目前2017我了解得python越来越火,越来越被市场认可了,能做的事情很多,web 抓取 人工智能 运维
Java 其中特点之一就是凸显了“架构”。Java国王授予了架构尊崇的地位,因为架构完全是由名词组成的。我们都知道,名词就是事物,而在Java里,事物的地位远胜一切动作。建筑是由看得见摸得着的事物构成的,譬如高耸入云的庞然大物,又如用棍子敲打时发出低沉悦耳声音的东西。Java国王特别喜欢这种沉闷的声音,每次换新马车的时候,他都特别喜欢从踢轮子中获得快感。不管上述的儿歌有何瑕疵,它就是不想要任何东西。
me:的确,Java最让人受不了的就是一堆架构,一层层封装致死,调试起来也麻烦。
福勒告诉我们所谓重构,就是通过迭代,将恶心的代码变成优质代码的艺术和科学,是能妆点代码却不会在操作过程中产生破坏的算法,而且正确性都是能证明的。
me:作者认为福勒写的重构这本书非常不错,值得一读。
那么这些代码一开始是怎么变烂的呢?首先当然是由于过早优化造成的,为了避免重复计算而保存了太多的中间变量。因为害怕方法调用会造成虚幻的负担,而刻意回避编写短小的函数。我们还弄出一大堆类的继承关系,仅仅是为了想象中可能存在的复用,为了避免分配器对象而弄出一个巨大的参数列表。滥用null,把它当成成具有语义的符号。放任简单的布尔逻辑表达式变成错综复杂、无法阅读的浆糊。不用访问方法来封装数据结构。还有其他很多乱七八糟的问题。正是因为各种各样的小错误别类,加以命名,并归类成严重错误。
me:这是福勒重构这本书告诉我们的。
那我们的代码是怎么变成那样的呢?因为写得烂。这时重构就能救命。再优秀的设计也会出纰漏,但我们仍然可以补救,反正有自动化的奴仆来帮我们修复这些:小问题。它们不知疲倦,我们只要点个按钮就行了。既然如此,谁能离得开自动化重构工具?还有谁能协调Java那些数以百计的小腿,让它们像毛毛虫一样统一行动呢?让我来告诉你答案:Ruby是蝴蝶。(意指Ruby是完全不同的物种,Java中自动化重构工具所要解决的问题在Ruby中根本不存在。)
me:作者喜欢Ruby,觉得Java需要重构是因为代码写的烂,要是用Ruby写的话根本不需要重构,也就没有自动化重构工具。
首先,再垃圾的语言和技术也一样有机会赢。甚至赢面可能还会大一点,因为改正起来会更快。Java击败了smalltalk , C++击败了Object-C,Perl击败了Python,VHS击败了Beta,诸如此类。并不是说一项技术(特别是编程语言)比较优秀,它就一定会胜出。营销才是关关键。追求公平竞争只会导致你的语言无人问可津。
me:原来一门语言的流行起关键作用的不是这门语言有多优秀,而是它的营销做的有多好。嗯,我记得Java就是营销搞起来的。使是的,我极力推荐身边的朋友去学习Laravel框架 和 python
注意,骂谁也不能骂Python。相反,骂Ruby骂得最凶的人可能就是Matz自己了。他在自己的演讲“为什么Ruby很烂”里,自陈了Ruby的各种问题,当时看得我汗都下来了。不可否认,任何语言都有缺点。相比之下,我更喜欢Ruby众的坦诚,Pyhon那种一味指责别人,回避问题,过分地自我标榜的行为令人感到恶心。
me:作者的意思是Python众狂妄自大,而Ruby相对比较坦诚,这是作者通过经过逛两个社区得出的结论,也不一定准确。我的局的谦虚,还是比较好的
静态类型的优点
下面列出了静态类型的主要优点:
(1)静态类型可以在程序运行之前,依赖其与生俱来的限制来及早发现一些类型错误。(或是在插入/更新记录,解析XML文档等情况下进行检测。)
(2)静态类型有更多机会(或者说更容易)优化性能。例如只要数据模型完整丰富,那么实现智能化的数据库索引就会更容易一些。编译器在拥有更精确的变量和表达式类型信息的情况下可以做出更优的决策。
(3)在C++和Java这样拥有复杂类型系统的语言里,你可以直接通过查看代码来确定变量、表达式、操作符和函数的静态类型。
这种优势或许在ML和Haskell这样的类型推导语言里并不明显,他们显然认为到哪里都要带着类型标签是缺点。不过你还是可以在有助阅读理解的情况下标明类型一而这些在绝大多数动态语言里是根本做不到的。
(4)静态类型标注可以简化特定类型的代码自动化处理。比如说自动化文档生成、语法高亮和对齐、依赖分析、风格检查等各种“让代码去解读代码”的工作。换句话说,静态类型标签让那些类似编译器的工具更容易施展拳脚:词法工具会有更多明确的语法元素,语义分析时也比较少要用猜的。
(5)只要看到API或是数据库结构(而不用去看代码实现或数据库表)就能大致把握到它的结构和用法。
还有其他要补充的吗?
静态类型的缺点如下:
(1)它们人为地限制了你的表达能力。
比如,Java的类型系统里没有操作符重载、多重继承、mix-in、引用参数、函数也不是一等公民。原本利用这些技术可以做出很自然的设计,现在却不得不去迁就java的类型系统。无论是Ada还是C++,或是OCaml等任何一种静态类型系统都有这样的问题。差不多半数的设计模式(不光是Gof的那些)都是扭曲原本自然直观的设计,好将它们塞进某种静态类型系统:这根本就是方枘圆凿嘛。
(2)它们会拖慢开发进度。
事先要创建很多静态模型(自顶向下的设计),然后还要依据需求变化不断修改。这些类型标注还会让源代码规模膨胀导致代码难以理解,维护成本上升。(这个问题只在Java里比较严重,因为它不支持给类型取别名。)还有就是我上面已经提到过的,你得花更多的时间来调整设计,以适应静态类型系统。
(3)学习曲线比较陡。
动态类型语言比较好学。静态类型系统则相对挑剔,你必须花很多时间去学它们建模的方式,外加静态类型的语法规则。另外,静态类型错误(也可以叫编译器错误)对于初学者来说很难懂,因为那时程序根本还没跑起来呢。你连用printf来调试的机会都没有,只能撞大运似的调整代码,祈求能让编译器满意。因此学习C++比C和Smalltalk难,OCaml比Lisp难,Nice语言比Java难。而Perl所具备的一系列静态复杂性—各种诡异的规则,怎么用,什么时候用等—让它的难度比Ruby和Python都要高。我从来没见过有哪门静态类型语是很好学的。
(4)它们会带来虚幻的安全感。
静态类型系统确实能减少运行时的错误,提升数据的完整性,所以很容易误导人们觉得只要能通过编译让程序跑起来,那它基本上就没什么bug了。人们在用强静态类型系统的语言写程序时似乎很少依赖单元测试,当然这也可能只是我的想像罢了。
(5)它们会导致文档质量下滑。
很多人觉得自动生成的javadoc就足够了,哪怕不注释代码也没关系, Sourceforge 上充斥着这样的项目,甚至连Sun JDK也常常有这个问题。(比如,Sun很多时候都没有给static final常量添加javadoc注释。)
(6)很难用它们写出兼具高度动态和反射特点的系统。
绝大多数静态类型语言(大概)都出于追求性能的目的,在运行时丢弃了几乎所有编译器生成的元数据。可是这样一来这些系统通常也就很难在运行时作出修改(甚至连内省都做不到)比如,若要想给模块加一个新函数,或是在类里加个方法,除了重新编译,关闭程序然后重启之外别无他法。受此影响的不单是开发流程整个设计理念也难逃波及。你可能需要搭建个复杂的架构来支持动态功能而这些东西会无可避免地和你的业务代码混在一起。
动态类型的优缺点:
只要把上面的列表对调一下,你基本上就可以列出动态类型语言的优缺点了。动态语言的表达能力更强,设计灵活度也更大;易学易用,开发速度快;通常运行时的灵活性也更高。相对地,动态语言无法及时给出类型错误(至少编译器做不到),性能调优的难度也比较高,很难做自动化静态分析,另外,变量和表达式的类型在代码里很不直观,没办法一眼看出来。
静态语言最终会向用户屈服开始添加一些动态特性,而动态语言常常也会尝试引入一下可选的静态类型系统(或是静态分析工具),此外它们还会设法改善性能增加错误检测,以便及早发现问题。很遗憾,除非一开始设计语言的时候就考虑到可选的静态类型,否则强扭的瓜怎么也不会甜的。
下面我会以稍微有点戏谑的方式解释这两种理念(指的是强类型和弱类型)的工作流程,尽可能将它们本质区别展现出来。
强类型阵营基本是这样工作的:首先是按照当前的需求进行设计;制定出文档哪怕只是初稿也没关系;然后定义接口和数据模型。假设系统要承受巨大流量,因此每个地方都要考虑性能。避免采用垃圾收集和正则表达式这类抽象。(注意:即便是Java程序员,通常也会努力避免触发垃圾收集,他们总是在开始写程序之讨论对象池的问题。)
他们只有在无计可施的情况下才会考虑动态类型。例如,一支采用Corba的团队只有在极端情况下才会在每个接口调用上添加一个XML字符串参数,这样他们就能绕开当初选择的死板的类型系统了。
第二个阵营基本是这样工作的:先搭建原型。只要你写代码的速度比写同等详细程度的文档快,你就可以更早地从用户那里获得反馈。按照当下的需求定义合理的接口和数据模型,但是别在上面浪费太多时间。一切以能跑起来为准,怎么方便怎么来。假设自己肯定要面对大量的需求变化,所以每个地方首先考虑的是尽快让系统运行起来。能用抽象的地方就尽量用(比如如每次都去收集数据而先不考虑缓冲,能用正则的地方就先不用字符串比较)就算明明知是牛刀也没关系,因为你换回的是更大的灵活性。代码量比较少,通常bug的数量也会更少。
他们只有在被逼无奈的情况下才会进行性能调优以及禁止修改接口和数据定义。例如,一支Perl团队可能会将一些关键的核心模块用C重写,然后创建XS绑定。时间—长,这些抽象就渐渐变成了既定标准,它们被包裹在数据定义和细致的OO接口里,再也无法修改。(就算是Perl程序员也常常会忍不住祭出银弹,为常用的抽象编写OO接口)
那你觉得最终采用这些策略的结果会怎么样?
me:现在Java程序员相信都知道依赖注入了,因为它太重要了,用在各大框架里,比如spring,依赖注入使得能够在文件里配置类及其各种关系,当然使得Java更灵活更强大了。
me:程序员所要解决的数学问题一般都是离散数学,其中最有用的课程应该就是组合数学和概率论统计。自从自学了python语言以后和算法以后我觉得数学其实真的很重要的
me:作者强烈要求程序员学编译器原理,你还记得吗?
me:保守派,尽量修复所有bug,回避错误,学不会新语法,通过编译器安全检查,数据必须遵循事先定义好的格式,公共接口必须严格建模,生产系统里绝不允许存在危险过有风险的后门,安全性有疑虑就不能上线,快比慢好,注重性能。自由派则相反。我觉得在IT这个行业,太保守还是不好的特别是创业公司
各大语言的分派:(作者自己使用语言的经验,仅供参考)
难以言喻的自由:汇编语言
极端自由:Perl、Ruby、PHP、脚本
非常自由:Javascript、VB、Lua
自由:Python、Common Lisp、Smalltalk/Sqeak
温和自由:C、Object-C、Schema
温和保守:C++、Java、C#、D、Go
保守:Clojure、Erlang、Pascal
非常保守:Scala、Ada、Ocaml、Eiffel
极端保守:Haskell、SML
(1)Facebook是极端自由的。他们主要用的是C++和PHP,他们的数据都放在memcached里:只有键值对,没有数据库结构。他们把数据导出来放到一个后台Hⅳe数据仓库里,然后用Hadoop来进行离线数据分析。每两个星期左右他们仍然会举办通宵黑客马拉松,反正他们的程序员大多都是单身男青年(至少我上次去参观的时候还是如此),股票的估值也还很高(我上次查价格的时候好像已经没那么好了)。作为一家公司,Facebook是非常紧密的,具有很强的执行力,十分注重程序员在网站上发布新功能的单兵能力,没有什么官僚主义。这对一家规模这么大、用户那么多多的公司来讲是难能可贵的。保守派毫无疑问会厌恶蔑视他们。但是Facebook证明了不管具有什么世界观的程序员,只要联合起来,就能解决很多问题。
(2)Amazon是自由的。
(3)Google是保守的。开始是有点自由的 ,然后就变得越来越保守了。只有在刚刚开始的时候才是软件自由的,那时候的搜索引擎是用Python写的。随着公司不断壮大,他们很快就转向了软件保守主义,而这完全是由工程师自己主导的。他们写了很多宣言警告太多语言所带来的危险,而仅有的几门语言里,也里,也有严格的风格指南,限制使用那些端保守,险”或者“难以阅读”的语言特性。
(4)微软是难以言喻的保守。