1. 计算机领域里,没有什么问题是加一层间接寻址解决不了的。
There's nothing in computing that can't be broken by another level of indirection.
这是 Rob Pike 的修改版。
经常 level of insriection
误引用为 abstraction layer
。
原始版本出自 Butler Lampson
All problems in computer science can be solved by another level of indirection但是 David Wheeler 完成了下半句:
All problems in computer science can be solved by another level of indirection, except for the problem of too many layers of indirection.还有 Kevlin Henney 的下半句:
ll problems in computer science can be solved by another level of indirection, except for the problem of too many layers of indirection."
这句话幽默地指出,在计算机编程中,通过引入额外的抽象层或中间层,几乎可以解决任何复杂的问题。这种思路在软件设计和架构中很常见。
2. 数据为王。如果你选择了正确的数据结构,并且组织得当,算法几乎总是不言自明的。编程的核心在于数据结构,而不是算法。
Data dominates. If you've chosen the right data structures and organized things well, the algorithms will almost always be self-evident. Data structures, not algorithms, are central to programming.
"数据为王"意味着在软件开发中,数据的组织和表示方式比实现算法的具体细节更加重要。
这个观点强调了良好的数据结构设计对于编程效率和代码质量的重要性。它鼓励程序员把更多精力放在思考如何组织和表示数据上,而不是过分关注算法的技巧性。
3. 面向对象设计就是计算机界的罗马数字。
Object-oriented design is the roman numerals of computing.
这是一句颇具争议性和挑衅性的话。罗马数字在数学史上曾经很重要,但现代计算中已被阿拉伯数字体系取代,因为后者更简单、更高效。这句话暗示面向对象设计(OOD)也是如此。
Pike认为,就像罗马数字对现代数学来说过于繁琐和低效一样,面向对象编程(OOP)的某些方面(如过度的类层次结构和封装)可能导致代码复杂、难以理解和维护。
这个比喻引发了编程圈内的热议。支持者认为它点出了OOP的一些问题,如过度设计和不必要的复杂性。反对者则认为OOP仍然是一个强大和有用的范式。
值得注意的是,Pike是Go语言的创始人之一,Go语言采用了一种不同于传统OOP的设计哲学,更注重简单性和数据结构。
4. 最后,我意识到光想是没什么出路的,该动手实践了。
Eventually, I decided that thinking was not getting me very far and it was time to try building.
这句话体现了一种在技术和创新领域常见的实用主义态度。
"光想没出路"是一种常见的中文表达,意思是仅靠思考而不付诸行动是难以取得进展的。
"动手实践"强调了在实践中学习和创新的重要性。在编程、创业等领域,这种"边做边学"的方法被广泛推崇。
但这并不是完全否定思考的价值。恰当的思考和规划仍然重要,只是强调不要陷入"分析瘫痪"(analysis paralysis),即过度分析导致迟迟不能行动的状态。
5. 见识短浅,想象力就会受限。
Narrowness of experience leads to narrowness of imagination.
更为甚者, 见识短浅, 反而将大师的作品视为平庸。一个讽刺性的文章: The Evolution of a Go Programmer
6. 这就是现代计算:简单的东西变得过于复杂,因为随意捣鼓太容易;复杂的东西依旧复杂,因为修复太难。
Such is modern computing: everything simple is made too complicated because it's easy to fiddle with; everything complicated stays complicated because it's hard to fix.
Rob Pike 作为一位推崇简洁设计的大师,他对当前计算机行业的复杂性提出了犀利的批评。
第一部分讽刺了一些程序员或设计师的倾向:明明有简单的解决方案,却偏爱使用复杂的技术,导致本来简单的问题变得难以理解和维护。
第二部分点出了一个现实问题:一旦系统变得复杂,就很难简化。原因可能包括兼容性问题、团队惯性、或者是简单地因为理解和重构复杂系统需要大量时间和资源。
它呼应了UNIX哲学中的一个核心原则:做好一件事。也就是说,程序应该简单、模块化,只专注于完成一个任务。
7. 过程名应该反映它做什么;函数名应该反映它返回什么。
Procedure names should reflect what they do; function names should reflect what they return
这是编程领域的一条重要命名规范,有助于提高代码的可读性和可维护性。
在中文编程圈,"过程"(procedure)和"函数"(function)的区别经常被讨论。简单来说:
- "过程"执行一系列操作,通常不返回值,重点在于"做"。
- "函数"计算并返回一个值,重点在于"得到"什么。
8. 花哨的算法在 N 小的时候很慢,而 N 通常都很小。
Fancy algorithms are slow when N is small, and N is usually small.
"N" 在算法分析中代表输入规模,如要排序的元素个数、要搜索的数据量等。"大 O 表示法"(如 O(n)、O(n²))就是用 N 来描述算法在最坏情况下的时间复杂度。
这句话的启示:
- 不要过早优化。在数据量小的情况下,简单直白的算法可能更快、更易理解。
- 理解实际问题的规模。过度设计(用复杂算法解决小问题)可能适得其反。
= 在选择算法时,要考虑具体场景,不能只看理论复杂度。
俗语"大炮打蚊子",就是类似的道理。有时候,简单的方法反而更有效。
9. UNIX不仅已经死了,臭的都快熏死人了。
Not only is UNIX dead, it's starting to smell really bad.
在1990年代,微软的Windows和IBM的OS/2等图形用户界面(GUI)操作系统开始流行,而基于命令行的UNIX看起来过时了。一些人认为,用户友好的GUI是未来,UNIX这样的系统已经落伍,注定会消亡。
讽刺的是,这个预言并没有完全实现:
- Linux(一个UNIX类操作系统)在服务器领域占据主导地位。
- macOS基于BSD(另一个UNIX变种)。
- 甚至Windows 10也加入了Linux子系统。
这句话现在常被用来嘲笑那些过早宣布某项技术"死亡"的人。
10. 想要杜绝傻瓜行为的编程语言,往往自己也变得傻不拉几。
Languages that try to disallow idiocy become themselves idiotic.
过度限制程序员可能弊大于利:
- 好的程序员应该被信任和赋能,而不是被当成"傻瓜"对待。
- 有时,所谓的"傻瓜行为"其实是创新和效率的源泉。
- 语言应该提供工具和指导,而不是强制规定唯一的"正确"方式。
这句话也反映了一个更广的设计哲学:过度设计来防止错误,可能带来更多问题。无论是编程语言、产品设计还是管理,给予用户或团队合理的自由和信任,往往比试图规避一切风险更有效。
11、缓存不是架构,只是个优化手段而已。
Caches aren't architecture, they're just optimization.
Pike的观点是:
- 不要因为缓存效果好,就把它当成架构的一部分。
- 如果没有缓存系统就崩溃,那可能是架构有问题。
- 缓存应该是"锦上添花",而不是"救命稻草"。
但这并不意味着缓存不重要。实际上:
- 合理使用缓存可以极大提升性能。
- 在某些场景(如高并发网站),缓存几乎是必需的。
关键是平衡:
- 先有好的架构和算法。
- 在合适的地方加缓存,但不要让系统对缓存产生依赖。
- 缓存失效或穿透时,系统应该能够"优雅降级"。
用中文的一句话概括就是:"先治本,再治标"。缓存是"标"(优化性能),好的架构才是"本"。
12、没有类型层次,就不用费劲去管理类型层次了。
When there is no type hierarchy you don't have to manage the type hierarchy.
它直指面向对象编程(OOP)中一个常见的复杂性来源。"类型层次"主要指面向对象语言中的类继承结构:
"没有类型层次"并非完全否定OOP,而是指一种不同的设计风格:
- 组合优于继承:用组合(has-a)而不是继承(is-a)来复用代码。
- 接口而非基类:定义行为协议,而不是强制继承关系。
- 简单类型:类的职责单一,减少复杂的层次结构。
这种思想在Go语言中很明显:
- Go没有类和继承,但有结构体和接口。
- 结构体可以嵌入其他结构体来复用字段和方法,但不是继承。
- 接口是隐式的:只要一个类型实现了接口的所有方法,它就"是"那个接口。
13、按工程管理的规则,生产力最重要;可在工程师眼里,乐趣才是第一位。生产力源于乐趣。
Productivity is most important by engineering management rules, but enjoyment is most important for engineers. One stems from the other.
- 这里的"乐趣"不只是表面的快乐,更指:
- 解决有趣问题的满足感。
- 创造优雅代码的成就感。
- 与团队协作的归属感。
- 学习新技术的好奇心。
- 优秀的工程师往往被这些内在动机驱动,而不仅仅是外部压力。
Pike指出,高生产力实际上源于工程师的乐趣。
当工程师享受工作时,他们会:
- 自发加班,因为问题太有趣了。
- 主动优化代码,因为看到丑陋的代码会不舒服。
- 积极学习,因为新技术太酷了。
这些行为自然而然地提高了生产力。
这一观点在软件行业有广泛共识:
- Google的20%时间:员工可以花20%工作时间做自己感兴趣的项目。许多重要产品(如Gmail)就是这样诞生的。虽然说现在Google已经去掉了20%工作时间的政策。
- 开源社区:大多数贡献者是因为热情而不是报酬。这种模式创造了Linux、Python等。
- 创业文化:舒适的办公环境、弹性工作制,都是为了让员工更快乐,从而更有创造力。
对管理者的启示:
- 不要只盯着KPI。创造让工程师愉悦的环境,生产力自然会提高。
- 理解并尊重工程师的动机。有时,让他们"玩"反而能得到更好的结果。
对工程师的启示:
- 追求技术乐趣并不自私。它能让你更高效,也让产品更优秀。
- 但也要有度。纯粹追求个人兴趣而忽视团队目标,同样问题。
14、第一法则:你猜不准程序会在哪里耗时。性能瓶颈总在意想不到的地方冒出来,所以别想当然去优化,除非你证实了那里就是瓶颈所在。
Rule 1. You can't tell where a program is going to spend its time. Bottlenecks occur in surprising places, so don't try to second guess and put in a speed hack until you've proven that's where the bottleneck is
"猜不准程序会在哪里耗时":
- 程序性能不是直观的。即使是经验丰富的程序员,也常常错误预测哪部分代码最慢。
- 现代系统复杂(多线程、缓存、编译器优化等),让性能特征更难预测。
"性能瓶颈总在意想不到的地方冒出来":
- "性能瓶颈"是限制整体性能的最慢部分。就像木桶,最短的那块板决定了水位。
- "意想不到"暗示即使是看似简单的代码,也可能因为被频繁调用或数据量大而成为瓶颈。
"别想当然去优化":
- "想当然"在中文里就是不经证实就认定。这在性能优化中很危险。
过早优化(premature optimization)是编程界臭名昭著的反模式。它可能导致:
- 代码复杂化,难以理解和维护。
- 浪费时间在实际上不慢的部分。
- 引入新的bug或性能问题。
"除非你证实了那里就是瓶颈所在":
- "证实"是关键。不是猜测,而是通过性能分析工具(profiler)确定。
- 现代profiler可以精确定位耗时函数、内存分配等,让优化有的放矢。
这一法则的实践:
- 先让它跑起来(Make it work)
- 然后让它对(Make it right)
- 最后才是让它快(Make it fast)
- 每一步都用数据(profile)来指导,不猜测。
14、扩展
第14条事实上来源自Robe Pike的编程五原则, 包括上面的多条名言:
- 第一法则: 你猜不准程序会在哪儿磨蹭。性能瓶颈总冒出在意想不到的地方,所以别瞎猜着去优化,除非你摸清楚了瓶颈的准确位置。
- 第二法则: 先量化。没测量之前别瞎调速度,就算测出来了,也得是哪块代码严重拖后腿了才优化。
- 第三法则: 花里胡哨的算法在数据小时龟速,而且数据往往就不大。花哨算法有大常数。除非你明摆着要处理大数据,别整那些花活。(就算真遇到大数据,也先用第二法则。)
- 第四法则: 花哨的算法比简单的更容易藏bug,而且实现起来费劲得很。算法要简单,数据结构也要简单。
- 第五法则: 数据为王。如果你选对了数据结构,组织得当,算法几乎都是呼之即来。编程的核心是数据结构,不是算法。
- Pike的第一、二法则重申了Tony Hoare的名言:"过早优化是万恶之源"。 在中文里,"万恶之源"是个很重的词,用在这儿既有警示,也带点调侃。
- Ken Thompson把Pike 的第三、四法则总结为:"疑难杂症,暴力破解"。 "暴力破解"在中文程序员圈很常见,指不优雅但直接有效的解法。
- 第三、四法则体现了KISS(Keep It Simple, Stupid)设计哲学。中文常说"简单就是美",或者IT圈的"能用短裤的地方,别穿西装"。
- 第五法则早先出现在Fred Brooks的《人月神话》中。程序员们常把它简化为"写傻瓜代码,用聪明对象"。 这句话在中文圈也很流行,强调代码逻辑要直白,复杂性应该封装在良好设计的数据结构里。
15、如果POSIX线程算好东西,我都不敢想它比什么还好。
If POSIX threads are a good thing, perhaps I don't want to know what they're better than.
这是一句典型的程序员式嘲讽,直指他认为设计糟糕的一个技术标准。相当于说"它已经够糟了,居然还有比它更糟的?"
Pike为什么这么说?
- 复杂性:pthreads API被认为过于复杂和底层,容易出错。
- 死锁风险:错误使用pthreads很容易导致死锁、竞态条件等并发问题。
- 可移植性问题:尽管POSIX旨在提高可移植性,但不同系统的pthreads实现仍有差异。
16、缓存的bug,哪个不是妖魔鬼怪。
There's no such thing as a simple cache bug.
"缓存"在计算机中无处不在:CPU缓存(L1, L2, L3)、内存缓存(如Redis)、浏览器缓存、数据库查询缓存、CDN(内容分发网络)、DNS缓存等等。
Pike之所以这么说,是因为缓存bug的特点:
- 诡异性:缓存问题常常表现得不一致、间歇性,像"鬼打墙"。
- 隐蔽性:问题可能潜伏很久才暴露,像"潜伏的妖怪"。
- 牵连性:一个小小的缓存问题可能导致系统范围的故障,像"妖风四起"。
- 难调试:因为缓存常常是分布式的,跟踪问题如同"捉鬼"。
- 死灰复燃:以为修好了,问题却在高负载时死灰复燃,像"怪物再生"。
17、用 Unix 就跟只听大卫·卡西迪的歌似的,纯属乐坛井底之蛙。
Using Unix is the computing equivalent of listening only to music by David Cassidy.
Rob Pike在一次采访中说了这句话rob pike responds。
Rob Pike可是Unix的大佬级人物,和Ken Thompson、Dennis Ritchie一起在贝尔实验室创造了Unix。他怎么可能真的觉得Unix就像肤浅的流行乐?
现在的macOS(Mach内核)、Linux,甚至Windows(WSL)都有Unix的影子。
Pike仿佛预言般地讽刺:"看看,大家最后都来听'大卫·卡西迪'了。"
Rob Pike这句话是典型的技术人的自嘲式炫耀。表面上自贬,实际上是在用幽默的方式表达:"对,我们就是主流,因为我们简单好用。学院派笑话我们Low,但最后还不是得用我们的东西?"这种自黑中带着骄傲的调调。
18、"智能"终端可不是"自作聪明"的终端,而是你能调教的好帮手。
A smart terminal is not a smartass terminal, but rather a terminal you can educate.
Rob Pike这句话用带点烟火气的方式,点出了技术设计的一个关键:真正的"智能"不是自作聪明,而是在交互中学习和成长。就像中国老话说的,"学而不舍,才能化茧成蝶"。无论是终端还是人,都是这个道理。
19、Socket 是 IO 接口的 X Window。
Sockets are the X windows of IO interfaces.
表面上是在夸 Socket,就像当年吹捧 X Window 一样,实际上是 Pike 式的反话,意思是:"Socket 复杂、难用,就跟 X Window 一样令人头疼。"
为什么 Pike 这么黑 Socket?
- 复杂性:Socket API 有很多参数、选项和状态,容易用错。
- 底层性:直接操作网络协议,程序员要处理字节流、缓冲区等底层细节。
- 错误处理难:网络环境复杂,Socket 编程中的错误情况多,很难全面处理。
- 跨平台坑多:不同操作系统的 Socket 实现有微妙差异,写出跨平台代码很烦。
20、搞个理论上不那么刺激的编程语言干嘛?因为好用啊,能用才是王道。
Why would you have a language that is not theoretically exciting? Because it's very useful.
这话当然还是出自Rob Pike。作为Unix和Go语言之父,他一贯秉持"实用主义者"的态度。
学院派追求"道"(理论和原则)。Pike强调"术"(实用技巧和方法)。
21、并发不是并行
Concurrency is not parallelism
22、 Go语言 箴言
Go Proverbs