一次只做一件事,并做到极致。

UNIX 简介

unix全面的性能分析(UNIX设计哲学Do)(1)

UNIX系统是一个分时系统。最早的UNIX系统于1970年问世。此前,只有面向批处理作业的操作系统,这样的系统对于需要立即得到响应的用户来说是太慢了。在60年代末,Kenneth Thompson和Dennis Ritchie都曾参加过交互方式分时系统Multics的设计,而开发该系统所使用的工具是CTSS。这两个系统在操作系统的发展过程中都产生过重大影响。在此基础上,在对当时现有的技术进行精选提炼和发展的过程中,K.Thompson于1969年在小型计算机上开发UNIX系统,后于1970年投入运行。

1973年,Dennis Ritchie 开发出C语言,用来改写原来用汇编语言编写的 UNIX,由此产生了UNIX Version V。1974年,Kenneth Thompson 和 Dennis Ritchie 合写的“The UNIX Time-Sharing System"在Communication of ACM上发表,正式向外界披露了Unix系统。

UNIX 设计哲学:Do one thing and do it well

很多人谈"Unix哲学",也就是开发Unix系统的指导思想。

Unix哲学起源于Ken Thompson早期关于如何设计一个服务接口简洁、小巧精干的操作系统的思考,随着Unix文化在学习如何尽可能发掘Thompson设计思想的过程中不断成长,同时一路上还从其它许多地方博采众长。

Unix哲学说来不算是一种正规设计方法。它并不打算从计算机科学的理论高度来产生理论上完美的软件。那些毫无动力、松松垮垮而且薪水微薄的程序员们,能在短短期限内,如同神灵附体般造出稳定而新颖的软件——这只不过是经理人永远的梦呓罢了。

Unix哲学(同其它工程领域的民间传统一样)是自下而上的,而不是自上而下的。Unix哲学注重实效,立足于丰富的经验。你不会在正规方法学和标准中找到它,它更接近于隐性的半本能的知识,即Unix文化所传播的专业经验。它鼓励那种分清轻重缓急的感觉,以及怀疑一切的态度,并鼓励你以幽默达观的态度对待这些。

Unix管道的发明人、Unix传统的奠基人之一Doug McIlroy在[McIlroy78]中曾经说过:

(i)让每个程序就做好一件事。如果有新任务,就重新开始,不要往原程序中加入新功能而搞得复杂。

(ii)假定每个程序的输出都会成为另一个程序的输入,哪怕那个程序还是未知的。输出中不要有无关的信息干扰。避免使用严格的分栏格式和二进制格式输入。不要坚持使用交互式输入。

(ⅲ)尽可能早地将设计和编译的软件投入试用, 哪怕是操作系统也不例外,理想情况下, 应该是在几星期内。对拙劣的代码别犹豫,扔掉重写。

(iv)优先使用工具而不是拙劣的帮助来减轻编程任务的负担。工欲善其事,必先利其器。

后来他这样总结道(引自《Unix的四分之一世纪》(A Quarter Century of Unix [Salus])):

Unix哲学是这样的:一个程序只做一件事,并做好。程序要能协作。程序要能处理文本流,因为这是最通用的接口。

unix全面的性能分析(UNIX设计哲学Do)(2)

Rob Pike, 最伟大的C语言大师之一, 在《Notes on C Programming》中从另一个稍微不同的角度表述了Unix的哲学[Pike]:

原则1:你无法断定程序会在什么地方耗费运行时间。瓶颈经常出现在想不到的地方,所以别急于胡乱找个地方改代码,除非你已经证实那儿就是瓶颈所在。

原则2:估量。在你没对代码进行估量,特别是没找到最耗时的那部分之前,别去优化速度。

原则3:花哨的算法在n很小时通常很慢,而n通常很小。花哨算法的常数复杂度很大。除非你确定n总是很大,否则不要用花哨算法(即使n很大,也优先考虑原则2)。

原则4:花哨的算法比简单算法更容易出bug、更难实现。尽量使用简单的算法配合简单的数据结构。

原则5:数据压倒一切。如果已经选择了正确的数据结构并且把一切都组织得井井有条,正确的算法也就不言自明。编程的核心是数据结构,而不是算法。

原则6:没有原则6。

Ken Thompson——Unix最初版本的设计者和实现者,禅宗偈语般地对 Pike 的原则4作了强调:拿不准就穷举。

Pike的第一、二条规则重申了高德纳的著名格言:“过早的优化是一切罪恶的根源。”

Pike的第三、四条规则被肯·汤普逊概述成:“疑惑不定之时最适合穷举。”事实上,这两条规则也是KISS原则的具体表现。

规则五在之前Fred Brooks的人月神话中也被提及。Jon Bentley的《Programming Pearls》中也有一章阐述了相同的设计哲学。此规则作为“如果你的数据结构很好,那么控制它的算法就无关痛痒了”的例子常常被简化成“简约地写代码,聪明地用数据”。

第六条规则当然只是Pike针对蒙提·派森之小品Bruces sketch的幽默发挥而已了。

1994年,X Window系统开发组的成员 Mike Gancarz根据他自己的Unix系统经验以及和其他领域使用Unix系统的资深程序员们的讨论结果,写成了《The UNIX Philosophy》,提出了9条训格之言:

  • 一:小即是美。
  • 二:让程序只做好一件事。
  • 三:尽可能早地建立原型。
  • 四:可移植性比效率更重要。
  • 五:数据应该保存为文本文件。
  • 六:尽可能地榨取软件的全部价值。
  • 七:使用shell脚本来提高效率和可移植性。
  • 八:避免使用可定制性低下的用户界面。
  • 九:所有程序都是数据的过滤器。

(极致简单即是美、抽象到本质就是美、极简之美)

此外还有十条原则则并不为所有人认同,甚至还是争论的焦点(如宏内核和微内核之争):

  • 一:应该允许用户定制操作环境。
  • 二:让操作系统核心小而轻。
  • 三:使用小写字母并尽量简短。
  • 四:节约纸张,保护树林。
  • 五:沉默是金。
  • 六:并行地思考。
  • 七:部分加部分大于整体。
  • 八:寻找问题的帕雷托法则。
  • 九:程序随需求而增长(Worse is better)。
  • 十:层级地思考。

Unix哲学中更多的内容不是这些先哲们口头表述出来的,而是由他们所作的一切和Unix本身所作出的榜样体现出来的。Eric S. Raymond则在 The Art of Unix Programming 一书中,一口气总结了17条。

1. 模块原则:使用简洁的接口拼合简单的部件。

2. 清晰原则:清晰胜于机巧。

3. 组合原则:设计时考虑拼接组合。

4. 分离原则:策略同机制分离,接口同引擎分离。

5. 简洁原则:设计要简洁,复杂度能低则低。

6. 吝啬原则:除非确无它法,不要编写庞大的程序。

7. 透明性原则:设计要可见,以便审查和调试。

8. 健壮原则:健壮源于透明与简洁。

9. 表示原则:把知识叠入数据以求逻辑质朴而健壮。

10. 通俗原则:接口设计避免标新立异。

11. 缄默原则:如果一个程序没什么好说的,就沉默。

12. 补救原则:出现异常时,马上退出并给出足够错误信息。

13. 经济原则:宁花机器一分,不花程序员一秒。

14. 生成原则:避免手工hack,尽量编写程序去生成程序。

15. 优化原则:雕琢前先要有原型,跑之前先学会走。

16. 多样原则:决不相信所谓“不二法门”的断言。

17. 扩展原则:设计着眼未来,未来总比预想来得快。

如果刚开始接触Unix,这些原则值得好好体味一番。谈软件工程的文章常常会推荐大部分的这些原则,但是大多数其它操作系统缺乏恰当的工具和传统将这些准则付诸实践,所以,多数的程序员还不能自始至终地贯彻这些原则。蹩脚的工具、糟糕的设计、过度的劳作和臃肿的代码对他们已经是家常便饭了;他们奇怪,Unix的玩家有什么好烦的呢。

所有人都同意,"简单原则"----尽量用简单的方法解决问题----是"Unix哲学"的根本原则。这也就是著名的KISS(keep it simple, stupid),意思是"保持简单和笨拙"。

The ‘Unix philosophy’ originated with Ken Thompson’s early meditations on how to design a small but capable operating system with a clean service interface. The Unix philosophy (like successful folk traditions in other engineering disciplines) is bottom-up, not top-down. It is pragmatic and grounded in experience. Doug McIlroy, the inventor of Unix pipes and one of the founders of the Unix tradition, had this to say at the time [McIlroy78]:

Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new features.

Expect the output of every program to become the input to another, as yet unknown, program. Don’t clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don’t insist on interactive input.

Design and build software, even operating systems, to be tried early, ideally within weeks. Don’t hesitate to throw away the clumsy parts and rebuild them.

Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you’ve finished using them.

He later summarized it this way (quoted in A Quarter Century of Unix [Salus]):

This is the Unix philosophy: Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.

Rob Pike, who became one of the great masters of C, offers a slightly different angle in Notes on C Programming [Pike]:

  • 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.
  • Rule 2. Measure. Don’t tune for speed until you’ve measured, and even then don’t unless one part of the code overwhelms the rest.
  • Rule 3. Fancy algorithms are slow when n is small, and n is usually small. Fancy algorithms have big constants. Until you know that n is frequently going to be big, don’t get fancy. (Even if n does get big, use Rule 2 first.)
  • Rule 4. Fancy algorithms are buggier than simple ones, and they’re much harder to implement. Use simple algorithms as well as simple data structures.
  • Rule 5. 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.
  • Rule 6. There is no Rule 6.

Ken Thompson, the man who designed and implemented the first Unix, reinforced Pike’s rule 4 with a gnomic maxim worthy of a Zen patriarch:

When in doubt, use brute force.

More of the Unix philosophy was implied not by what these elders said but by what they did and the example Unix itself set. Looking at the whole, we can abstract the following ideas:

  • 1.Rule of Modularity: Write simple parts connected by clean interfaces.
  • 2.Rule of Clarity: Clarity is better than cleverness.
  • 3.Rule of Composition: Design programs to be connected to other programs.
  • 4.Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
  • 5.Rule of Simplicity: Design for simplicity; add complexity only where you must.
  • 6.Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
  • 7.Rule of transparency: Design for visibility to make inspection and debugging easier.
  • 8.Rule of Robustness: Robustness is the child of transparency and simplicity.
  • 9.Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.
  • 10.Rule of Least Surprise: In interface design, always do the least surprising thing.
  • 11.Rule of Silence: When a program has nothing surprising to say, it should say nothing.
  • 12.Rule of Repair: When you must fail, fail noisily and as soon as possible.
  • 13.Rule of Economy: Programmer time is expensive; conserve it in preference to machine time
  • 14.Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
  • 15.Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
  • 16.Rule of Diversity: Distrust all claims for “one true way”.
  • 17.Rule of Extensibility: Design for the future, because it will be here sooner than you think.

If you’re new to Unix, these principles are worth some meditation. Software-engineering texts recommend most of them; but most other operating systems lack the right tools and traditions to turn them into practice, so most programmers can’t apply them with any consistency. They come to accept blunt tools, bad designs, overwork, and bloated code as normal — and then wonder what Unix fans are so annoyed about.

The unix philosophy was originally published by ericsson.xiao at ericsson.xiao's blog on December 19, 2013.

unix全面的性能分析(UNIX设计哲学Do)(3)

,