语句摘录:
Preface
知识和专能差异巨大,凭借知识可以推断该做什么,而专能可以让你在无意见,条件反射似的把事情做好。
少一些技术,多一些共享文化:显见和显微的,直观和潜流的,不止与方法,更重乎理念。
场景:哲学和历史;设计:哲学原理细分为有关设计和实现;工具:Unix提供的工具;社群:人与人之间的事物和约定。
须弥不重,芥子不轻;Unix程序员的教养。
构成文化是人,获知文化的方式可以是口口相传,潜移默化,也可以是书籍。
AdvancedProgramming in the Unix Environment[Stevens92]是探究UnixAPI的经典名著。ThePractice of Programming[Kernighan-Pike99]是每个C程序员必读的书籍。
从代码中汲取养分,将有助于将所学的原理消化为庖丁之技。
TheUnix Philosophy[Mike Gancarz],最简单的Unix设计手法就是持久耐用。
ThePragmatic Programmer[Hunt-Thomas]。《ZenFlesh,ZenBones》[Reps-Senzaki]-佛教禅宗本源的合集,禅为表达某种想法提供了丰富的词汇。
一些约定:
Unix手册页(manualpage),Unix程序簇(emacs).
Oldschool:昂贵的共用计算机,专属的Unix,shell脚本和无处不在的C
Newschool:脚本语言,用户界面,开放源代码的unix和万维网
PartI
Philosophy:PhilosophyMatters
文化,什么是文化?
工程和设计的每个分支都有自己的技术文化。在大多数工程领域中,一个专业人员的素养组成来说,不成文的行业素养具有与标准手册及教科书同等重要的地位(并且随着专业人员经验的日积月累,这些经验常常比书本更重要).资深工程师在工作中会积累大量的隐性的知识,通过类似禅宗“教外别传(不立文字,直至人心,见性成佛)”的方式,言传身教传授给后辈。
Unix演进成一种强势的技术文化,有鲜明特色的艺术和世代相传的设计哲学。
Unix的生命力
Unix被应用在各种机型上,从超级计算机到手持设备。Unix现已演化为:Linux,BSD,Solaris,MacOSX以及其他的各种Unix的变种。
Unix的核心技术:C语言—系统级软件工程,带目录节点的属性文件名字空间和吃呢工序间通信的管道机制。
性能-时间指数曲线对软件开发过程所引发的结果,就是每过18个月,就有一半的知识会过时。而Unix技术中很多的东西都是积年不变的:语言,系统调用,工具用法。
Unix的稳定和成功很大程度上归功于它与身据来的内在的优势,归功于早期的Unix看者作出的设计决策。这些设计决策和设计哲学,编程艺术,技术文化一起,被反复证明是健康可靠的。
Unix之失
Unix文件在字节层次上无结构可言,文件删除了就没法恢复了。安全模型过于原始,作业控制有欠精致,命令方式非常混乱。
Unix哲学中的最有争议部分是机制和策略分离的特性。这特性是由Xwindow设计者明确提出的,提供一套“机制,而不是策略”。Unix的其他系统级的服务也有类似的倾向:行为逻辑被最可能的推后到使用端。Unix可以在多种shell中进行选择,Unix应用程序提供了很多的行为选择和令人眼花缭乱的定制的功能。
上述行为体现了Unix的设计理念:最终用户比操作系统设计人员更清楚他们需要什么。
策略和机制分离的代价是:用户可以设置策略,其实上他们必须设置策略。只看眼前的话,Unix这种自由放纵主义风格会让它失去很多非技术型用户。长久的来看,策略是相对短寿,而机制才会长存。只提供机制不提供方法能使Unix长久保鲜。
Unix之得
开源软件:自由共享的源码和同僚严格复审的开发方式。
跨平台可移植性和开发标准:POSIX(读音更像Unix),只有称之为UnixAPI的等价物才算是比较可信的模型。
Internet和万维网:TCP/IP协议栈的开发合同交给Unix研发组,Unix成为互联网提供商(InternetService Provider)行业不可或缺的核心技术之一。Unix世界中可以看到稳定可靠的成果。
开源社区:Unix社区是各种软件的强大支持组,高质量的开源开发工具在Unix世界中极为丰富。借助这些工具,可以减少90%的工作量。通过协作开发与代码复用路上艰辛的探索,才耕耘出代码共享的传统。通过大量的工程实践,才有这些并非显而易见的设计原则。开源运行给Unix注入新的血液和新的技术方法,带来了新一代的有才华的程序员。Linux系统+Apache+Mozilla.
Unix的灵活性:Unix提供了众多程序粘和手段,将基本的工具箱的各种组件联合开合,将收到单个工具无法想象的功效。Unix将重点放在使各个程序接口相对小巧,简洁和正交—提高灵活性。
UnixHack的乐趣:趣味性很重要。乐趣是一个符号,意味着效能,效率和高产。
好的设计原则和开发方法在Unix上实施相对容易,Unix是一个学习这些原则和方法的平台,ANSIC程序库表述了相当打部分的Unix服务。
Unix哲学基础
Unix哲学注重实效,立足与丰富的经验,不会在正规的方法学和标准中找到它,它更接近于隐性的半本能的知识。它鼓励那种分清轻重缓急的感觉,以及怀疑一切的态度,并且鼓励你以幽默达观的态度对待这些。
Unix哲学的DougMcIlroy总结:一个程序只做一件事情,并做好。程序要能协作。程序要能处理文本流,因为这是最通用的接口。
Unix哲学的RobPike总结:
-
无法断定程序会在什么地方耗费运行时间。瓶颈经常发生在意想不到的地方。
-
估量(Little定律)
-
花哨的算法在n很小的时候通常很慢,而且n通常很小。
-
花哨的算法比简单的算法更容易出bug,更难实现。拿不准就穷举
-
数据压倒一切。
Unix哲学的概述:
1.模块原则:使用简洁的接口拼合简单的部件
计算机编程的本质是控制复杂度。各种各样的软件方法将程序的复杂度提升了而不是简化了。
编写复杂的软件而不至于失败的唯一的方法就是降低复杂度--使用清晰的接口把若干个简单的模块组合成一个复杂软件。
2.清晰原则:清晰胜于技巧
代码注释,在选择算法和实现时考虑到将来的可扩展性。为了一点性能的提升而大幅提升技术的复杂性和晦涩性是不值得的。
3.组合原则:设计时考虑并接组合
在输入输出方面,Unix传统极力提倡采用简单,文本化,面向流,设备无关的格式。经典Unix下,多数程序尽可能采用简单过滤器(sed,awk)的形式,将简单文本输入流处理为一个简单的文本流的输出。
Unix中,文本流之于工具,如同面向对象中消息之于对象。文本流界面的简洁性加强了工具的封装性。程序要具有组合性,就要使得程序之间彼此的独立。
GUI可以是一个好东西,但是要避免使用复杂的二进制数据格式。在GUI中,考虑将复杂的交互程序和算法程序分离开,每个部分单独成为一块,使用简单的命令或者应用协议将其组合起来。文本流的数据可以使用通用的工具来处理。
4.分离原则:策略同机制分离,接口同引擎分离
X系统的设计,X成为了通用的图形引擎。分离变化的模式。机制和策略不是按相同的时间尺度变化的。
接口和引擎的剥离:比如将应用按照一个库开编写,库中包含使用脚本语言驱动的C服务程序,应用的控制流程使用脚本编写而不是使用c编写。典型的例子是Emacs编辑器。
另一种实践是,将应用程序分成可以协作的前端和后端进程,通过套接字使用上层的专用的应用协议进行通讯。
5.简洁原则:设计要简洁,复杂度能低就低
简洁为美,设法将复杂的系统分解为几个能够写作的小部分
6.吝啬原则:除非确无它法,不要编写庞大的程序
大的程序:体积大,复杂度高
7.透明性原则:设计要可见,以便审查和调试
调试通常会占用四分之三的甚至是更多的开发时间。透明性和显见性可以减少调试的工具量。
软件透明性:一眼就可以看出软件是做什么的。显见性就是程序带有监视和显示内部状态的功能。早点考虑测试或者调试事项,会给项目全过程带来好处。
程序如果要展示其正确性,应该使用足够简单的输入输出格式,这样可以方便的检验有效的输入和正确的输出之间的关系是否正确。
透明性和显见性的目的,提倡接口的简洁性。
8.健壮性原则:健壮性来源于透明和简洁
如果不能正确的理解一个程序的逻辑,谈何确定其是正确的!程序的健壮性要考虑极端大量的输入。程序越简洁,越透明,也就越健壮。
模块性(代码简朴,接口简洁)是组织程序以达到更简洁的目的的一个方法。
9.表示原则:把知识叠入数据以求逻辑质朴而健壮
数据要比编程逻辑更容易驾驭。在复杂的数据和复杂的代码中选择,宁可选择前者。更近一步,在设计中,应当主动将代码的复杂度转移到数据中去。
10.通俗原则:接口设计避免标新立异(最小惊奇原则)
最易用的程序就是用户需要学习新的东西最少的程序,或者最易用的程序是最切合用户已有的知识的程序。
关注目标受众。关注传统惯例,Unix世界形成了一套系统的惯例,比如匹配和运行控制文件的格式,命令行开关等等。
11.缄默原则:如果一个程序没有什么好说的,就沉默
沉默是金原则源自于Unix诞生的时候还没有视频显示器。简洁是Unix程序的核心风格。
设计良好的程序将用户的注意力视为有限的宝贵的资源,只有必要的时候才要求使用
12.补救原则:出现异常时,就马上退出并给出足够错误消息
异常处理逻辑,要尽可能的从容的应付各种错误输入和自身的运行错误。即使做不到,也要仅可能的以一种容易诊断的错误的方式终止。“宽容的收,谨慎的发的原则”
13.经济原则:宁花机器一分,不花程序员一秒
14.生成原则:避免手工hack,尽量编写程序去生成程序
人类很不擅长干辛苦的细节工作。程序中任何的手工的hacking都是滋生错误和延误的温床。程序规格越简单,设计者就越容易做对。程序生成代码总是比手写代码廉价并且更值得信赖。
编译器和解释器做的就是批量生成机器码的代码生成器。需要手写的重复而麻木的高级程序语言代码可以考虑使用代码生成器,并且代码生成器可以提高抽象度。备注:这里可以参考Paul关于Lisp的论断。
15.优化原则:优化前先要有原型,跑之前先学会走
做好原型设计可以让我们总是将时间用在刀刃上。
不知道瓶颈就匆匆进行优化,是唯一一个比乱添加功能更加损害设计的错误。过早的优化是万恶之源。考虑局部优化和全局优化的权衡。
先做原型,再精雕细琢。优化之前确保能用(KenThompson)
先运行,在求正确,最后求快(kentBack)。
使用shell脚本和awk代码构建原型。
16.多样原则:决不相信所谓的“不二法门”的断言
承认没有人能聪明的把所有的东西都最优化,也不可能预想到软件所有的用途.Beopen
Unix:采用多种语言,开发的可扩展系统,用户定制机制。
17.扩展原则:设计着眼未来,未来总是比预想来得快
绝不要认为自己找到了最终答案,要为数据格式和代码留下扩展空间。设计协议或是文件格式时,使其具有充分的自描述性以便可以扩展。要不包含进一个版本号,要不采用独立,自描述的语句。Unix经验:稍微增加一点让数据部署具有自描述性的开销,就可以在无需破坏整体的情况下进行扩展。
设计代码的时候,要有很好组织,让将来的开发者增加新的功能时,无需拆毁整个或者重建整个架构。
Unix哲学一言以蔽之:KISS(KeepIt Simple,Stupid!),这个有点像诗三百首,一言以蔽之,思无邪。
Unix哲学的应用
-
只要可行,一切都应该做成来源和目标无关的过滤器(filter)。
-
数据流应该尽可能的文本化(这样可以使用标准的工具来查看和过滤)
-
数据库部署和应用协议应尽可能文本化(让人阅读和编辑)
-
复杂的前端(用户界面)和后端应该泾渭分明
-
如果可能,在用C编写前,先用解释性语言搭建原型
-
当仅仅只用一门语言编程会提高程序复杂度时,混用语言编程才比单一的语言编程来的更好
-
宽收严发(对接受的东西要包容,对输出的东西要严格)
-
过滤时,重要的信息绝对不丢失
-
小就是美,在确保完成任务的基础上,程序功能尽可能的少--大道致简
态度要紧
看到该做的就去做,这是捷径。如果不能确定是什么是对的,只做最少量的工作,确保任务完成就行了。
要良好的运行Unix哲学,必须要不断的追求卓越。软件设计是一门技艺,值得付出所有的智慧(wisdom),创造力(creation)和激情(passion)。
良好的运用Unix哲学,就应该珍惜你的时间决不浪费。不重复造轮子,不蛮干,好钢用在刀刃上。善用工具,尽可能将一切读自动化。
软件设计和实现应该是一门充满快乐的艺术,一种高水平的游戏。
History:ATale of Two Cultures
前事不忘,后事之师。Unix历史悠久,且丰富多彩。
Unix的起源及其历史,1969—1995
CTSS-->Multics-->Unix
创世纪,1969—1971
Unix诞生在KenThompson的头脑中,JohnMcCarthy(lisp)提出分时系统,实验阶段,性能不稳定。
早期分时系统的标准的交互设备是ASR-33点传打字机-->命令简洁,少说多做的来源。
PDP-7,文件系统,星际旅行。Multics交互式计算,良好的编程环境,伙伴关系的系统,Remote-access和分时系统的公共计算。Unix是第一个可以让程序员坐在机器旁,飞快的捕获灵感,并能一边编写一边测试的系统