#每周读书#黑客与画家

提问:《黑客与画家》中,作者曾在书中提到,“效率低下的软件并不等于很烂的软件" 这句话如何理解?作者的编程思维是?

答:理解这句话的关键是理解“效率低下”和“烂”,这是两个有着相当广阔含义外延的中文词汇。如果脱离文本语境去阐述,就像单独去解读《论语》中的某个字某句话,可能和作者表达的本意有较大出入。

“效率低下”:这里的效率低下不是贬义词。作者说的效率低下不是指代码运行效率低下,比如一些没有优化过的,时间复杂度和空间复杂度很高的算法。效率低下是指为了架构的优美,可扩展而牺牲了一定代码效率。比如用C++写一个计算圆形面积的程序,如果用用结构化编程的方法把圆形面积计算公式直接写到程序里肯定比用面向对象的方法创造一个Class AreaCalc并且写一个AreaCircleCalc的function的代码效率要高,但是结构化的代码有局限性,只能计算圆形的面积,后期代码维护起来很麻烦,所以作者认为有更好架构但是效率没那么高的代码更好。作者举了Lisp语言里string和list的例子,引入string类型是一种“效率很高”的方式,而用list生成字符串是一种“效率很低”的方式。作者认为不引入string类型能保持基本运算符的简洁性,他并不认可string这种“效率很高”的方式。更进一步说,所谓的“效率低下”只是体现在某一个小规模的具体问题计算上,如果考虑到程序的扩展及维护,那些针对具体问题优化到极致的程序反而会花掉程序员更多的时间(第一版开发+优化的时间以及后续痛苦的维护时间)。随着计算机计算能力的大幅提升,牺牲一部分计算效率换取优良的代码架构是值得的。在4k内存的年代,可以把代码的优化精确到寄存器,但是后续任何改动都需要重写代码,这样的“效率高”反而是“效率低”。

“烂”“烂”是一个意思丰富的中文词,翻译的时候存在一定的信息压缩(并不是说阮一峰翻译的不准确,因为语言表达习惯差异,这种信息压缩难免的)。《黑客与画家》是作者博文的摘编,作者的博客是免费的,可以很容易找到原文(原文链接http://www.paulgraham.com/hundred.html),附上这一整段:

Inefficient software isn't gross. What's gross is a language that makes programmers do needless work. Wasting programmer time is the true inefficiency, not wasting machine time. This will become ever more clear as computers get faster.

这里“坏”用的是gross,同义词是unpleasant,disgusting,让人恶心,不舒服的意思。当你打开一份没有注释,基本没有命名习惯,类封装随意的代码时,一定可以体会到gross。可见这里的“坏”并不是说软件的运行效率很低或者bug很多,无法满足目标需求,而是指代码的编写习惯很差,让人读不下去。具体到这个语境下就是为了极限优化计算效率而牺牲可读性,扩展性,可维护性的代码。goto语句是一个想当典型的例子,很多C/C++的科班学子可能在教材的第一页上就看到了对goto的批判。程序员手动的使用goto可以一定程度上优化代码的效率(尤其是针对早期的编译器以及早期捉襟见肘的硬件资源),但是大量的goto严重牺牲了程序的可读性,大型程序几乎无维护的可能,这样的软件看似efficient,但是gross。

总结一个程序的效率不光是指运行的机器时间,还要考虑到程序员编写以及维护这个程序需要的时间。随着计算机运算能力的大幅提高,程序员的时间会更加的宝贵。

作者的编程思维:好的编程语言以及好的代码应该是能够帮助程序员节省时间的(包括开发和维护的时间),而不是为机器节省时间。编程的起点是一个高可靠性,可维护性,可复用的架构,具体填充代码实现反而是下一步的工作。


拓展练习试着画出编程语言的进化脉络

首先要讨论一下“进化”这个词。作者在The Hundred-year Language里梳理了编程语言发展的历史,谈了自己的一些展望。中文里“进化”是一个显性的褒意词,比以前变得更好了叫“进化”。作者用的词是evolve,确切地说是“演化”,演化是一个中性词,单纯表示发生了变化。马哲里讲世界是运动的,但是只有向上,向前的运动才是发展。evolve是运动,但不一定是发展。进化论是evolution,现在学界更倾向叫演化论。严复翻译赫胥黎Evolution and Ethics时翻的特别好,叫《天演论》,他说演化不说进化。

编程语言的演化脉络是降低编写程序的难度,或者说降低程序员操作计算资源的难度,让写代码变得越来越轻松。这也符合人类社会的运行规律。80年代的汽车驾驶员需要具备很强的修车能力,考驾照还要考机械结构,但是这些科目都从现在的驾考中消失了。如果要求开汽车的人必须了解汽车的结构,这对于汽车普及是相当不利的。2012年360能够完成珍珠港偷袭,主要得益于把软件变得前台妹子都能轻松使用(现在更进一步,连安装都不需要你动手)。Ubuntu应当说为Linux推广做了巨大贡献,因为她让Linux不再是专家级程序员的玩具。编程语言的发展也是类似,如果现在的程序开发还需要打纸带,儿童编程基本没有可能。

  • 第一代

第一代编程语言是机器语言,程序员直接和电子管,寄存器打交道。这样的程序显然书写难度大,基本没有维护的可能。

  • 第二代

第二代编程语言是汇编语言,一些寄存器操作被封装成MOV,ADD这种指令,用一个指令代替多条机器指令。

  • 第三代

第三代编程欲言是高级语言,进一步把MOV,ADD这种汇编指令封装,程序员可以用接近自然语言的逻辑表达式书写代码,由编译器负责把高级语言的代码转化成机器指令。高级语言也分很多流派,比如按照程序设计思想可以分为面向对象和面向过程。由于面向对象的开发是目前软件开发中的主流,所以大部分语言都有面向对象的特性。今年3月份TIOBE的top10里只有C语言不是面向对象的,以往也基本如此。按照编译方法分为解释型和编译型语言:解释型的又叫脚本语言,比如Python,Ruby,Perl;编译型的比如C++,C#,Java等。一般地认为编译型语言更底层,能操作更底层的硬件资源,运行效率高;而脚本语言往往是为了解决一些具体的问题,所以有着丰富的特定场景解决方案,但是运行效率并不高。最典型的是python,由于有大量的科学计算,人工智能,模式识别的库,python几乎是人工智能的首选语言。当你使用一个更聪明的解释器时,解释型语言的效率劣势能得到很大弥补,而且python相当多的底层函数库也是用c/c++开发的,实现了使用效率和运行效率的平衡。可以预见在相当长的时间里,编程语言的舞台还是高级语言的天下,而且是百花齐放,各有所长。

  • 第四代
    下一代编程语言是值得展望的事情。如果以100年为时间尺度,下一代编程语言很可能超出我们的想象,一如让1920年代的人类想象智能手机。下一代编程语言一定是打破冯诺伊曼计算架构的,它可能工作在量子计算机或者DNA 计算机平台上。下一代便成语言的编写门槛更低,我们可以用自然语言描述需求,由人工智能负责代码的实现。可以肯定的是,下一代编程语言可以让大部分人变得更懒,大部分普通程序员(或者人人皆可为程序员)用着极少部分精英程序员开发的工具(或者底层代码库,由中级程序员编写工具)书写着大量代码。

你可能感兴趣的:(#每周读书#黑客与画家)