《黑客与画家》读书笔记
《黑客与画家》读书笔记
作者:【美】格雷厄姆
保罗·格雷厄姆其人其事
Y Combinator (Y运算子,简称YC)
YC在每年的一月和六月举办两次训练营,每次为期三个月。通常每次大概有500个申请者,他们从中挑出20个项目 。每个项目将得到1.1万美元的启动资金,外加每个项目成员3000美元的生活津贴,交换条件是YC将拿走该项目5%的股份 。如果项目成功,5%的股份将非常值钱。
保罗·格雷厄姆有一套完整的创业哲学,他的创业公式是:
(1)搭建原型
(2)上线运营(别管bug)
(3)收集反馈
(4)调整产品
(5)成长壮大
首先,他鼓励创业公司快速发布产品,因为这样可以尽早知道一个创意是否可行。其次,他认为一定要特别关注用户需要什么,这样才有办法将一个坏项目转变成好项目。
比起那些令人叫好的创意,格雷厄姆更看重创始人的素质。他说:“我们从一开始就认识到,创始人本身比他的创意更重要。”他还认为,小团队更容易成功,创始成员总数最好不要超过三个人。其中一个原因是,创始人越多,股权越不容易平等分配,容易造成内耗。
译者序
20世纪60年代初,麻省理工学院有一个学生团体叫做“铁路模型技术俱乐部”(Tech Model Railroad Club,简称TMRC),他们把难题的解决方法称为hack。
在这里,hack作为名词有两个意思,既可以指很巧妙或很便捷的解决方法,也可以指比较笨拙、不那么优雅的解决方法。两者都能称为hack,不同的是,前者是漂亮的解决方法(cool hack或neat hack),后者是丑陋的解决方法(ugly hack或quick hack)。
完成这种hack的过程就被称为hacking,而从事hacking的人就是hacker,也就是黑客。
hack还有一个引申义,指对某个程序或设备进行修改,使其完成原来不可用的功能(或者禁止外部使用者接触到的功能)。在这种意义上,hacking可以与盗窃信息、信用卡欺诈或其他计算机犯罪联系在一起,这也是后来“黑客”被当作计算机入侵者的称呼的原因。
自由软件基金会创始人理查德·斯托尔曼说:“出于兴趣而解决某个难题,不管它有没有用,这就是黑客。”
恶意入侵计算机系统的人应该被称为cracker(入侵者)
本书的一些章节中作者谈论的都是计算机行业的专业问题,但是他又希望让普通读者看懂,试图用口语化、生活化的语言解释专业概念,我个人感觉效果不太理想,反而使得行文稍显冗余和模糊,这一点提醒读者注意。
前言
我们生活中的一切,都正在成为计算机。
旅游网站Orbitz成功打入了竞争激烈的网络订房订票市场。该市场原先被两大巨头主宰,一个是微软公司,另一个是拥有数十年电子预定服务经验的Sabre。Orbitz是怎么从它们手中抢到市场的?最主要的原因就是它使用了一种更好的编程语言。
Slashdot 它是黑客世界的《纽约时报》
虽然黑客从外表看上去一般都是呆呆的,但是他们的大脑内部却是一个有趣得让你吃惊的地方。
1 为什么书呆子不受欢迎
文艺复兴时期的代表人物阿尔伯蒂有一句名言:“任何一种艺术,不管是否重要,如果你想要在该领域出类拔萃,就必须全身心投入。”
在任何社会等级制度中,那些对自己没自信的人就会通过虐待他们眼中的下等人来突显自己的身份。
但是我认为,孩子们欺负书呆子的主要原因也与追求“受欢迎”的心理有关。怎样才能让自己更受欢迎?个人魅力只是很小的一方面,你应该更多地考虑如何结盟。秘诀就是不停地设法使自己与其他受欢迎的人变得关系更密切。没有什么比一个共同的敌人更能使得人们团结起来了。
当你所做的事情能产生真实的效果,那就不仅仅是好玩而已了,发现正确的答案就开始变得重要了,这正是书呆子的优势所在。
青少年都不喜欢孤独一人,即使具有叛逆心理的青少年也是如此。
2 黑客与画家
我现在认为,大学里教给我的编程方法都是错的。
你把整个程序想清楚的时间点,应该是在编写代码的同时,而不是在编写代码之前
编程语言首要的特性应该是允许动态扩展(malleable)。编程语言是用来帮助思考程序的,而不是用来表达你已经想好的程序。
静态类型(static typing)
等我来到雅虎以后,发现在他们看来,“黑客”的工作就是用软件实现某个功能,而不是设计软件。在那里,程序员被当作技工,职责就是将产品经理的“构想”(如果这个词是这么用的话)翻译成代码。
真正竞争软件设计的战场是新兴领域的市场
我们面试程序员的时候,主要关注的事情就是业余时间他们写了什么软件。因为如果你不爱一件事,你不可能把它做得真正优秀,要是你很热爱编程,你就不可避免地会开发你自己的项目。
也许对于黑客来说,采取像画家这样的做法很有好处:应该定期地从头开始,而不要长年累月地在一个项目上不断工作,并且试图把所有的最新想法都以修订版的形式包括进去。
你不能盼望先有一个完美的规格设计,然后再动手编程,这样想是不现实的。如果你预先承认规格设计是不完美的,在编程的时候,就可以根据需要当场修改规格,最终会有一个更好的结果。
(大公司的内部结构,使得它们很难这样做。这是又一个创业公司占优之处。)
如果你查看优秀软件的内部,就会发现那些预料中没有人会看见的部分也是优美的。
正确的合作方法是将项目分割成严格定义的模块,每一个模块由一个人明确负责。模块与模块之间的接口经过精心设计,如果可能的话,最好把文档说明写得像编程语言规范那样清晰。
就像绘画作品一样,大多数软件是为人类用户准备的。所以,黑客必须像画家一样,时刻考虑到用户的人性需要,这样才能做出伟大的产品。你必须能够站在用户的角度思考问题,也就是说你必须学会“换位思考”。
判断一个人是否具备“换位思考”的能力有一个好方法,那就是看他怎样向没有技术背景的人解释技术问题。
软件的部分功能就是解释自身。为了写出优秀软件,你必须假定用户对你的软件基本上一无所知。你要明白,用户第一次使用你的软件的时候,不会预先做好功课,他们没有任何准备就开始用了,所以软件的使用方式最好能符合用户的直觉,别指望用户去读使用手册。
源代码也应该可以自己解释自己。如果我只能让别人记住一句关于编程的名言,那么这句名言就是《计算机程序的结构与解释》一书的卷首语:
程序写出来是给人看的,附带能在机器上运行。
3 不能说的话
到底什么话是我们不能说的?为了找到答案,首先,我们可以看看,周围的人因为说了什么而陷入麻烦。
第一个条件是,这些话不能说出口;第二个条件是,它们是正确的,或者看起来很可能正确,值得进一步讨论。如果达不到第二个条件,大部分情况下你都不会有麻烦。
触怒他人的言论是那些可能会有人相信的言论。我猜想,最令人暴跳如雷的言论,就是被认为说出了真相的言论。
这就是找出“不能说的话”的第一种方法:判断言论的真伪。
除了真话以外,“不能说的话”还有一种可能。有些想法,纯粹因为非常特别,而不能说出口。比如,某个话题极其富有争议,不管是对是错,没有人敢在公开场合谈论它。我们怎样才能发现这种情况呢?
我们把这种不一定正确、但是极富争议的言论称为“异端邪说”。关注“异端邪说”,是找出“不能说的话”的第二种方法。
历史上的每一个年代,都会给“异端邪说”贴一些标签,目的是在人们开始思考它们是否为真之前就把它们封杀。“亵渎神明”、“冒犯圣灵”、“异端”都是西方历史上常见的标签,当代的标签则是“有伤风化”、“不得体”、“破坏国家利益”等。以前时代的标签在今天已经不可避免地失去了杀伤力,最多只能用于讽刺。
所以,如何找出那些我们自以为正确却会被未来人们耻笑的话?方法就是关注这些标签!
给放射科医生看胸部X光片,请他们判断病人有没有肺癌迹象。研究人员记录了医生检查X光片时的眼球运动。研究发现,即使那些医生漏掉了一个癌症病灶,他们的目光通常也会在那个地方停留一会。这说明他们的头脑深处已经意识到那里有问题,但是这种深层的反应没有上升为自觉的意识。我认为,类似的思维机制存在于每个人的头脑中,很多看似叛逆的“异端邪说”,早就“潜伏”在我们的思维深处。如果我们暂时关闭自我审查意识,它们就会第一个浮现出来。
我们可以去找那些过去被认为理所当然,如今却被认为不可思议的事情,这是用来找出我们自己正在犯下的错误的第三种方法。
大多数的斗争,不管它们实际上争的是什么,都会以思想斗争的形式表现出来。
思想斗争更容易争取支持者。不管哪一方获胜,他们所代表的思想也就被认为获得了胜利
我并不是说斗争从来就与思想无关,而是要强调,不管实际上是否有思想斗争,斗争总是会以思想斗争的形式表现出来。
想要做出优秀作品,你需要一个什么问题都能思考的大脑。尤其是那些似乎不应该思考的问题,你的大脑也要养成思考它们的习惯。
优秀作品往往来自于其他人忽视的想法,而最被忽视的想法就是那些被禁止的思想观点。
智力越高的人,越愿意去思考那些惊世骇俗的思想观点。
不仅是在科学领域,在任何有竞争的地方,只要你能看到别人看不到或不敢看的东西,你就有很大的优势。
训练自己去想那些不能想的事情,你获得的好处会超过所得到的想法本身。
如果你能“远远地”跳出传统思维,提出让别人一听就脑袋轰一声炸开的惊人观点,那么你就在“小小地”跳出传统思维方面不会有任何困难。要知道,人们把后面的这种情况称为“创新”。
一旦发现了“不能说的话”,下一步怎么办?我的建议就是别说,至少也要挑选合适的场合再说,只打那些值得打的仗。
这时你要明白,自由思考比畅所欲言更重要。如果你感到一定要跟那些人辩个明白,绝不咽下这口气,一定要把话说清楚,结果很可能是从此你再也无法自由理性地思考了。我认为这样做不可取,更好的方法是在思想和言论之间划一条明确的界线。在心里无所不想,但是不一定要说出来。我就鼓励自己在心里默默思考那些最无法无天的想法。你的思想是一个地下组织,绝不要把那里发生的事情一股脑说给外人听。
每个时代都有自己的忌讳,如果你触犯它们,就算没有坐牢,至少也会为自己惹来麻烦,干扰了正常生活。
“不能说的话”太多了,如果口无遮拦,你就没时间做正事了。
“守口如瓶”的真正缺点在于,你从此无法享受讨论带来的好处了。讨论一个观点会产生更多的观点,不讨论就什么观点也没有。所以,如果可能的话,你最好找一些信得过的知己,只与他们畅所欲言、无所不谈。这样不仅可以获得新观点,还可以用来选择朋友。能够一起谈论“异端邪说”并且不会因此气急败坏的人,就是你最应该认识的朋友。
人们喜欢讨论的许多问题实际上都是很复杂的,马上说出你的想法对你并没有什么好处。
历史上,荷兰人确实长期具有相对开放的思想。几个世纪以来,这个地势低洼的欧洲国家一直是言论相对自由的地方。在那里,你可以放心说出其他地方不能说的话。这帮助它成为学术和工业的中心。(言论自由与这两者紧密结合的历史,比大多数人意识到的还要长。)
4 良好的坏习惯
黑客都用同一个词形容
注: terrific
在我看来,一个人们拥有言论自由和行动自由的社会,往往最有可能采纳最优方案,而不是采纳最有权势的人提出的方案。
应用服务供应商(Application Service Provider),简称ASP。
由于软件转移到服务器的趋势才刚刚开始,所以我下面所写的是对未来的憧憬。
有一种编程方法叫做“函数式编程”(functional programming),
函数式编程在学术文献中研究得比较多,在商业软件中用得比较少。
实现某个构思,会带来更多的构思。
要让软件变得可靠,关键是你要全神贯注,而不是开发得很慢。
如果你亲眼见到某人第一次使用你的软件,你就会知道软件的哪个地方最打动他。
如果某样东西易于购买,你就会多买一点。
最好的安排就是把个人和小企业客户放在第一位。其他的客户该来的时候就会来。
现在,善于写软件的那类人更喜欢使用Linux或者FreeBSD操作系统。
互联网做起来很辛苦,还有许多特别大的压力,但是它们的唯一作用,就是使得创业公司成功的机会变大。
管理企业其实很简单,只要记住两点就可以了:做出用户喜欢的产品,保证开支小于收入。只要做到这两点,你就会超过大多数创业公司。
至于如何做出用户喜欢的产品,下面是一些通用规则。从制造简洁的产品开始着手,首先要保证你自己愿意使用。然后,迅速地做出1.0版,并且不断加以改进,整个过程中密切倾听用户的反馈。用户总是对的,但是不同的用户要求不一样。低端的用户要求简化操作和清晰易懂,高端的用户要求你增加新功能。软件最大的好处就是让一切变得简单。但是,做到这一点的方法是正确设置默认值,而不是限制用户的选择。如果竞争对手的产品很糟糕,你也不要自鸣得意。比较软件的标准应该是看对手的软件将来会有什么功能,而不是现在有什么功能。无论何时,你都要使用自己的软件。
如果你不打算自己动手设计和开发,那就不要创业。
6 如何创造财富
真正重要的是做出人们需要的东西,而不是加入某个公司。
要致富,你需要两样东西:可测量性和可放大性。
可放大性,也就是说你做出的决定能够产生巨大的效应。
有一个办法可以发现是否存在可放大性,那就是看失败的可能性。因为收入和风险是对称的,所以如果有巨大的获利可能,就必然存在巨大的失败可能。
如果你有一个令你感到安全的工作,你是不会致富的,因为没有危险,就几乎等于没有可放大性。
高科技 = 可放大性
创业公司通过发明新技术盈利,所以具备可放大性。
选择公司要解决什么问题应该以问题的难度作为指引,而且此后的各种决策都应该以此为原则。
设置“进入壁垒”的方法之一就是申请专利。
如果你开发出来的技术是竞争对手难于复制的,那就够了,你不需要依靠其他防御手段了。
一种很普遍的情况是,某个创业公司确实在开发一个很好的产品,但是开发时间太长了一点,结果资金都用完了,只好关门散伙。
潜在的买家会尽可能地拖延收购。收购这件事最难的地方就是让买方真正拿出钱。大多数时候,促成买方掏钱的最好办法不是让买家看到有获利的可能,而是让他们感到失去机会的恐惧。对于买家来说,最强的收购动机就是看到竞争对手可能收购你。
次强的动机则是让他们担心如果现在不买你,你的高速成长将使得未来的收购耗资巨大,甚至你本身可能变成一个他们的竞争对手。
不应该收购的危险信号。排在榜首的信号中有一个就是公司由技术顽童掌控,只想解决有趣的技术问题,不考虑用户的需要。你开办创业公司不是单纯地为了解决问题,而是为了解决那些用户关心的问题。
做过软件优化的人都知道,优化难点就是如何测出系统的表现。
将公司管理视同软件优化还能帮助你避免VC担心的另一个陷阱——开发某种产品的时间过长。现在,黑客都已经熟知这一点,并总结出一个术语“过早优化”(premature optimization)。尽快拿出1.0版,然后根据用户的反映而不是自己的猜测进行软件优化。
政府禁止个人积累财富实际上就是命令人民减慢工作的速度。
只要懂得藏富于民,国家就会变得强大。
7 关注贫富分化
简单的解释就是最好的解释。
一个人的工作具有多少价值不是由政府决定的,而是由市场决定的。
8 防止垃圾邮件的一种方法
只要对单个词语进行贝叶斯判断,就能很好地过滤大部分垃圾邮件。
9 设计者的品味
好设计是简单的设计。
保持简单
好设计是永不过时的设计。
如果解决方法是丑陋的,那就肯定还有更好的解决方法,只是还没有发现而已。
如果你不愿别人的答案取代你的答案,你就只好自己做出最佳答案。
好设计是解决主要问题的设计。
好设计是启发性的设计。
好设计通常是有点趣味性的设计。
幽默感是强壮的一种表现,始终拥有幽默感就代表你对厄运一笑了之,而丧失幽默感则表示你被厄运深深伤到。
好的设计并非一定要有趣,但是很难想象完全无趣的设计会是好的设计。
好设计是艰苦的设计。
如果你工作得不艰苦,你可能正在浪费时间。
好设计是看似容易的设计。
练习的作用也许是训练你把刻意为之的事情变成一种自觉的行为。有时,我们的训练只是为了让身体养成下意识的反应。
对称有两种:重复性对称和递归性对称。递归性对称就是指子元素的重复,比如树叶上叶脉的纹路。
在软件中,能用递归解决的问题通常代表已经找到了最佳解法。
好设计是一种再设计。
先完成一个早期原型,然后提出修改计划,最后把早期原型扔掉。
你应该培养对自己的不满。
推动人才成批涌现的最大因素就是,让有天赋的人聚在一起,共同解决某个难题。互相激励比天赋更重要
好设计常常是大胆的设计。
单单是无法容忍丑陋的东西还不够,只有对这个领域非常熟悉,你才可能发现哪些地方可以动手改进。
10 编程语言解析
Fortran、Lisp、Cobol、Basic、C、Pascal、Smalltalk、C++、Java、Perl和Python,全都是高级语言。
11 一百年后的编程语言
任何一种编程语言都可以分成两大组成部分:基本运算符的集合(扮演公理的角色)以及除运算符以外的其他部分(原则上,这个部分可以用基本运算符表达出来)。
我认为,基本运算符是一种语言能否长期存在的最重要因素。其他因素都不是决定性的。
你仔细审视一种语言的内核,考虑哪些部分可以被摒弃,这至少也是一种很有用的训练。在长期的职业生涯中,我发现冗余的代码会导致更多冗余的代码,不仅软件如此,而且像我这样性格懒散的人,我发现在床底下和房间的角落里这个命题也成立,一件垃圾会产生更多的垃圾。
我的判断是,那些内核最小、最干净的编程语言才会存在于进化的主干上。一种语言的内核设计得越小、越干净,它的生命力就越顽强。
随着技术的发展,每一代人都在做上一代人觉得很浪费的事情。
效率低下的软件并不等于很烂的软件。一种让程序员做无用功的语言才真正称得上很烂。浪费程序员的时间而不是浪费机器的时间才是真正的无效率。随着计算机速度越来越快,这会变得越来越明显。
并行计算(parallel computation)
性能分析器(profiler)
(1)一百年后的编程语言在理论上今天就能设计出来;
(2)如果今天真能设计出这样一种语言,很可能现在就适合编程,并且能够产生更好的结果。
12 拒绝平庸
埃里克·雷蒙德写过一篇文章《如何成为一名黑客》(How to Become a Hacker)。文中有一部分专门谈到,在他看来,如果你想当一个黑客,应该学习哪些语言。他建议从Python和Java入手,因为它们比较容易学。想当高级一点的黑客,还应该学习C和Perl。前者用来对付Unix系统,后者用来系统管理和开发CGI脚本。最后,真正非常严肃地把黑客作为人生目标的人,应该考虑学习Lisp:
Lisp很值得学习。你掌握它以后,会感到它给你带来的极大启发。这会大大提高你的编程水平,使你成为一个更好的程序员。尽管在实际工作中极少会用到Lisp。
软件业是竞争非常激烈的行业,而且容易出现垄断。在不考虑其他情况的条件下,某家公司的软件更快更好用,就会把竞争者赶出这个市场。一旦你开始创业,你就会更深切地感受到这一点。一般情况是,创业公司要么赢得一切,要么彻底失败。你要么成为富翁,要么一无所获。创业的时候,如果你选择了错误的技术,竞争对手就会一举打败你。
选择使用哪一种技术的时候,你不能考虑别人的做法,只能考虑什么样的技术能最好地完成工作。
大公司可以互相模仿,但是创业公司就不行。
如果开发只在自己服务器上运行的软件,这意味着你想用什么语言就能用什么语言。
在Viaweb创业期间我从来没有公开谈论过Lisp语言。我们对新闻媒体闭口不谈Lisp,如果你在我们的网站上搜索Lisp,只会发现我在个人介绍中提到过两次,那是我写的两本关于Lisp的书。这是故意的,创业公司对竞争对手应该越保密越好。
闭包
Lisp代码由Lisp数据对象构成。其他语言的源代码一般由字符组成,字符串是主要数据类型之一,但是Lisp语言不完全是这样。经过解析器处理之后,Lisp代码就变成了你可以遍历的数据结构。
如果你理解编译器的工作原理,那么事实是,与其说Lisp有一种很奇特的语法,还不如说它根本没有语法。一般的源代码程序经过编译器解析会生成解析树。Lisp的奇特之处就在于,你可以完全写出程序,控制这种解析树,进行任意的存取操作。Lisp的这种程序就叫做宏,它们可以用来生成其他程序。
Ansi Common Lisp
注: 作者的另一本书
编程语言不一样,与其说它是技术,还不如说是程序员的思考模式。
如果你为创业公司工作,那么这里有一个评估竞争对手的妙招——关注他们的招聘职位。他们网站上的其他内容无非是一些陈腐的照片和夸夸其谈的文字,但是招聘职位却不得不写得很明确,反映出他们到底想干什么,否则就会引来一大批不合适的求职者。
最不用担心的竞争对手就是那些要求应聘者具有Oracle数据库经验的公司,你永远不必担心他们。如果是招聘C++或Java程序员的公司,对你也不会构成威胁。如果他们招聘Perl或Python程序员,就稍微有点威胁了。至少这听起来像一家技术公司,并且由黑客控制。如果我有幸见到一家招聘Lisp黑客的公司,就会真的感到如临大敌。
13 书呆子的复仇
快速排序(Quicksort)算法
这种算法是1960年提出的,至今仍然是最快的通用排序方法。
如果你创业的话,千万不要为了取悦风险投资商或潜在并购方而设计你的产品。让用户感到满意才是你的设计方向。只要赢得用户,其他事情就会接踵而来。如果没有用户,谁会关心你选择的“正统”技术是多么令人放心。
总的来说,你的经理其实不关心公司是否真的能获得成功,他真正关心的是不承担决策失败的责任。所以对他个人来说,最安全的做法就是跟随大多数人的选择。
第一,不同语言的编程能力不一样。
第二,大多数经理故意忽视第一点。
14 梦寐以求的编程语言
脚本语言(scripting language)
布赖恩·柯尼汉和丹尼斯·里奇合写的《C程序设计语言》(C Programming Language)
开发大型程序的另一个方法就是从一次性程序开始,然后不断地改进。
函数库的使用应该符合程序员的直觉,让他可以猜得出哪个函数能满足自己的需要。
大多数人接触新事物时都学会了使用类似的过滤机制。甚至有时要听到别人提起十遍以上他们才会留意。这样做完全是合理的,因为大多数的热门新商品事后被证明都是浪费时间的噱头,没多久就消失得无影无踪。
所以,发明新事物的人必须有耐心,要常年累月不断地做市场推广,直到人们开始接受这种发明。
简单重复同一个信息就能解决这个问题。你只需要不停地重复同一句话,最终人们将会开始倾听。人们真正注意到你的时候,不是第一眼看到你站在那里,而是发现过了这么久你居然还在那里。
“最好的文字来自不停的修改”。所有优秀作家都知道这一点,它对软件开发也适用。设计一样东西,最重要的一点就是要经常“再设计”
15 设计与研究
假定你正在设计一种工具,你可以把目标用户定为初学者,也可以定为专家级用户。一种人眼里的优秀设计可能在另一种人眼里却是糟糕无比。这里的重点是你必须选出某些人作为你的目标用户。
我觉得,除非设定目标用户,否则一种设计的好坏根本无从谈起。
如果目标用户群体涵盖了设计师本人,那么最有可能诞生优秀设计。
如果目标用户与你本人差别很大,你往往会假定目标用户的需求比你本人的需求更简单,而不是更复杂。低估用户(即使出于善意)一般来说总是会让设计师出错。
如果你觉得自己在为傻瓜设计产品,那么很可能不仅无法设计出优秀产品,而且就连傻瓜也不喜欢你的设计。
在软件领域,贴近用户的设计思想被归纳为“弱即是强”(Worse is Better)模式
那就是如果你正在设计某种新东西,就应该尽快拿出原型,听取用户的意见。
开发软件的时候,我有一条规则:任何时候,代码都必须能够运行。如果你正在写的代码一个小时之后就可以看到运行结果,这好比让你看到不远处就是唾手可得的奖励,你因此会受到激励和鼓舞。
术语解释
抽象(abstract) 隐藏细节。编程语言越抽象,你写出程序所需的运算步骤就越少,每一步的功能就越强。
算法(algorithm) 完成任务的方法。菜谱也算是算法。
字母数字式字符(alphanumeric character) 26个英文字母和10个阿拉伯数字的总称。
数组(array) 一种存储数据的方式,教材中又称矩阵(matrix),即一个个用数字编号的存储空间,排列成一个n维的集合。
应用服务提供商(ASP,Application Service Provider) 这种软件公司允许用户通过网络使用存放在服务器上的软件,而不是采用传统的方式让用户在自己的电脑上安装软件后使用。
贝叶斯定理(Bayesian) 一种统计推断的方法,又称贝叶斯算法。
二进制(binary) 如果这个词前面有冠词(比如a binary),指的是软件的目标码。如果没有冠词,指的是采用二进制(而不是日常使用的十进制)作为表示数字的方法
位操作(bit manipulation) 对某个内存区域的一些简单转换操作,比如在屏幕上移动窗口就可以通过位操作实现。
代码膨胀(bloatcode) 程序过于冗长,大大超过合理的长度。
块结构(block-structured)
Blub困境(Blub Paradox) 程序员的思想往往会受到自己正在使用的语言的束缚,不相信还存在更强大的语言。
自下而上编程法(bottom-up programming) 一种编程的风格,与早期的“自上而下编程法”(top-down)正好相反,“自上而下编程法”要求你把编程任务分解成一个个更小的单元,“自下而上编程法”要求你先开发最底下的层,然后用底层所定义的“语言”开发上一层,这样直到最高层。这两种编程法可以结合使用。
限制(bound) 受到某种资源的约束,比如I/O限制、内存限制、CPU限制等。
跳转(branch) 机器语言的goto命令。
布鲁克斯假说(Brooks’s Hypothesis) 程序员一天写出的代码行数是一个常量,与他使用什么语言无关。
缓冲区(buffer) 一个内存区域,用来保存程序需要的输入数据,或者将程序的输出数据累积起来,到一定数量后再输出。
缓冲区溢出攻击(buffer overflow attack)
字节码(byte code) 类似于机器语言的计算机语言,但是不局限于特定的计算机。由于字节码与机器语言很类似,所以很容易开发出字节码解释器,让它把字节码转换成相应的机器语言命令。
CGI脚本(Common Gateway Interface script,通用网关接口脚本) 当网络服务器需要进行某种运算(比如数据库搜索)而不是直接传输现有文件时所运行的一种程序。CGI脚本的主要缺点是,每次运行只能生成一个页面,无法像桌面软件那样将数据保存在内存中从而实现与用户的不间断对话。
校验和(checksum) 一种用特征值验证文件的方法。特征值通过对文件的所有信息进行某种计算而产生。
循环定义(circular definition) 参见“无限循环”(infinite loop)。
类(class) 面向对象编程语言的一种数据类型。
点击轨迹(click trail) 同一个用户向网络服务器发出的一系列HTTP请求,基本等同于他浏览的网页顺序。
托管(collocated) 通常指放在ISP处。
注释(comment)
Common Lisp Lisp语言的一种流行的方言
编译器(compiler)
“解释器”(interpreter)
复杂度(complexity) 算法的“时间复杂性”(time complexity)指的是,当输入的数据量不断增加时,计算机完成这种算法所消耗的时间。比如,假定你要在一间屋子中寻找某一个人,方法是看每个人的脸,那么找到这个人所需要的时间与屋中的人数成正比。这样一种算法就叫做O(n),意为所需的时间与n成比例(n代表数据量)。现在进一步假设你要在屋子中寻找看上去长得很像的两兄弟(或两姐妹),那么你所需要的时间可能与人数的平方成正比,因为你也许不得不每两个人就比较一次,而所有可能的两人组合是人数的平方,算法就是O(n︿2)。
条件结构(conditional)
基于内容的过滤(content-based filtering) 根据电子邮件的内容而不是它的外部特征(比如发信地址)进行过滤。
CPU(中央处理器,Central Processing Unit)
处理器现在广泛用于各种各样的设备,比如显卡和硬盘。
崩溃(crash) bug引起的操作系统或应用程序停止正常工作。用在硬盘上面也指硬件失灵。
冗余(cruft)
周期(cycle) 执行一个机器指令的最少时间。一台内部时钟频率1 GHz的计算机可以在1秒内完成10亿个周期,即每秒执行10亿条机器指令。
DARPA(美国国防部高级研究计划局,Defense Advanced Research Projects Agency) 一个赞助美国国内很多计算机研究项目的机构。
数据结构(data structure) 一种由多个部分组成的数据格式。比如,一对数据可以组成一个数据结构,表示图形上的一个点。
数据类型(data type) 编程语言处理的数据种类。
动态类型(dynamic typing)
静态类型(static typing)
排错(debugging)
声明(declaration) 程序的要素之一,描述的成分多于命令的成分。最常见的声明是变量类型声明,用于说明一个变量包含哪一类数据。
废弃(deprecated) 原来属于标准的某种做法,现在它的设计者后悔做出了这样的设计。
设计战争(design war) 一种竞争规则,只要是最好的设计就能获胜,而不是其他因素(比如广告宣传、销售渠道的控制)主导竞争。
硬件驱动程序(device driver) 操作系统的一部分,使操作系统可以与硬件设备(比如打印机)对话。
diff 对某件东西的两个版本进行客观的、精细的比较。这个词源自Unix操作系统的一个用来比较文件的应用程序。
嵌入式语言(embedded language) 在一种语言内部定义的另一种语言,常用于解决某些特殊的问题。比如,如果你定义了一系列操作图像的命令,你就可以把它们视为一种操作图像的语言,参见“自下而上编程法”(bottom-up programming)。
最终用户(end user) 需求很简单的用户的婉转说法。
编程环境(environment) 帮助编程的软件,比如编辑器和性能分析器。
表达式(expression)
字段(field) 一种数据结构的组成部分。
FreeBSD 一种Unix的开源版本。
自由软件(freeware)
在一些语言中函数也是一种数据类型。
垃圾回收机制(garbage collection) 程序自动判断哪些内存不再需要,并予以回收,而不是要求程序员在使用完毕后明确声明
goto 将程序的运行顺序从一部分改向另一部分的命令。goto与子程序调用最大的不同在于它使用后没有办法再回到原处。所以如果用了goto,程序往往会乱成一团。现在已经很少使用这个命令了。
格林斯潘第十定律(Greenspun’s Tenth Rule) “任何C或Fortran程序复杂到一定程度之后,都会包含一个临时开发的、只有一半功能的、不完全符合规格的、到处都是bug的、运行速度很慢的Common Lisp实现。”
破解(hack) 一种破坏规则的解决方法,可能有益也可能有害。
黑客(hacker)
散列表(hash table) 一种类似数据库的数据结构,存储在里面的每一段数据都有一个对应的键,使用时只要按照键就可以取出对应的数据。
邮件头(header) 电子邮件最前面的那部分,包含了邮件本身的相关信息。普通用户只会看到发信人(From)、收信人(To)、日期(Date)、主题(Subject)、抄送(Cc)等信息,但是还包含其他信息(比如邮件的传送路径)。
启发(heuristic) 从经验法则中得到灵感。
缩进(indented)
解释器(interpreter)
内循环(inner loop) 一个程序中执行次数最频繁的部分。
记录仪(instrument) 修改程序使得它的每一步结果都得到记录,这样的话,如果程序运行速度缓慢或者占用太多内存,你就能找到原因。
蹩脚(kludge) 水平很差的破解。(这个词与stooge“丑角”是押韵的!)
雏形创业公司(larval startup) 创业公司最早期、还未成形的阶段。此时,潜在的创业者还不确定是否应该成立一家公司创业。
历史遗留软件(legacy software) 这些软件虽然还有人使用,但是并不符合使用者的要求。他们继续使用它们只是因为无钱购买新软件,或者不敢改变现状。
闭包(lexical closure) 一个函数,通过它可以引用由包含这个函数的代码所定义的变量。
LFSP(聪明人的语言,Language For Smart People) 设计目标主要是追求功能强大而不是保证安全性的编程语言。
函数库(library)
Linux Unix操作系统的一个开源版本。讲究一点的话,它应该被称为GNU Linux,因为它的内核部分是由Linus Torvalds编写的,但是其他更大量的代码来自Richard Stallman的GNU项目。
列表(list) 一连串的数据块,各个数据块的类型通常是不一样的。不同的列表可以像火车车厢一样连接在一起,组成更大的列表。
字面量(literal representation) 一种直接在高级语言中表示数据的方法。
机器指令(machine instruction)
机器语言(machine language)
宏(macro) 一个能够生成其他程序的程序。
大型机(mainframe) 根据20世纪六七十年代的设计而建造的大型计算机。
对数学家的妒忌(math envy) 担心自己不如数学家聪明。这种焦虑的一个重要体现就是让自己的工作成果带有一种完全不必要的数学味。
元循环(metacircular) 当一种语言的解释器用这种语言本身开发时,就会出现这种情况。与其说这是为了做出这种语言的一种实现,还不如说这是描述语言的一种技巧。
方法(method) 面向对象编程中充当某个类的属性的一个子程序。
模块(module) 一组子程序和变量,它们可以被视为是一个整体。通常情况下,模块外部的代码只能访问模块内部一部分专门对外公开的子程序和变量。
摩尔定律(Moore’s Law) 摩尔定律的正式版本是指,一块芯片上的晶体管数量每两年就会翻一番。但是,大多数人提到这个术语时,指的却是处理器的运算速度每18个月就会翻一番。很多人认为摩尔定律更像是商业计划,而不是产业发展的规律,毕竟它的提出者Gordon Moore是英特尔公司的创始人之一。
数字密集运算(number crunching) 对巨量的数值资料进行直接处理。
目标码(object code) 编译器产生的机器语言。
OO(面向对象,object-oriented) 一种组织程序的方式。假定不同的类代表不同类型的数据,那么针对这些数据执行某种特定任务的代码,可以根据数据的不同被分别写进不同的类,成为这些类的方法。
“奥卡姆剃刀”原则(Occam’ Razor) 简单的解释就是较好的解释。
开放源代码(open source)
正交的(orthogonal) 彼此独立、能够以多种方式组合在一起的一组东西。经典的乐高积木就比普通的塑料模型玩具更有正交性。
优化(optimization) 调整程序,使得它的效率更高。
帕金森定律(Parkinson’s Law) 完成一项任务所需要的资源会不断扩展,直至把这种资源消耗光为止。
解析器(parser) 读取输入的数据然后生成解析树的程序。
解析树(parser tree) 解析器读取源码后生成的数据结构。它是将源码翻译成机器语言的第一步。
补丁(patch)
PDA(个人数字助理,Personal Digital Assistant) 一种可以随身携带的小型计算机。它的操作界面通常比正规计算机更简单,限制也更多。
管道(pipe) 将操作系统的各种命令连接起来的一种方式,使得一个命令的输出变成另一个命令的输入。
指针(pointer) 一块数据,它的值是另一块数据的内存地址。
指针运算(pointer arithmetic) 通过对已知地址进行加法运算在内存中找到目标对象。这是低层次语言的一种技巧。
可移植性(portable)
门户(portal) 网站。
过早设计(premature design) 过早决定一个程序的行为。
过早优化(premature optimization) 还没有写完程序,你就开始考虑它的性能问题。
进程(process)
性能分析器(profiler) 一种观察运行中的目标程序的程序,它会告诉你目标程序的哪一个部分最消耗资源。
伪码(pseudocode)
QA(质量保证,Quality Assurance) 软件行业中负责找出和登记bug的人。
递归(recursive) 一种调用自身的算法。警察审讯犯人时就会用到递归。警察先问犯人是否知道案件的情况,或者是否知道谁干的,如果犯人回答知道,那么继续这样问下去。
RAID(冗余独立磁盘阵列,Redundant Array of Independent Disks) 一种硬件,将多个硬盘模拟成单硬盘,(理论上)避免了硬盘崩溃。
“读取—求值—打印”循环(read-eval-print loop) 一种顶层解释器(toplevel)。
RISC(精简指令集计算机,Reduced Instruction Set Computer) 这种计算机的机器语言功能有限,但是运行速度较快。它的目标是更好地适应编译器的需要
扫描(scan) 读取一串字符,将其分解成一个个的语义单位(token)。
脚本语言(scripting language) 一种编程语言,用来对某个程序进行定制。有时,开源编程语言(比如Perl和Python)也被称为脚本语言,但是这种叫法意义不大。
SETI@home(搜寻地外文明,Search for Extra-Terrestrial Intelligence) 一个科研项目,使用互联网上桌面电脑的空闲计算能力搜索宇宙中其他生命发出的电磁波。
s-表达式(s-expression) 一种语义单位(token),用括号表示,内部可以再包含0到多个s-表达式。
套接字(socket) Unix操作系统的一种内部渠道,不同计算机的进程通过它可以在网络上交换信息。
面条式代码(spaghetti) 扭曲缠绕在一起的代码,没有人能够读懂,包括作者本人。
spam 无缘无故收到的、数量庞大的垃圾邮件,通常是广告。这个词来自Monty Python剧团的喜剧小品,每当餐厅服务员打开一听Spam牌罐装肉,一群维京海盗打扮的演员就齐声高唱“Spam,Spam,Spam”,将主人公的对话声都淹没了,因此spam就有了外界强加的大量打扰的含义。
规格(spec) 软件的规格说明书。对程序功能的一种非正式描述。
SSH(安全shell,Secure Shell) 可以安全连接远程计算机的一种程序。
SSL(安全套接字层,Secure Sockets Layer) 一种在网络上安全传输数据的协议。
状态机(state machine) 一种理论上的机器,它的所有可能状态是一个集合。当满足某些条件时,状态之间就会发生转换。
语句(statement) 一串不产生值的代码。为了使得自己有用,它必须能够产生一些实际效果,比如显示内容。有人认为这个概念本身就是错的,在一些语言中根本没有语句,只有表达式。
静态类型语言(static typing) 这一类编程语言的所有变量的类型在开始编写程序的时候就必须知道。
子程序(subroutine)
子集(subset)
西装革履的人士(suits)
符号(symbol) 一种数据类型,语义单位(token)就是符号的实例。符号与字符串很类似,除了两点区别:(a)一个符号就是一个独立的单位,而不仅仅是一串字符;(b)一个符号通常只有一个对应的名称,而包含同样字符的字符串却可能有好几种。
句法(syntax)
系统管理员综合症(system administrator disease) 系统管理员心底里总是认为,他们管理的那些设备只是独立的设备,而不是用户的工具。更概括地说,他们的态度就是将客户视为一种麻烦,而不是自己能够有这个饭碗的原因。这种心理是感受不到竞争压力的工作职位所特有的。
一次性程序(throwaway program) 为了满足暂时性需求而编写的程序。
语义单位(token) 一串同属于一个单位的字符。更通用的叫法是“词”(word)。
顶层解释器(toplevel) 编程语言的一种界面,你可以在其中用这种语言与计算机进行不间断的对话,正如你在Unix的shell界面中所做的那样,而不是简单地编译程序,然后运行,对话就结束了。
树(tree) 一种数据结构,它包含的每一个实例都可以指向两个或更多的实例,比如家谱树。
图灵完备(Turing-complete) 如果一种编程语言写出的所有程序都能被转换成图灵机程序,并且反之也成立,那么这种编程语言就是图灵完备的。所有当代编程语言都是图灵完备的,这意味着(在理论上)它们的功能都是一样强大的。图灵完备又称图灵等价(Turing- equivalent)。
图灵机(Turing machine) 一种完全虚构的计算机,作用是证明计算理论。由于所有计算机的程序都可以被转换成图灵机程序,所以在这个意义上,你不可能做出比图灵机更强大的计算机。但是没有人能保证这一点,因为“计算机”这个词并没有被正式定义过。
UDP 一种网络传播信息的协议。
UI 用户界面(User Interface)。
向量(vector)
正常运行时间(uptime) 一台计算机(特别指一台服务器)正常工作的时间百分比。它的另一个意思是指某台计算机从上次宕机到现在的时间长度。
朦胧件(vaporware) 谈论已久但是迟迟不亮相的软件。
VC(风险投资商,Venture Capitalist) 为他人创业或再融资提供金钱的人,他们要求创业者用股份来交换投资。
1.0版(version 1.0) 某样东西的第一个版本,暗示不完整、不好用。
楔住(wedged) 表示无回应状态,尤其是指服务器。
所见即所得(wysiwyg) What you see is what you get(你看到的就是你得到的)的缩写(发音为whizzy wig)。比如文字处理器中,你在屏幕上看到的页面与打印机的输出是一样的。