为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

Unix基本哲学

2012-03-04 18页 pdf 205KB 16阅读

用户头像

is_745890

暂无简介

举报
Unix基本哲学 Unix基本哲学 ----------------------------------------------------------------------------------------- --------------------------------------------------中国 IT实验室整理 2009-8-26 Unix哲学起源于Ken Thompson早期关于如何设计一个服务接口 简洁、小巧精干的操作系统的思考,随着 Unix 文化在学习如何尽可 能发掘 Thompson设计思想...
Unix基本哲学
Unix基本哲学 ----------------------------------------------------------------------------------------- --------------------------------------------------中国 IT实验室整理 2009-8-26 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 哲学是这样的:一个程序只做一件事,并做好。程序要能 协作。程序要能处理文本流,因为这是最通用的接口。 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作了强调:拿不准就穷举。 Unix 哲学中更多的内容不是这些先哲们口头表述出来的,而是 由他们所作的一切和 Unix 本身所作出的榜样体现出来的。从整体上 来说,可以概括为以下几点: 1. 模块原则:使用简洁的接口拼合简单的部件。 2. 清晰原则:清晰胜于机巧。 3. 组合原则:设计时考虑拼接组合。 4. 分离原则:策略同机制分离,接口同引擎分离。 5. 简洁原则:设计要简洁,复杂度能低则低。 6. 吝啬原则:除非确无它法,不要编写庞大的程序。 7. 透明性原则:设计要可见,以便审查和调试。 8. 健壮原则:健壮源于透明与简洁。 9. 表示原则:把知识叠入数据以求逻辑质朴而健壮。 10. 通俗原则:接口设计避免标新立异。 11. 缄默原则:如果一个程序没什么好说的,就沉默。 12. 补救原则:出现异常时,马上退出并给出足够错误信息。 13. 经济原则:宁花机器一分,不花程序员一秒。 14. 生成原则:避免手工 hack,尽量编写程序去生成程序。 15. 优化原则:雕琢前先要有原型,跑之前先学会走。 16. 多样原则:决不相信所谓“不二法门”的断言。 17. 扩展原则:设计着眼未来,未来总比预想来得快。 如果刚开始接触 Unix,这些原则值得好好体味一番。谈软件工 程的文章常常会推荐大部分的这些原则,但是大多数其它操作系统缺 乏恰当的工具和传统将这些准则付诸实践,所以,多数的程序员还不 能自始至终地贯彻这些原则。蹩脚的工具、糟糕的设计、过度的劳作 和臃肿的代码对他们已经是家常便饭了;他们奇怪,Unix 的玩家有 什么好烦的呢。 1.6.1 模块原则:使用简洁的接口拼合简单的部件 正如 Brian Kernighan曾经说过的:“计算机编程的本质就是控制 复杂度”[Kernighan-Plauger]。排错占用了大部分的开发时间,弄出 一个拿得出手的可用系统,通常与其说出自才华横溢的设计成果,还 不如说是跌跌撞撞的结果。 汇编语言、编译语言、图、过程化编程、结构化编程、所谓 的人工智能、第四代编程语言、面向对象、以及软件开发的方法论, 不计其数的解决之道被抛售者吹得神乎其神。但实际上这些都用处不 大,原因恰恰在于它们“成功”地将程序的复杂度提升到了人脑几乎 不能处理的地步。就像 FredBrooks的一句名言[Brooks]:没有万能药。 要编制复杂软件而又不至于一败涂地的唯一方法就是降低其整 体复杂度——用清晰的接口把若干简单的模块组合成一个复杂软件。 如此一来,多数问题只会局限于某个局部,那么就还有希望对局部进 行改进而不至牵动全身。 1.6.2 清晰原则: 清晰胜于机巧 维护如此重要而成本如此高昂;在写程序时,要想到你不是写给 执行代码的计算机看的,而是给人——将来阅读维护源码的人,包括 你自己——看的。 在 Unix传统中,这个建议不仅意味着代码注释。良好的 Unix实 践同样信奉在选择算法和实现时就应该考虑到将来的可扩展性。而为 了取得程序一丁点的性能提升就大幅度增加技术的复杂性和晦涩性, 这个买卖做不得——这不仅仅是因为复杂的代码容易滋生 bug,也因 为它会使日后的阅读和维护工作更加艰难。 相反,优雅而清晰的代码不仅不容易崩溃——而且更易于让后来 的修改者立刻理解。这点非常重要,尤其是说不定若干年后回过头来 修改这些代码的人可能恰恰就是你自己。 永远不要去吃力地解读一段晦涩的代码三次。第一次也许侥幸成 功,但如果发现必须重新解读一遍——离第一次太久了,具体细节无 从回想——那么你该注释代码了,这样第三次就相对不会那么痛苦 了。—Henry Spencer 1.6.3 组合原则:设计时考虑拼接组合 如果程序彼此之间不能有效通信,那么软件就难免会陷入复杂度 的泥淖。 在输入输出方面,Unix 传统极力提倡采用简单、文本化、面向 流、设备无关的格式。在经典的 Unix 下,多数程序都尽可能采用简 单过滤器的形式,即将一个输入的简单文本流处理为一个简单的文本 流输出。 抛开世俗眼光,Unix 程序员偏爱这种做法并不是因为他们仇视 图形用户界面,而是因为如果程序不采用简单的文本输入输出流,它 们就极难衔接。 Unix 中,文本流之于工具,就如同在面向对象环境中的消息之 于对象。文本流界面的简洁性加强了工具的封装性。而许多精致的进 程间通讯方法,比如远程过程调用,都存在牵扯过多各程序间内部状 态的倾向。 要想让程序具有组合性,就要使程序彼此独立。在文本流这一端 的程序应该尽可能不要考虑文本流另一端的程序。将一端的程序替换 为另一个截然不同的程序,而完全不惊扰另一端应该很容易做到。 GUI可以是个好东西。有时竭尽所能也不可避免复杂的二进制数 据格式。但是,在做一个 GUI 前,最好还是应该想想可不可以把复 杂的交互程序跟干粗活的算法程序分离开,每个部分单独成为一块, 然后用一个简单的命令流或者是应用将其组合在一起。 在构思精巧的数据传输格式前,有必要实地考察一下,是否能利 用简单的文本数据格式;以一点点格式解析的代价,换得可以使用通 用工具来构造或解读数据流的好处是值得的。 当程序无法自然地使用序列化、协议形式的接口时,正确的 Unix 设计至少是,把尽可能多的编程元素组织为一套定义良好的 API。这 样,至少你可以通过链接调用应用程序,或者可以根据不同任务的需 求粘合使用不同的接口。(我们将在第 7章详细讨论这些问题。) 1.6.4 分离原则: 策略同机制分离,接口同引擎分离 在 Unix之失的讨论中,我们谈到过 X系统的设计者在设计中的 基本抉择是实行“机制,而不是策略”这种做法——使 X 成为一个 通用图形引擎,而将用户界面风格留给工具包或者系统的其它层次来 决定。这一点得以证明是正确的,因为策略和机制是按照不同的时间 尺度变化的,策略的变化要远远快于机制。GUI工具包的观感时尚来 去匆匆,而光栅操作和组合却是永恒的。 所以,把策略同机制揉成一团有两个负面影响:一来会使策略变 得死板,难以适应用户需求的改变,二来也意味着任何策略的改变都 极有可能动摇机制。 相反,将两者剥离,就有可能在探索新策略的时候不足以打破机 制。另外,我们也可以更容易为机制写出较好的测试(因为策略太短 命,不值得花太多精力在这上面)。 这条设计准则在 GUI 环境之外也被广泛应用。总而言之,这条 准则告诉我们应该设法将接口和引擎剥离开来。 实现这种剥离的一个方法是,比如,将应用按照一个库来编写, 这个库包含许多由内嵌脚本语言驱动的 C 服务程序,而至于整个应 用的控制流程则用脚本来撰写而不是用 C 语言。这种模式的经典例 子就是 Emacs 编辑器,它使用内嵌的脚本语言 Lisp 解释器来控制用 C编写的编辑原语操作。我们会在第 11章讨论这种设计风格。 另一个方法是将应用程序分成可以协作的前端和后端进程,通过 套接字上层的专用应用协议进行通讯;我们会在第 5章和第 7章讨论 这种设计。前端实现策略,后端实现机制。比起仅用单个进程的整体 实现方式来说,这种双端设计方式大大降低了整体复杂度,bug有望 减少,从而降低程序的寿命周期成本。 1.6.5 简洁原则:设计要简洁,复杂度能低则低 来自多方面的压力常常会让程序变得复杂(由此代价更高,bug 更多),其中一种压力就是来自技术上的虚荣心理。程序员们都很聪 明,常常以能玩转复杂东西和耍弄抽象概念的能力为傲,这一点也无 可厚非。但正因如此,他们常常会与同行们比试,看看谁能够鼓捣出 最错综复杂的美妙事物。正如我们经常所见,他们的设计能力大大超 出他们的实现和排错能力,结果便是代价高昂的废品。 “错综复杂的美妙事物”听来自相矛盾。Unix 程序员相互比的 是谁能够做到“简洁而漂亮”并以此为荣,这一点虽然只是隐含在这 些规则之中,但还是很值得公开提出来强调一下。 更为常见的是(至少在商业软件领域里),过度的复杂性往往来自 于项目的要求,而这些要求常常基于当月的推销热点,而不是基于顾 客的需求和软件实际能够提供的功能。许多优秀的设计被市场推销所 需要的大堆大堆“特性清单”扼杀——实际上,这些特性功能几乎从 未用过。然后,恶性循环开始了:比别人花哨的方法就是把自己变得 更花哨。很快,庞大臃肿变成了业界标准,每个人都在使用臃肿不堪、 bug极多的软件,连软件开发人员也不敢敝帚自珍。 无论以上哪种方式,最后每个人都是失败者。 要避免这些陷阱,唯一的方法就是鼓励另一种软件文化,以简洁 为美,人人对庞大复杂的东西群起而攻之——这是一个非常看重简单 解决方案的工程传统,总是设法将程序系统分解为几个能够协作的小 部分,并本能地抵制任何用过多噱头来粉饰程序的企图。 这就有点 Unix文化的意味了。 1.6.6 吝啬原则: 除非确无它法,不要编写庞大的程序 “大”有两重含义:体积大,复杂程度高。程序大了,维护起来 就困难。由于人们对花费了大量精力才做出来的东西难以割舍,结果 导致在庞大的程序中把投资浪费在注定要失败或者并非最佳的方案 上。(我们会在第 13章就软件的最佳大小进行更多的详细讨论。) 1.6.7 透明性原则:设计要可见,以便审查和调试 因为调试通常会占用四分之三甚至更多的开发时间,所以一开始 就多做点工作以减少日后调试的工作量会很划算。一个特别有效的减 少调试工作量的方法就是设计时充分考虑透明性和显见性。 软件系统的透明性是指你一眼就能够看出软件是在做什么以及 怎样做的。显见性指程序带有监视和显示内部状态的功能,这样程序 不仅能够运行良好,而且还可以看得出它以何种方式运行。 设计时如果充分考虑到这些要求会给整个项目全过程都带来好 处。至少,调试选项的设置应该尽量不要在事后,而应该在设计之初 便考虑进去。这是考虑到程序不但应该能够展示其正确性,也应该能 够把原开发者解决问题的思维模型告诉后来者。 程序如果要展示其正确性,应该使用足够简单的输入输出格式, 这样才能保证很容易地检验有效输入和正确输出之间的关系是否正 确。 出于充分考虑透明性和显见性的目的,还应该提倡接口简洁,以 方便其它程序对其进行操作——尤其是测试监视工具和调试脚本。 1.6.8 健壮原则: 健壮源于透明与简洁 软件的健壮性指软件不仅能在正常情况下运行良好,而且在超出 设计者设想的意外条件下也能够运行良好。 大多数软件禁不起磕碰,毛病很多,就是因为过于复杂,很难通 盘考虑。如果不能够正确理解一个程序的逻辑,就不能确信其是否正 确,也就不能在出错的时候修复它。 这也就带来了让程序健壮的方法,就是让程序的内部逻辑更易于 理解。要做到这一点主要有两种方法:透明化和简洁化。 就健壮性而言,设计时要考虑到能承受极端大量的输入,这一点 也很重要。这时牢记组合原则会很有益处;经不起其它一些程序产生 的输入(例如,原始的 Unix C编译器据说需要一些小小的升级才能 处理好 Yacc的输出)。当然,这其中涉及的一些形式对人类来说往往 看起来没什么实际用处。比如,接受空的列表、字符串等等,即使在 人们很少或者根本就不提供空字符串的地方也得如此,这可以避免在 用机器生成输入时需要对这种情况进行特殊处理。 在有异常输入的情况下,保证软件健壮性的一个相当重要的策略 就是避免在代码中出现特例。bug通常隐藏在处理特例的代码以及处 理不同特殊情况的交互操作部分的代码中。 上面我们曾说过,软件的透明性就是指一眼就能够看出来是怎么 回事。如果“怎么回事”不算复杂,即人们不需要绞尽脑汁就能够推 断出所有可能的情况,那么这个程序就是简洁的。程序越简洁,越透 明,也就越健壮.模块性(代码简朴,接口简洁)是组织程序以达到 更简洁目的的一个方法。另外也有其它的方法可以得到简洁。接下来 就是另一个。 1.6.9 表示原则: 把知识叠入数据以求逻辑质朴而健壮 即使最简单的程序逻辑让人类来验证也很困难,但是就算是很复 杂的数据,对人类来说,还是相对容易地就能够推导和建模的。不信 可以试试比较一下,是五十个节点的指针树,还是五十行代码的流程 图更清楚明了;或者,比较一下究竟用一个数组初始化器来表示转换 表,还是用 switch语句更清楚明了呢?可以看出,不同的方式在透明 性和清晰性方面具有非常显著的差别。参见 Rob Pike的原则 5。 数据要比编程逻辑更容易驾驭。所以接下来,如果要在复杂数据 和复杂代码中选择一个,宁愿选择前者。更进一步:在设计中,你应 该主动将代码的复杂度转移到数据之中去。 此种考量并非 Unix社区的原创,但是许多 Unix代码都显示受其 影响。特别是 C 语言对指针使用控制的功能,促进了在内核以上各 个编码层面上对动态修改引用结构。在结构中用非常简单的指针操作 就能够完成的任务,在其它语言中,往往不得不用更复杂的过程才能 完成。(我们将在第 9章再讨论这些技术。) 1.6.10 通俗原则:接口设计避免标新立异 (也就是众所周知的“最少惊奇原则”。) 最易用的程序就是用户需要学习新东西最少的程序——或者,换 句话说,最易用的程序就是最切合用户已有知识的程序。 因此,接口设计应该避免毫无来由的标新立异和自作聪明。如果 你编制一个计算器程序,‘+’应该永远表示加法。而设计接口的时 候,尽量按照用户最可能熟悉的同样功能接口和相似应用程序来进行 建模。 关注目标受众。他们也许是最终用户,也许是其他程序员,也许 是系统管理员。对于这些不同的人群,最少惊奇的意义也不同。 关注传统惯例。Unix 世界形成了一套系统的惯例,比如配置和 运行控制文件的格式,命令行开关等等。这些惯例的存在有个极好的 理由:缓和学习曲线。应该学会并使用这些惯例。(我们将在第 5 章 和第 10章讨论这些传统惯例。) 最小立异原则的另一面是避免表象相似而实际却略有不同。这会 极端危险,因为表象相似往往导致人们产生错误的假定。所以最好让 不同事物有明显区别,而不要看起来几乎一模一样。 1.6.11 缄默原则:如果一个程序没什么好说的,就保持沉默 Unix 中最古老最持久的设计原则之一就是:若程序没有什么特 别之处可讲,就保持沉默。行为良好的程序应该默默工作,决不唠唠 叨叨,碍手碍脚。沉默是金。 “沉默是金”这个原则的起始是源于 Unix 诞生时还没有视频显 示器。在 1969 年的缓慢的打印终端,每一行多余的输出都会严重消 耗用户的宝贵时间。现在,这种情况已不复存在,一切从简的这个优 良传统流传至今。 我认为简洁是 Unix 程序的核心风格。一旦程序的输出成为另一 个程序的输入,就很容易把需要的数据挑出来。站在人的角度上来 说――重要信息不应该混杂在冗长的程序内部行为信息中。如果显示 的信息都是重要的,那就不用找了。 设计良好的程序将用户的注意力视为有限的宝贵资源,只有在必 要时才要求使用。(我们将在第 11章末尾进一步讨论缄默原则及其理 由。) 1.6.12 补救原则: 出现异常时,马上退出并给出足量错误信息 软件在发生错误的时候也应该与在正常操作的情况下一样,有透 明的逻辑。最理想的情况当然是软件能够适应和应付非正常操作;而 如果补救措施明明没有成功,却悄无声息地埋下崩溃的隐患,直到很 久以后才显现出来,这就是最坏的一种情况。 因此,软件要尽可能从容地应付各种错误输入和自身的运行错 误。但是,如果做不到这一点,就让程序尽可能以一种容易诊断错误 的方式终止。 同时也请注意 Postel 的规定[8]:“宽容地收,谨慎地发”。Postel 谈的是网络服务程序,但是其含义可以广为适用。就算输入的数据很 不规范,一个设计良好的程序也会尽量领会其中的意义,以尽量与别 的程序协作;然后,要么响亮地倒塌,要么为工作链下一环的程序输 出一个严谨干净正确的数据。 然而,也请注意这条警告:最初 HTML 文档推荐“宽容地接受 数据”,结果因为每一种浏览器都只接受规范中一个不同的超集,使 我们一直倍感无奈。要宽容的应该是规范而不是它们的解释工具。 McIlroy 要求我们在设计时要考虑宽容性,而不是用过分纵容的 实现来补救标准的不足。否则,正如他所指出的一样,一不留神你会 死得很难看。 1.6.13 经济原则: 宁花机器一分,不花程序员一秒 在 Unix 早期的小型机时代,这一条观点还是相当激进的(那时 机器要比现在慢得多也贵得多)。如今,随着技术的发展,开发公司 和大多数用户(那些需要对核爆炸进行建模或处理三维电影动画的除 外)都能够得到廉价的机器,所以这一准则的合理性就显然不用多说 啦! 但不知何故,实践似乎还没完全跟上现实的步伐。如果我们在整 个软件开发中很严格的遵循这条原则的话,大多数的应用场合都应该 使用高一级的语言,如 Perl、Tcl、Python、Java、Lisp,甚至 shell— —这些语言可以将程序员从自行管理内存的负担中解放出来(参见 [Ravenbrook])。 这种做法在 Unix世界中已经开始施行,尽管 Unix之外的大多数 软件商仍坚持采用旧 Unix学派的 C(或 C++)编码方法。本书会在后面 详细讨论这个策略及其利弊权衡。 另一个可以显著节约程序员时间的方法是:教会机器如何做更多 低层次的编程工作,这就引出了…… 1.6.14 生成原则: 避免手工 hack,尽量编写程序去生成程序 众所周知,人类很不善于干辛苦的细节工作。因此,程序中的任 何手工 hacking都是滋生错误和延误的温床。程序规格越简单越抽象, 设计者就越容易做对。由程序生成代码几乎(在各个层次)总是比手写 代码廉价并且更值得信赖。 我们都知道确实如此(毕竟这就是为什么会有编译器、解释器的 原因),但我们却常常不去考虑其潜在的含义。对于代码生成器来说, 需要手写的重复而麻木的高级语言代码,与机器码一样是可以批量生 产的。当代码生成器能够提升抽象度时——即当生成器的说明性语句 要比生成码简单时,使用代码生成器会很合算,而生成代码后就根本 无需再费力地去手工处理了。 在 Unix 传统中,人们大量使用代码生成器使易于出错的细节工 作自动化。Parser/Lexer 生成器就是其中的经典例子,而 makefile 生 成器和 GUI界面式的构建器(interface builder)则是新一代的例子。 (我们会在第 9章讨论这些技术。) 1.6.15 优化原则: 雕琢前先得有原型,跑之前先学会走 原型设计最基本的原则最初来自于 Kernighan 和 Plauger 所说 的“90%的功能现在能实现,比 100%的功能永远实现不了强”。做好 原型设计可以帮助你避免为蝇头小利而投入过多的时间。 由于略微不同的一些原因,Donald Knuth(程序设计领域中屈指 可数的经典著作之一《计算机程序设计艺术》的作者)广为传播普及 了这样的观点:“过早优化是万恶之源”[9]。他是对的。 还不知道瓶颈所在就匆忙进行优化,这可能是唯一一个比乱加功 能更损害设计的错误。从畸形的代码到杂乱无章的数据布局,牺牲透 明性和简洁性而片面追求速度、内存或者磁盘使用的后果随处可见。 滋生无数 bug,耗费以百万计的人时——这点芝麻大的好处,远不能 抵消后续排错所付出的代价。 经常令人不安的是,过早的局部优化实际上会妨碍全局优化(从 而降低整体性能)。在整体设计中可以带来更多效益的修改常常会受 到一个过早局部优化的干扰,结果,出来的产品既性能低劣又代码过 于复杂。 在 Unix 世界里,有一个非常明确的悠久传统(例证之一是 Rob Pike以上的评论, 另一个是 Ken Thompson关于穷举法的格言):先 制作原型,再精雕细琢。优化之前先确保能用。或者:先能走,再学 跑。“极限编程”宗师 Kent Beck 从另一种不同的文化将这一点有效 地扩展为:先求运行,再求正确,最后求快。 所有这些话的实质其实是一个意思:先给你的设计做个未优化 的、运行缓慢、很耗内存但是正确的实现,然后进行系统地调整,寻 找那些可以通过牺牲最小的局部简洁性而获得较大性能提升的地方。 制作原型对于系统设计和优化同样重要——比起阅读一个冗长 的规格说明,判断一个原型究竟是不是符合设想要容易得多。我记得 Bellcore有一位开发经理,他在人们还没有谈论“快速原型化”和“敏 捷开发”前好几年就反对所谓的“需求”文化。他从不提交冗长的规 格说明,而是把一些 shell脚本和 awk代码结合在一起,使其基本能 够完成所需要的任务,然后告诉客户派几个职员来使用这些原型,问 他们是否喜欢。如果喜欢,他就会说“在多少多少个月之后,花多少 多少的钱就可以获得一个商业版本”。他的估计往往很精确,但由于 当时的文化,他还是输给了那些相信需求分析应该主导一切的同行。 借助原型化找出哪些功能不必实现,有助于对性能进行优化;那 些不用写的代码显然无需优化。目前,最强大的优化工具恐怕就是 delete键了。 我最有成效的一天就是扔掉了 1000行代码。—Ken Thompson (我们将在第 12章对相关内容进行深一步讨论。) 1.6.16 多样原则:决不相信所谓“不二法门”的断言 即使最出色的软件也常常会受限于设计者的想象力。没有人能聪 明到把所有东西都最优化,也不可能预想到软件所有可能的用途。设 计一个僵化、封闭、不愿与外界沟通的软件,简直就是一种病态的傲 慢。 因此, 对于软件设计和实现来说,Unix传统有一点很好,即从不 相信任何所谓的“不二法门”。Unix奉行的是广泛采用多种语言、开 放的可扩展系统和用户定制机制。 1.6.17 扩展原则: 设计着眼未来,未来总比预想快 如果说相信别人所宣称的“不二法门”是不明智的话,那么坚信 自己的设计是“不二法门”简直就是愚蠢了。决不要认为自己找到了 最终答案。因此,要为数据格式和代码留下扩展的空间,否则,就会 发现自己常常被原先的不明智选择捆住了手脚,因为你无法既要改变 它们又要维持对原来的兼容性。 设计协议或是文件格式时,应使其具有充分的自描述性以便可以 扩展。一直,总是,要么包含进一个版本号,要么采用独立、自描述 的语句,按照可以随时插入新的、换掉旧的而不会搞乱格式读取代码 的方法组织格式。Unix 经验告诉我们:稍微增加一点让数据部署具 有自描述性的开销,就可以在无需破坏整体的情况下进行扩展,你的 付出也就得到了成千倍的回报。 设计代码时,要有很好的组织,让将来的开发者增加新功能时无 需拆毁或重建整个架构。当然这个原则并不是说你能随意增加根本用 不上的功能,而是建议在编写代码时要考虑到将来的需要,使以后增 加功能比较容易。程序接合部要灵活 ,在代码中加入“如果你需 要……”的注释。有义务给之后使用和维护自己编写的代码的人做点 好事。 也许将来就是你自己来维护代码,而在最近项目的压力之下你很 可能把这些代码都遗忘了一半。所以,设计为将来着眼,节省的有可 能就是自己的精力。
/
本文档为【Unix基本哲学】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索