程序员也可能是艺术家——《黑客与画家》 读书笔记

程序员也可能是艺术家——《黑客与画家》 读书笔记_第1张图片

注:此文有大量原文引用,但并无牟利目的,如涉及版权问题,请通知本人下架。另禁止转载。


[格式]

原文摘录

我的批注


零、开始


1、写在前面

这本书是硅谷创业之父 Paul Graham的文集

这本书是阮一峰翻译的。

在这里,我劝大家把书名想成《程序员与画家》,毕竟黑客这个词跟我们距离感太强,会找不到代入感。

2、创业公式

保罗·格雷厄姆有一套完整的创业哲学,他的创业公式是:

( 1)搭建原型( 2)上线运营(别管 bug)( 3)收集反馈( 4)调整产品( 5)成长壮大

3、Hack

在这里, hack作为名词有两个意思,既可以指很巧妙或很便捷的解决方法,也可以指比较笨拙、不那么优雅的解决方法。两者都能称为 hack,不同的是,前者是漂亮的解决方法( hack或 hack),后者是丑陋的解决方法( hack或 hack)。 hack的字典解释是砍(木头),在这些学生看来,解决一个计算机难题就好像砍倒一棵大树。那么相应地,完成这种 hack的过程就被称为 hacking,而从事 hacking的人就是 hacker,也就是黑客

在 20世纪 60年代这个词被发明的时候,“黑客 ”完全是正面意义上的称呼。

为了澄清 “黑客 ”这个概念,他们提出只有传统意义上的黑客才能被称为 hacker,而那些恶意入侵计算机系统的人应该被称为 cracker(入侵者)。这个观点已经在程序员社区中得到普通认同。本书正是在这个意义上使用 “黑客 ”这个词。在本书中, “黑客 ”就是指最优秀的程序员,而不是入侵计算机系统的人。

一、为什么书呆子不受欢迎


书呆子被称为怪人(freak)。

在一个人产生良知之前,折磨就是一种娱乐。

我觉得这里的良知指的更像是一种认知,对人对事的一种认知。而良知在中国人的语境里更多的指先天的,而不是后天学习到的。这里用道德更加合适,因为道德是后天形成的。

这就是为什么最恶劣的以强凌弱的事件都与团体有关的原因。

参考电影《浪潮》。

人类喜欢工作,在世界上大多数地方,你的工作就是你的身份证明。

前者不认同,后者认同,且更多的针对男性。

二、黑客与画家


黑客与画家的共同之处,在于他们都是创作者。

我觉得在其他更多领域里人们也都是创作者。

我一直不喜欢 “计算机科学 ”( science)这个词。主要原因是根本不存在这种东西。计算机科学就像一个大杂烩,由于某些历史意外,很多不相干的领域被强行拼装在一起。这个学科的一端是纯粹的数学家,他们自称 “计算机科学家 ”,只是为了得到国防部研究局( DARPA)的项目资助。中间部分是计算机物理学家,研究各种专门性的题目,比如网络数据的路由算法。另一端则是黑客,只想写出有趣的软件,对于他们来说,计算机只是一种表达的媒介,就像建筑师手里的混凝土,或者画家手里的颜料。所以,在 “计算机科学 ”的名下,数学家、物理学家、建筑师都不得不待在同一个系里。

当代很多新兴学科其实就是跨学科、糅合的产物,我认同可以创造这么一个新的学科 —— 计算机科学。

有时,黑客做的事情被称为 “软件工程 ”( engineering),但是这个词也是误导的。与其说优秀的软件设计师是工程师,还不如说是建筑师。建筑学和工程学之间的区别并不是很严格的,但就是存在区别。这表现在 “做什么 ”和 “怎么做 ”:建筑师决定做什么,工程师想出怎么做。

所以现在软件工程师里大多数负责实现的叫开发工程师,而负责怎么实现的就叫架构工程师(简称”架构师“)了。

唯一有效的外部考核就是时间。经过岁月的洗礼,优美的东西生存发展的机会更大,丑陋的东西往往会被淘汰。不幸的是,这种考核需要的时间可能比一个人的生命还要长。塞缪尔 ·约翰逊说过,人们对一个作家的评价,需要 100年才能达成一致。你必须先等他的那些有影响力的朋友都死了,然后再等他的追随者都死了,才能对他有一个公正的评价。

举例来说,我在大学受到的教育是,在上机编程之前,应该先在纸上把程序搞清楚。可我自己一直不是这样编程的,我喜欢直接坐在计算机前编程,而不是在纸上编程。更糟的是,我不是耐心地一步步写出整个程序,确保大体上是正确的,而是一股脑不管对错,先把代码堆上去,再慢慢修改。书上说,调试( debugging)是最后的步骤,用来纠正打字的错误和疏忽。可是我的工作方法看上去却像编程就是在调试。很长一段时间内我都为此事沮丧,就像小学里老师教我怎么拿铅笔,我却总是学不会的那种感觉。如果我那时看到其他创作领域,比如绘画或者建筑,我就会想到,自己的方法其实有一个正式的名称:打草稿。我现在认为,大学里教给我的编程方法都是错的。你把整个程序想清楚的时间点,应该是在编写代码的同时,而不是在编写代码之前,这与作家、画家和建筑师的做法完全一样。明白这一点对软件设计有重大影响。它意味着,编程语言首要的特性应该是允许动态扩展( malleable)。编程语言是用来帮助思考程序的,而不是用来表达你已经想好的程序。它应该是一支铅笔,而不是一支钢笔。如果大家都像学校教的那样编程,那么静态类型( typing)是一个不错的概念。但是,我认识的黑客,没有一个人喜欢用静态类型语言编程。我们需要的是一种可以随意涂抹、擦擦改改的语言,我们不想正襟危坐,把一个盛满各种变量类型的茶杯,小心翼翼放在自己的膝盖上,为了与一丝不苟的编译器大婶交谈,努力地挑选词语,确保变量类型匹配,好让自己显得礼貌又周到。

这段话真的是对高级语言最好的褒奖。但虽说可以把高级语言当成草稿来写,但是在这个草稿实施前,还是得在心里或纸上来确认题纲。

但我也同意 ”你把整个程序想清楚的时间点,应该是在编写代码的同时,而不是在编写代码之前“,很多时候只有写了代码时,才能理清你之前没有考虑到的点。

如果黑客认识到自己与其他创作者——比如作家和画家——是一类人,这种诱惑对他就不起作用。作家和画家没有 “对数学的妒忌 ”,他们认为自己在从事与数学完全不相关的事情。我认为,黑客也是如此。

大学和实验室强迫黑客成为科学家,企业强迫黑客成为工程师。

大公司为了避免设计上的灾难,选择了减少设计结果的标准差。但是当你排斥差异的时候,你不仅将失败的可能性排除在外,也将获得高利润的可能性排除在外。这对大公司来说不是问题,因为生产特别优秀的产品不是它们的获胜手段。大公司只要做到不太烂,就能赢。

稳定发挥和超常发挥。

黑客如何才能做自己喜欢的事情?我认为这个问题的解决方法是一个几乎所有创作者都知道的方法:找一份养家糊口的 “白天工作 ”。

应该如何学习编程。画家学习绘画的方法主要是动手去画,黑客学习编程的方法也理所如此。

编程最重要的学习方法,就是实践。

同样地,黑客可以通过观看优秀的程序学会编程,不是看它们的执行结果,而是看它们的源代码。开源运动最鲜为人知的优点之一,就是使得学习编程变得更容易了。

就像学习别人的画作(注意,不是欣赏)不是只看别人的成果,而是最好能看出别人创作的思路,甚至看到手稿。

大多数创作者都是为人类用户而创作。为了吸引用户,你必须理解用户需要什么。举例来说,几乎所有最伟大的绘画作品都是画人的,因为人类总是对自身感兴趣的。

程序写出来是给人看的,附带能在机器上运行。

大多数领域的伟大作品都诞生于很早以前。

是时候来一波文艺复兴了。

在达 ·芬奇的年代,绘画并不是一件很酷的事情,达 ·芬奇用自己的工作推动绘画成为一种伟大的表达方式。同样,编程到底能够有多酷,取决于我们能够用这种新媒介做出怎样的工作。

这是我们这一代程序员的使命。

每当遇到两个选项无法决策时,我们就会问自己,我们的竞争对手最恨哪一个选项。

三、不能说的话


为了防止他人复制,古代制作地图的工匠会故意在地图上画错一个小地方。

那些团体神经越紧张,它们所产生的禁止力量就越大。伽利略因为宣传日心说而遭到教廷的审判,这件事讽刺的地方在于,他只是在宣传哥白尼的观点,而后者却安然无恙。事实上,哥白尼不仅不反对教廷,还是一个虔诚的天主教教士,他把自己的著作献给教皇。不幸的是,伽利略正赶上教廷内部反对派上台,宗教改革被压制,任何非正统的思想遭受到前所未有的严厉控制和禁止。

为了在全社会制造出一个禁忌,负责实施的团体必定既不是特别强大也不是特别弱小。

大多数的斗争,不管它们实际上争的是什么,都会以思想斗争的形式表现出来。 16世纪的英国宗教改革( Reformation)本质上是为了争夺权力和财富,但是却表现为英国人要求自主的精神与罗马教廷腐化的控制之间的斗争。思想斗争更容易争取支持者。不管哪一方获胜,他们所代表的思想也就被认为获得了胜利,仿佛上帝通过选择胜利的一方表示了自己的倾向。

意识形态是披着羊皮的狼。

恐惧心在背后驱使着他们。他们接受流行,不是因为想要与众不同,而是因为害怕与众不同。

我觉得我喜欢接受主流影视、音乐、书籍,背后反映我害怕与众不同的心理。

如果有必要的话,大多数物理学家有能力拿到法国文学的博士学位,但是反过来就不行,很少存在法国文学的教授有能力拿到物理学的博士学位。

此话可作为理科 > 文科的论据。

不受传统观念束缚的人,往往也不会穿流行的衣服。

此句存疑。

更好的方法是在思想和言论之间划一条明确的界限。在心里无所不想,但是不一定要说出来。

有时候心里的很多思想还在混沌陈酿之中,不要轻易说出口,否则就会表达错误,遭人误会,甚至变成歪理学说。

”格斗俱乐部“的第一条规则,就是不要提到格斗俱乐部。

人们喜欢讨论的很多问题实际上都是很复杂的,马上说出你的想法对你并没有什么好处。

如果你的数学不好,那么你自己会知道,因为考试的时候你得不出正确答案。但是,如果你的思想很保守,你自己不会知道,而且你很可能还会持有相反的看法。

四、良好的坏习惯


更麻烦的是, “黑 ”( hack)这个词也有两个意思,既可以用作赞美,也可以用作羞辱。如果你解决问题的方式非常丑陋笨拙,这叫做你很 “黑 ”。如果你解决问题的方式非常聪明高超,将整个系统操纵在股掌之间,这也叫做你很 “黑 ”。日常生活中,前一种意思更多见,可能因为丑陋的做法总是多于聪明的做法。

信不信由你, “黑 ”的这两个意思也是相关的。丑陋的做法与聪明的做法存在一个共同点,那就是都不符合常规

跟书法一样,一开始写的丑,熟练后写的规规矩矩,大师级别又写的龙飞凤舞洋洋洒洒。

在计算机工业的历史上,新技术往往是由外部人员开发的,而且所占的比例可能要高于内部人员。 1977 年, IBM 公司内部肯定有一些部门正在开发下一代电脑。他们没有料到的是,真正的下一代电脑不是诞生于 IBM 实验室,而是由两个与他们完全不相干的长头发年轻人在旧金山的一间车库里开发出来的。这两个年轻人,一个是史蒂夫 · 乔布斯,另一个是史蒂夫 · 沃兹尼亚克。差不多同一时间,计算机工业的几大巨头聚在一起,合作研发官方版的下一代操作系统 Multics 。但是,另外两个年轻人——26 岁的肯 · 汤普森和 28 岁的丹尼斯 · 里奇——觉得 Multics 过分复杂,就另起炉灶,写出了一个自己的操作系统。他们参照 Multics ,为它取了一个搞笑式的名字 Unix 。

公民更自由使得国家富强。如果将人均国民生产总值与公民自由的关系画成图,你会发现它们是很清楚的正相关关系。

此处存疑。

在我看来,一个人们拥有言论自由和行动自由的社会,往往最有可能采纳最优方案,而不是采纳最有权势的人提出的方案。

这个我同意,但是现在以美国为代表的西方国家,看似言论自由,实则媒体被操控,看似行动自由,实则被财团把持着社会的走向。

五、另一条路


互联网软件与桌面软件最显著的区别就是,前者不是一个单独的代码块。它是许多不同种类程序的集合,而不是一个单独的巨大的二进制文件。设计桌面软件就像设计一幢大楼,而设计互联网软件就像设计一座城市。

你不会对互联网软件做出这样的承诺,因为它根本没有”版本“这个概念。

解决新代码的 bug要比解决历史遗留代码的 bug容易。在自己刚刚写好的代码中,找出 bug往往会比较快。

早一点发现 bug就不容易形成复合式 bug,也就是互相影响的两个 bug。举例来说,一个 bug是楼梯很滑,另一个 bug是扶手松了,那么只有当这两个 bug互相作用时,才会导致你从楼梯上摔下来。在软件中,复合式 bug是最难发现的 bug,往往也会导致最大的损失。传统的方法是: “把软件彻底拆开,将所有 bug统统清理干净。 ”这样做难免产生一大堆的复合式 bug。如果软件是经常性发布,每次只有小幅度的变化,那么就不容易产生复合式 bug。这就好比做扫除:你一直在打扫大厅,掉落在地板上的东西会被立刻清理,省得它们时间一长与其他东西粘在一起。

很多男生很少有持续打扫房间的习惯,都是好几个月来一个大扫除。这个习惯在解决 bug 上最好不要有。及时解决,不要拖。

复合式 bug 有一个子类型:两个 bug 是互相弥补的,好比“负负得正”,软件反而能正常运行。这种 bug 可能才是最难发现的 bug 。当你修正了其中的一个 bug ,另一个 bug 才会暴露出来。这时对你来说,你会觉得刚才修正错了,因为那是你最后修改的地方,你就怀疑自己在那里做错了,但是你其实是对的。

你的资本支出成本除以服务器所能支持的最大用户数量,就是你为每个用户付出的成本。如果你的软件效率高,你就能比同样硬件配置的竞争对手多发展用户,获得更多的利润。

只要有可能,商业性公司就会采用一种叫做 “价格歧视”( discrimination)的定价方法,也就是针对不同的客户给出不同的报价,使得利润最大化。

这就是为什么很多软件的 Sun 服务器版本比 Intel 服务器版本更贵的原因,因为如果一个公司购买 Sun 服务器,就表明它很有钱,不在乎对设备的投资,那么为什么不向它开个高价呢?盗版实质上是一种价格歧视,只不过针对的是最底层的消费者。

看来价格歧视无处不在。有的在管,有的只能睁一眼闭一只眼。

有钱的客户倾向于更贵的选择,即使便宜的选择更符合他们的需要,他们也不会买。

大公司付出的高价之中,很大一部分是商家为了让大公司买下这个商品而付出的费用。

苹果公司的 Mac 电脑自从一问世,就在黑客之中很流行,许多黑客为它写软件。你在 Windows 身上就很少看到这种现象,因为黑客不喜欢使用 Windows 。现在,善于写软件的那类人更喜欢使用 Linux 或者 FreeBSD 操作系统。

桌面软件迫使用户变成系统管理员,互联网软件则是迫使程序员变成系统管理员:用户的压力变小了,程序员的压力变大了。

首先,管理企业其实很简单,只要记住两点就可以了:做出用户喜欢的产品,保证开支小于收入。只要做到这两点,你就会超过大多数创业公司。随着事业的发展,你自己就能琢磨出来其他的诀窍。

比较软件的标准应该是看对手的软件将来会有什么功能,而不是现在有什么功能。

从长远的眼光来跟竞争对手比。

基准测试( benchmark test )指的是先设置一个基本的数据环境,测试应用程序的表现,然后把这个表现当作“基准”( benchmark ),用来比较其他情况下应用程序的表现。

基准测试包含几个特质:可重复性 、可观测性、可展示性、真实性、可执行性。

不少公司都很想知道,什么事情可以外包,什么事情不可以外包。一个可能的答案是,公司内部所有不直接感受到竞争压力的部门都应该外包出去,让它们暴露在竞争压力之下。(我这里所说的“外包”,指的是聘请另一个公司来执行,而不是指把业务部门转移到海外。)

六、如何创造财富


从经济学观点看,你可以把创业想象成一个压缩过程,你的所有工作年份被压缩成了短短几年。你不再是低强度地工作四十年,而是以极限强度工作四年。在高技术领域,这种压缩的回报尤其丰厚,工作效率越高,额外报酬就越高。

但是高回报高风险。

要致富,你需要两样东西:可测量性和可放大性。你的职位产生的业绩,应该是可测量的,否则你做得再多,也不会得到更多的报酬。此外,你还必须有可放大性,也就是说你做出的决定能够产生巨大的效应。

有一个办法可以发现是否存在可放大性,那就是看失败的可能性。

你最好找出色的人合作,因为他们的工作和你的一起平均计算。

乔布斯曾经说过,创业的成败取决于最早加入公司的那十个人。

小团队的优势不在于它本身的小,而在于你可以选择成员。我们不需要小村庄的那种“小”,而需要全明星第一阵容的那种“小”。

假定软件有两个候选的新功能,它们创造的商业价值完全相同,那么我们总是选择较困难的那个功能。不是因为这个功能能带来更多的收入,而是因为它比较难。我们很乐于迫使那些又大又慢的竞争对手跟着我们一起走进沼泽地。创业公司就像游击队一样,喜欢选择不易生存的深山老林作为根据地,政府的正规军无法追到那种地方。

大多数时候,促成买方掏钱的最好办法不是让买家看到有获利的可能,而是让他们感到失去机会的恐惧。

卖保健品也是这个套路。

要鼓励大家去创业,只要懂得藏富于民,国家就会变得强大。让书呆子保住他们的血汗钱,你就会无敌于天下。

七、关注贫富分化


事实上,财富与金钱是两个概念。金钱只是用来交易财富的一种手段,财富才是有价值的东西,我们购买的商品和服务都属于财富。

财富从何而来?人类创造出来的。

正如逻辑学的”奥卡姆剃刀“原则所说,简单的解释就是最好的解释。

技术的发展使得通过创造而积累财富的速度第一次有可能超过通过偷窃而积累财富的速度。

巴尔扎克说过: “每一笔巨大财富的背后,都隐藏着罪行。 ”

今天的人们多多少少还是有一些互相隔离的趋势,但主要是因为教育层次的差别,而不是财富的差别。

我怎么觉得,恰好相反呢。

八、防止垃圾邮件的一种方法


识别垃圾邮件特征的过滤器(比如 SpamAssassin )为每封邮件计算一个“得分”,而贝叶斯方法为每封邮件算出一个概率。“得分”方法的缺点在于没人知道这个分数到底是什么意思,用户不知道,更糟的是,就连过滤器的开发者也不知道。如果邮件中有 sex (性)这个词,请问得分是多少?计算概率当然也会出错,但是至少意义上很清楚,一点也不模糊,而且用来计算它的那些依据也很清楚。根据我的邮件库,一封邮件中含有 sex 这个词,那么它有 0.97 的概率是一封垃圾邮件;要是含有 sexy 这个词,垃圾邮件的概率更是上升到 0.99 。贝叶斯规则同样毫不含糊地表明,如果一封邮件同时含有这两个词,即使没有其他证据(事实上,这是不可能的),垃圾邮件的概率也将达到 99.97 %。

九、设计者的品味


数学家哈代才说:”丑陋的数学在世界上无法生存“

我觉得数学 or 物理是真的符合“奥卡姆剃刀“原则。

大多数做出优美成果的人好像只是为了修正他们严重丑陋的东西。

好设计是永不过时的设计。

说来奇怪,如果你希望自己的作品对未来的人们有吸引力,方法之一就是让你的作品对上几代人有吸引力。

老少咸宜真的好难啊。

好设计是启发性的设计。

在科学领域中,总体上可以把引用次数看作对他人启发性大小的粗略指标。

好设计是看似容易的设计

优秀运动员比赛时,让人觉得他轻轻松松就获胜了,优秀设计师也是如此,他们的工作看上去很容易。大多数时候,这是一种错觉。作家的文章读起来流畅自如,但是背后其实经过了反复修改。

有点像:台上一分钟,台下十年功。

对称有两种:重复性对称和递归性对称。

20 世纪 20 年代,不对称成了现代主义建筑的一个明确的前提条件。但是即使如此,这些建筑物往往也只是在主轴上不对称,细节部分依然大量使用对称。

好设计是模仿大自然的设计。我不是说模仿大自然这种行为本身有多么好,而是说大自然在长期的演化中已经解决了很多设计问题。所以,如果你的设计与大自然很接近,那么它基本上不会很差。

也可以说是借鉴(演化的很完美的)自然。

美术史上, 15 世纪油彩取代蛋彩( tempera )就是一个重大突破,油彩使得画家更方便地处理那些困难的主题(比如人体),因为油彩可以调制,还可以重画,蛋彩就做不到这些。

我想,最伟大的大师最终会达到一种超脱自我的境界。他们一心想找到正确答案,如果别人已经回答出了一部分,那就没理由不拿来用。他们足够自信地使用他人的成果,完全不担心因此丧失个人的特点

善于站在巨人的肩膀上。

推动人才成批涌现的最大因素就是,让有天赋的人聚在一起,共同解决某个难题。互相激励比天赋更重要,达 ·芬奇之所以成为达 ·芬奇,主要原因不仅仅是他的天赋,更重要的是他生活在当时的佛罗伦萨,而不是米兰。

让我坚信,去大城市是对的!

优秀作品的秘诀就是:”非常严格的品味,再加上实现这种品味的能力“。

品味和能力两者不可缺一。

十、编程语言解析


这种简便方式书写的程序所使用的语言就叫做高级语言。

高级语言还有一个优点,它使得程序更具有可移植性

编译器不是高级语言唯一的实现方法,另一种方法是使用解释器,它的作用是实时地将代码解释为相应的机器语言,然后一行行运行。相比之下,编译器则是先将整个程序全部翻译成机器语言,然后再运行。

编译器处理的高级语言代码又叫做源码。它经过翻译以后产生的机器码就叫做目标码。顾客购买市场上的商业软件时得到的往往只是目标码。(目标码很难读懂,所以相当于被加密了,可以保护公司的商业秘密。)

关于面向对象编程优劣的争论并不像静态类型动态类型之争那样壁垒分明,因为编程的时候你只能在静态类型和动态类型之中选一种。但是,面向对象编程只是程度不同的问题。事实上有两种程度的面向对象编程:某些语言允许你以这种风格编程,另一些语言则强迫你一定要这样编程。我觉得后一类语言不可取。允许你做某事的语言肯定不差于强迫你做某事的语言。

静态类型与动态类型之争:静态类型语言的拥护者认为这样可以防止 bug,并且帮助编译器生成更快的代码(这两点理由都成立)。动态类型语言的拥护者认为静态类型对程序构成了限制(这点理由也成立)。

关于面向对象编程优劣的争论并不像静态类型与动态类型之争那样壁垒分明,因为编程的时候你只能在静态类型和动态类型之中选一种。但是,面向对象编程只是程度不同的问题。事实上有两种程度的面向对象编程:某些语言允许你以这种风格编程,另一些语言则强迫你一定要这样编程。我觉得后一类语言不可取。允许你做某事的语言肯定不差于强迫你做某事的语言。

结果就是产生了一些也许可以称为 “头重脚轻 ”的语言:它们的内核设计得并非很好,但是却有着无数强大的函数库,可以用来解决特定的问题。(你可以想象一辆本身性能很差的小汽车,车顶却绑着一个飞机发动机。)

最常见的几种入侵计算机的手法都是利用了 C 语言的某些特点。当你在 C 语言中为输入的内容分配出一片内存(也叫“缓存”)时,它会被分配在当前运行代码的返回地址旁边。所谓“返回地址”指的是一块特定内存,当前代码运行完毕以后,就要运行这块内存中包含的代码。也就是说,它实际上是计算机下一步要做的事情。

假定有人打算入侵你的计算机,他们猜出你会为某种输入分配 256 字节的缓存,于是他们就提交多于 256 字节的内容,目的是覆盖旁边的“返回地址”。那么,当前代码运行完毕之后,程序的控制权就交给了他们指定的内存地址。这个地址通常是缓存的首地址,缓存中是入侵者事前编好的机器码。于是,入侵者的程序就运行在你的计算机上了。

如果使用更抽象的高级语言,上面的事情是不可能发生的。但是,在 C 语言中,一旦接受用户输入的时候你没有检查输入长度,就创造出了一个安全漏洞。利用这种漏洞的攻击行为就被称为“缓冲区溢出攻击”。在这种攻击中,还有其他方法可以控制计算机,但是覆盖返回地址是最经典的一种。有意思的是,劫持飞机与“缓冲区溢出攻击”有类似之处。在一般飞机上,乘客区与驾驶舱是相通的,就好像 C 语言中数据区与代码区是相邻的一样。劫机者一旦进入驾驶舱,实际上就相当于把自己从数据提升为代码。

十一、一百年后的编程语言


任何一种编程语言都可以分成两大组成部分:基本运算符的集合(扮演公理的角色)以及除运算符以外的其他部分(原则上,这个部分可以用基本运算符表达出来)。我认为,基本运算符是一种语言能否长期存在的最重要因素。

慎重选择公理还不够,还必须控制它的规模。数学家总是觉得公理越少越好,我觉得他们说到了点子上。

在长期的职业生涯中,我发现冗余的代码会导致更多冗余的代码

滚雪球效应。

我的判断是,那些内核最小、最干净的编程语言才会存在于进化的主干上。一种语言的内核设计得越小、越干净,它的生命力就越顽强。

编程语言进化缓慢的原因在于它们并不是真正的技术。语言只是一种书写法,而程序则是一种严格符合规则的描述,以书面形式记录计算机应该如何解决你的问题。所以,编程语言的进化速度更像数学符号的进化速度,而不像真正的技术(比如交通或通信技术)的进化速度。数学符号的进化是缓慢的渐变式变化,而不是真正技术的那种跳跃式发展。

就像现实中人类语言的进化也是缓慢的。

一百年后会有多少种编程语言?从最近来看,出现了大量的新语言。硬件性能提高是一个原因,这就允许程序员根据使用目的在运行速度和编程便利性之间做出不同的取舍。

essay(论文)这个词来自法语的动词 essayer,意思是 “试试看 ”。从这个原始意义来说,论文就是你写一篇文章,试着搞清楚某件事。软件也是如此。我觉得一些最好的软件就像论文一样,也就是说,当作者真正开始动手写这些软件的时候,他们其实不知道最后会写出什么结果。

有一句俗话说,如果你自己做不到,那就去当老师 。

当你设计语言的时候,心里牢牢记住这个目标是有好处的。学习开车的时候,一个需要记住的原则就是要把车开直,不是通过将车身对齐画在地上的分隔线,而是通过瞄准远处的某个点。即使你的目标只在几米开外,这样做也是正确的。

目光要长远。

十二、拒绝平庸


许多公司直到 80 年代还在用机器语言编程。我敢打赌,很多人对机器语言恋恋不舍,直到 CPU 开始采用精简指令集了才不得不放弃使用机器语言。

编程语言是技术和宗教的混合物。

确实,各个语言的信徒都能在网上掐起来。

十三、书呆子的复仇


Lisp 语言是无意中从纯理论发展为编程语言的,而 Fortran 从一开始就是作为编程语言设计出来的。

Lisp和 Fortran代表了编程语言发展的两大方向。前者的基础是数学,后者的基础是硬件架构。

在大型组织内部,有一个专门的术语描述这种跟随大多数人的选择的做法,叫做 “业界最佳实践”。这个词出现的原因其实就是为了让你的经理可以推卸责任。既然我选择的是 “业界最佳实践 ”,如果不成功,项目失败了,那么你也无法指责我,因为做出选择的人不是我,而是整个 “业界 ”。

背锅专用名词。

十四、梦寐以求的编程语言


一心让臣民行善的暴君可能是最专制的暴君

因为人心也不都是善的,违背人性即是暴君,顺应人心才是明君。

专家级黑客的看法不是决定一种语言流行程度的唯一因素,某些古老的软件( Fortran和 Cobol的情况)和铺天盖地的广告宣传( Ada和 Java的情况)也会起到作用。

虽然语言的核心功能就像大海的深处,很少有变化,但是函数库和开发环境之类的东西就像大海的表面,一直在汹涌澎湃。

如果你想设计一种流行的编程语言,就不能只是单纯地设计语言本身,还必须为它找到一个依附的系统,而这个系统也必须流行。

如果一种编程语言只有语法规则,没有一个好的实现( implementation ),那么它就不能算完整的编程语言。

黑客欣赏的一个特点就是简洁。

简洁性最重要的方面就是要使得语言更抽象。

简洁性是静态类型语言的力所不及之处。不考虑其他因素时,没人愿意在程序的头部写上一大堆的声明语句。

单个的语法单位也应该很简短。

对黑客来说,选择编程语言的时候,还有一个因素比简洁更重要,那就是这种语言必须能够帮助自己做到想做的事。

针对青年男性读者的 Maxim 杂志每年出版一本特辑,里面一半是美女照片,另一半是各种严重事故的现场照片。这本杂志非常清楚它的读者想看什么。

一种真正优秀的编程语言应该既整洁又混乱。 “整洁 ”的意思是设计得很清楚,内核由数量不多的运算符构成,这些运算符易于理解,每一个都有很完整的独立用途。 “混乱 ”的意思是它允许黑客以自己的方式使用。

类似简洁的基本功能,和支持高级的自定义拓展。

所谓一次性程序,就是指为了完成某些很简单的临时性任务而在很短时间内写出来的程序。

所以,编程时提高代码运行速度的关键是使用好的性能分析器( profiler),而不是使用其他方法,比如精心选择一种静态类型的编程语言。

随着互联网软件的兴起,越来越多的程序主要不是受限于计算机的运算速度,而是受限于 I/O 的速度。

所以现在 C10K 问题流行起来了。

在一些应用程序中,处理器的运算能力是瓶颈,那么最重要的优化对象就是软件的运行速度。但是,一般情况下内存才是瓶颈,你能够同时支持的用户数量取决于用户数据所消耗的内存。编程语言在这方面也能发挥作用,对线程的良好支持将使得所有用户共享同一个内存堆( heap)。持久化对象和语言内核级别的延迟加载( loading)支持也有助于减少内存需求。

人们真正注意到你的时候,不是第一眼看到你站在那里,而是发现过了这么久你居然还在那里。

新技术被市场接纳的方式有两种,一种是自然成长式,另一种是大爆炸式。

最终来看,自然成长式会比大爆炸式产生更好的技术,能为创始人带来更多的财富。如果你研究一下目前的主流技术,就会发现大部分都是源于自然成长式。

著名散文家 E.B.怀特说过, “最好的文字来自不停的修改 ”。

梦寐以求的编程语言让我们试着描述黑客心目中梦寐以求的语言来为以上内容做个小结。这种语言干净简练,具有最高层次的抽象和互动性,而且很容易装备,可以只用很少的代码就解决常见的问题。不管是什么程序,你真正要写的代码几乎都与你自己的特定设置有关,其他具有普遍性的问题都有现成的函数库可以调用。

这种语言的句法短到令人生疑。你输入的命令中,没有任何一个字母是多余的,甚至用到 Shift键的机会也很少。

这种语言的抽象程度很高,使得你可以快速写出一个程序的原型。然后,等到你开始优化的时候,它还提供一个真正出色的性能分析器,告诉你应该重点关注什么地方。你能让多重循环快得难以置信,并且在需要的地方还能直接嵌入字节码。

这种语言有大量优秀的范例可供学习,而且非常符合直觉,你只需花几分钟阅读范例就能领会应该如何使用此种语言。你偶尔才需要查阅操作手册,它本身很薄,里面关于限定条件和例外情况的警告寥寥无几。

这种语言的内核很小,但很强大。各个函数库高度独立,而且和内核一样经过精心设计,它们都能很好地协同工作。语言的每个部分就像精密照相机的各种零件一样完美契合,不需要为了兼容性问题放弃或者保留某些功能。所有函数库的源码都很容易得到。这种语言能够很轻松地与操作系统和用其他语言开发的应用程序对话。

这种语言以层的方式构建。较高的抽象层透明地构建在较低的抽象层之上。如果需要的话,你可以直接使用较低的抽象层。

除了一些绝对必要隐藏的东西,这种语言的所有细节对使用者都是透明的。它提供的抽象能力只是为了方便你的开发,而不是为了强迫你按照它的方式行事。事实上,它鼓励你参与它的设计,给你提供与语言创造者平等的权力。你能够对它的任何部分加以改变,甚至包括它的语法。它尽可能让你自己定义的部分与它本身定义的部分处于同等地位。这种梦幻般的编程语言不仅开放源码,更开放自身的设计。

醒醒!别活在梦里。

帕金森定律( Parkinson's Law )的一种原始表达形式是,后来引申到计算机领域就变成了“数据总是会填满所有空间”,更一般性的总结则是“对一种资源的需求总是会消耗光这种资源的所有供应”。

十五、设计与研究


设计与研究的区别看来就在于,前者追求 “好 ”( good),后者追求 “新 ”( new)。

所以,最终来说,设计和研究都通往同一个地方,只是前进的路线不同罢了。

可是,让用户满意并不等于迎合用户的一切要求。用户不了解所有可能的选择,也经常弄错自己真正想要的东西。做一个好的设计师就像做一个好医生一样。你不能头痛医头,脚痛医脚。病人告诉你症状,你必须找出他生病的真正原因,然后针对病因进行治疗。

就跟乔布斯说的一样,iPhone 没出来前,没人会意识到自己想要这个。

怎么理解编程语言?你不要把它看成那些已完成的程序的表达方式,而应该把它理解成促进程序从无到有的一种媒介。

评价一种语言的优劣不能简单地看最后的程序是否表达得很漂亮,而是看程序从无到有的那条完成路径是否很漂亮。某种设计使得最后的程序非常漂亮,但是不一定同时具备漂亮的编程过程。

我觉得可以理解成编程过程是否”优雅“。

在软件领域,贴近用户的设计思想被归纳为 “弱即是强 ”( is Better)模式。

先做出原型,再逐步加工做出成品,这种方式有利于鼓舞士气,因为它使得你随时都可以看到工作的成效。开发软件的时候,我有一条规则:任何时候,代码都必须能够运行。如果你正在写的代码一个小时之后就可以看到运行结果,这好比让你看到不远处就是唾手可得的奖励,你因此会受到激励和鼓舞。

小步迭代,步子别迈的太大。

跟你说实话吧,画家之间甚至流传着一句谚语:“画作永远没有完工的一天,你只是不再画下去而已。”这种情况对于第一线的程序员真是再熟悉不过了。

永远没有完成的代码,你可以反复的重构。这这点能不能把编程(工程)当成艺术呢?


拓展一、包豪斯

所以:注意包豪斯跟包豪斯主义的区别!

1、包豪斯历史关键点

1919年4月1日,包豪斯在德国魏玛市成立;

尽管它只存在从1919到1933年短短的14年,并先后3迁校址魏玛、德绍、柏林。

1931年,纳粹党在德绍大选获胜,包豪斯被纳粹主义认为是布尔什维克主义,是“非德国”的事物,而被下令关闭学校。

1933年在纳粹政权的压迫下,包豪斯宣布关闭,同年也是魏玛共和的结束。

大批的师生为了逃避迫害,都逃亡到美国,将现代主义设计发展成后来的国际主义,格罗皮乌斯在哈佛成立了哈佛设计学院,培养了贝聿铭等大师,米斯凡德罗建立了芝加哥设计学院,而德国剩余的包豪斯学员在1953年至1969年在德国也建立了乌尔姆学院,延续了包豪斯的精神,但影响已经大不如前。

2019年4月1日,包豪斯成立100周年纪念日。

2、包豪斯特征

1、形式追随功能

形式应该是内容本身。

设计的目的是人而不是产品

艺术与技术的新统一,符合和促进了工业化生产。

2、忠实于原材料

设计需遵循自然法则进行 。

例如不要企图让水泥伪造成木头。

3、少即是多

他们反对多余的装饰,奉行“少即多”的原则。

极简主义、激进字体、几何元素、多用明亮色彩。

就像《神雕侠侣》里独孤九剑的「重剑无锋,大巧不工」。

3、包豪斯起源

包豪斯兼容了荷兰的风格派俄罗斯的构成派

杜斯伯格建立的「风格派」又叫新造型主义画派,宗旨是完全拒绝使用任何的具象元素,只用单纯的色彩和几何形象来表现纯粹的精神。而且早期杜斯伯格强调直线的运用,随后又主张使用斜线来营造画面动感,以后只要看到类似的用色用线条,就知道这是源自荷兰的风格派。

构成主义是指由一块块金属、玻璃、木块、纸板或塑料组构结合成的雕塑。强调的是空间中的势(movement),而不是传统雕塑着重的体积量感。

4、包豪斯的影响

它的成立标志着现代设计教育的诞生,也奠定了现代主义设计的基础。

包豪斯在艺术、建筑、工业设计、平面设计、室内设计、现代戏剧、现代美术等领域上的发展都具有显著的影响。

影响了包括苹果等现代数码产品的设计。

5、包豪斯的贡献

现在的设计教学中,有一个非常重要的学习体系,叫三大构成,而这个体系就是由包豪斯奠定。

三大构成即平面构成色彩构成立体构成,是现代艺术设计基础的重要组成部分。

6、包豪斯的缺点

1、忽视了人们的生理需求

例如有些椅子的设计为了极简的美感,并没有考虑到人体工程学的因素。

2、忽视了人们的心理需求

由于它过于重视形式的简约,一味强调满足人类的物理需求,从而忽视了人们对产品的心理需求。机械、呆板、冰冷感、缺乏人情味和历史感的「包豪斯」,因此受到“后现代主义”的批评。

后现代主义,源自现代主义但又反叛现代主义,是对现代化过程中出现的剥夺人的主体性和感觉丰富性,进行的批判与解构。波普艺术的兴起,标志着西方的现代主义向后现代主义转变。

3、形式主义

“立方体就是上帝”,无论何种产品,何种材料都采用几何造型,从而走上了形式主义的道路,有时甚至破环了产品的使用功能。

正如上面说的,过犹不及导致忽视了人们的生理需求或心理需求。

4、价格高昂

不少包豪斯的产品仍价格高昂,只能被视为一种审美水准和社会地位的象征,如米斯的巴塞罗那椅就是典型的例子,售价达数百美元。

5、风格千篇一律

例如包豪斯的建筑导致了千篇一律的国际主义风格。有没有发现如今国内很多城市的建筑都差不多。


拓展二、墨菲定律/帕金森定律/彼得原理 区别

1、墨菲定律

含义:凡是可能出错的事均会出错

启示:要有忧患意识,防微杜渐。同时做好备灾方案和补救措施。

2、帕金森定律

含义:只要还有时间,工作就会不断扩展,直到用完所有的时间。即“工作总是到最后一刻才会完成”。

启示:合理定好截止日期,安排充足又适量的任务。

3、彼得原理

含义:在组织或企业的等级制度中,人会因其某种特质或特殊技能,令他在被擢升到不能胜任的地步,相反变成组织的障碍物(冗员)及负资产。

启示:量力而为,不逞强,出来混都是要还的。企业认命人事升迁时也要考虑,有的人业务能力强不代表领导能力也好。


读后感

这本书真的让我重新认识了编程,也思考了很多编程和艺术之前的微妙联系。很有启发。推荐所有程序员读一读。

你可能感兴趣的:(程序员也可能是艺术家——《黑客与画家》 读书笔记)