Unix哲学起源于Ken Thompson早期关于如何设计一个服务接口简洁、小巧精干的操做系统的思考,随着Unix文化在学习如何尽量发掘Thompson设计思想的过程当中不断成长,同时一路上还从其它许多地方博采众长。前端
Unix哲学说来不算是一种正规设计方法。它并不打算从计算机科学的理论高度来产生理论上完美的软件。那些毫无动力、松松垮垮并且薪水微薄的程序员们,能在短短时间限内,如同神灵附体般造出稳定而新颖的软件——这只不过是经理人永远的梦呓罢了。linux
Unix哲学(同其它工程领域的民间传统同样)是自下而上的,而不是自上而下的。Unix哲学注重实效,立足于丰富的经验。你不会在正规方法学和标准中找到它,它更接近于隐性的半本能的知识,即Unix文化所传播的专业经验。它鼓励那种分清轻重缓急的感受,以及怀疑一切的态度,并鼓励你以幽默达观的态度对待这些。程序员
Unix管道的发明人、Unix传统的奠定人之一Doug McIlroy在[McIlroy78]中曾经说过:算法
(i)让每一个程序就作好一件事。若是有新任务,就从新开始,不要往原程序中加入新功能而搞得复杂。shell
(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]。排错占用了大部分的开发时间,弄出一个拿得出手的可用系统,一般与其说出自才华横溢的设计成果,还不如说是跌跌撞撞的结果。
汇编语言、编译语言、流程图、过程化编程、结构化编程、所谓的人工智能、第四代编程语言、面向对象、以及软件开发的方法论,不可胜数的解决之道被抛售者吹得神乎其神。但实际上这些都用处不大,缘由偏偏在于它们“成功”地将程序的复杂度提高到了人脑几乎不能处理的地步。就像Fred Brooks的一句名言[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程序员相互比的是谁可以作到“简洁而漂亮”并以此为荣,这一点虽然只是隐含在这些规则之中,但仍是很值得公开提出来强调一下。
—Doug McIlroy
更为常见的是(至少在商业软件领域里),过分的复杂性每每来自于项目的要求,而这些要求经常基于当月的推销热点,而不是基于顾客的需求和软件实际可以提供的功能。许多优秀的设计被市场推销所须要的大堆大堆“特性清单”扼杀——实际上,这些特×××几乎从未用过。而后,恶性循环开始了:比别人花哨的方法就是把本身变得更花哨。很快,庞大臃肿变成了业界标准,每一个人都在使用臃肿不堪、bug极多的软件,连软件开发人员也不敢敝帚自珍。
不管以上哪一种方式,最后每一个人都是失败者。
要避免这些陷阱,惟一的方法就是鼓励另外一种软件文化,以简洁为美,人人对庞大复杂的东西群起而攻之——这是一个很是看重简单解决方案的工程传统,老是设法将程序系统分解为几个可以协做的小部分,并本能地抵制任何用过多噱头来粉饰程序的企图。
这就有点Unix文化的意味了。
1.6.6 吝啬原则: 除非确无它法,不要编写庞大的程序
“大”有两重含义:体积大,复杂程度高。程序大了,维护起来就困难。因为人们对花费了大量精力才作出来的东西难以割舍,结果致使在庞大的程序中把投资浪费在注定要失败或者并不是最佳的方案上。
(咱们会在第13章就软件的最佳大小进行更多的详细讨论。)
1.6.7 透明性原则:设计要可见,以便审查和调试
由于调试一般会占用四分之三甚至更多的开发时间,因此一开始就多作点工做以减小往后调试的工做量会很划算。一个特别有效的减小调试工做量的方法就是设计时充分考虑透明性和显见性。
软件系统的透明性是指你一眼就可以看出软件是在作什么以及怎样作的。显见性指程序带有监视和显示内部状态的功能,这样程序不只可以运行良好,并且还能够看得出它以何种方式运行。
设计时若是充分考虑到这些要求会给整个项目全过程都带来好处。至少,调试选项的设置应该尽可能不要在过后,而应该在设计之初便考虑进去。这是考虑到程序不但应该可以展现其正确性,也应该可以把原开发者解决问题的思惟模型告诉后来者。
程序若是要展现其正确性,应该使用足够简单的输入输出格式,这样才能保证很容易地检验有效输入和正确输出之间的关系是否正确。
出于充分考虑透明性和显见性的目的,还应该提倡接口简洁,以方便其它程序对其进行操做——尤为是测试监视工具和调试脚本。
1.6.8 健壮原则: 健壮源于透明与简洁
软件的健壮性指软件不只能在正常状况下运行良好,并且在超出设计者设想的意外条件下也可以运行良好。
大多数软件禁不起磕碰,毛病不少,就是由于过于复杂,很难通盘考虑。若是不可以正确理解一个程序的逻辑,就不能确信其是否正确,也就不能在出错的时候修复它。
这也就带来了让程序健壮的方法,就是让程序的内部逻辑更易于理解。要作到这一点主要有两种方法:透明化和简洁化。
就健壮性而言,设计时要考虑到能承受极端大量的输入,这一点也很重要。这时牢记组合原则会颇有益处;经不起其它一些程序产生的输入(例如,原始的Unix C编译器听说须要一些小小的升级才能处理好Yacc的输出)。固然,这其中涉及的一些形式对人类来讲每每看起来没什么实际用处。好比,接受空的列表/字符串等等,即便在人们不多或者根本就不提供空字符串的地方也得如此,这能够避免在用机器生成输入时须要对这种状况进行特殊处理。
—Henry Spencer
在有异常输入的状况下,保证软件健壮性的一个至关重要的策略就是避免在代码中出现特例。bug一般隐藏在处理特例的代码以及处理不一样特殊状况的交互操做部分的代码中。
上面咱们曾说过,软件的透明性就是指一眼就可以看出来是怎么回事。若是“怎么回事”不算复杂,即人们不须要绞尽脑汁就可以推断出全部可能的状况,那么这个程序就是简洁的。程序越简洁,越透明,也就越健壮.
模块性(代码简朴,接口简洁)是组织程序以达到更简洁目的的一个方法。另外也有其它的方法能够获得简洁。接下来就是另外一个。
1.6.9 表示原则: 把知识叠入数据以求逻辑质朴而健壮
即便最简单的程序逻辑让人类来验证也很困难,可是就算是很复杂的数据,对人类来讲,仍是相对容易地就可以推导和建模的。不信能够试试比较一下,是五十个节点的指针树,仍是五十行代码的流程图更清楚明了;或者,比较一下究竟用一个数组初始化器来表示转换表,仍是用switch语句更清楚明了呢?能够看出,不一样的方式在透明性和清晰性方面具备很是显著的差异。参见Rob Pike的原则5。
数据要比编程逻辑更容易驾驭。因此接下来,若是要在复杂数据和复杂代码中选择一个,宁愿选择前者。更进一步:在设计中,你应该主动将代码的复杂度转移到数据之中去。
此种考量并不是Unix社区的原创,可是许多Unix代码都显示受其影响。特别是C语言对指针使用控制的功能,促进了在内核以上各个编码层面上对动态修改引用结构。在
结构中用很是简单的指针操做就可以完成的任务,在其它语言中,每每不得不用更复杂的过程才能完成。
(咱们将在第9章再讨论这些技术。)
1.6.10 通俗原则:接口设计避免标新立异
(也就是众所周知的“最少惊奇原则”。)
最易用的程序就是用户须要学习新东西最少的程序——或者,换句话说,最易用的程序就是最切合用户已有知识的程序。
所以,接口设计应该避免毫无来由的标新立异和自做聪明。若是你编制一个计算器程序,‘+’应该永远表示加法。而设计接口的时候,尽可能按照用户最可能熟悉的一样功能接口和类似应用程序来进行建模。
关注目标受众。他们也许是最终用户,也许是其余程序员,也许是系统管理员。对于这些不一样的人群,最少惊奇的意义也不一样。
关注传统惯例。Unix世界造成了一套系统的惯例,好比配置和运行控制文件的格式,命令行开关等等。这些惯例的存在有个极好的理由:缓和学习曲线。应该学会并使用这些惯例。
(咱们将在第5章和第10章讨论这些传统惯例。)
最小立异原则的另外一面是避免表象类似而实际却略有不一样。这会极端危险,由于表象类似每每致使人们产生错误的假定。因此最好让不一样事物有明显区别,而不要看起来几乎如出一辙。
—Henry Spencer
1.6.11 缄默原则:若是一个程序没什么好说的,就保持沉默
Unix中最古老最持久的设计原则之一就是:若程序没有什么特别之处可讲,就保持沉默。行为良好的程序应该默默工做,决不唠唠叨叨,碍手碍脚。沉默是金。
“沉默是金”这个原则的起始是源于Unix诞生时尚未视频显示器。在1969年的缓慢的打印终端,每一行多余的输出都会严重消耗用户的宝贵时间。如今,这种状况已不复存在,一切从简的这个优良传统流传至今。
我认为简洁是Unix程序的核心风格。一旦程序的输出成为另外一个程序的输入,就很容易把须要的数据挑出来。站在人的角度上来讲――重要信息不该该混杂在冗长的程序内部行为信息中。若是显示的信息都是重要的,那就不用找了。
—Ken Arnold
设计良好的程序将用户的注意力视为有限的宝贵资源,只有在必要时才要求使用。
(咱们将在第11章末尾进一步讨论缄默原则及其理由。)
1.6.12 补救原则: 出现异常时,立刻退出并给出足量错误信息
软件在发生错误的时候也应该与在正常操做的状况下同样,有透明的逻辑。最理想的状况固然是软件可以适应和应付非正常操做;而若是补救措施明明没有成功,却悄无声息地埋下崩溃的隐患,直到好久之后才显现出来,这就是最坏的一种状况。
所以,软件要尽量从容地应付各类错误输入和自身的运行错误。可是,若是作不到这一点,就让程序尽量以一种容易诊断错误的方式终止。
同时也请注意Postel的规定[8]:“宽容地收,谨慎地发”。Postel谈的是网络服务程序,可是其含义能够广为适用。就算输入的数据很不规范,一个设计良好的程序也会尽可能领会其中的意义,以尽可能与别的程序协做;而后,要么响亮地倒塌,要么为工做链下一环的程序输出一个严谨干净正确的数据。
然而,也请注意这条警告:
最初HTML文档推荐“宽容地接受数据”,结果由于每一种浏览器都只接受规范中一个不一样的超集,使咱们一直倍感无奈。要宽容的应该是规范而不是它们的解释工具。
—Doug McIlroy
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代码结合在一块儿,使其基本可以完成所须要的任务,而后告诉客户派几个职员来使用这些原型,问他们是否喜欢。若是喜欢,他就会说“在多少多少个月以后,花多少多少的钱就能够得到一个商业版本”。他的估计每每很精确,但因为当时的文化,他仍是输给了那些相信需求分析应该主导一切的同行。
—Mike Lesk
借助原型化找出哪些功能没必要实现,有助于对性能进行优化;那些不用写的代码显然无需优化。目前,最强大的优化工具恐怕就是delete键了。
我最有成效的一天就是扔掉了1000行代码。
—Ken Thompson
(咱们将在第12章对相关内容进行深一步讨论。)
1.6.16 多样原则:决不相信所谓“不二法门”的断言
即便最出色的软件也经常会受限于设计者的想象力。没有人能聪明到把全部东西都最优化,也不可能预想到软件全部可能的用途。设计一个僵化、封闭、不肯与外界沟通的软件,简直就是一种病态的傲慢。
所以, 对于软件设计和实现来讲,Unix传统有一点很好,即从不相信任何所谓的“不二法门”。Unix奉行的是普遍采用多种语言、开放的可扩展系统和用户定制机制。
1.6.17 扩展原则: 设计着眼将来,将来总比预想快
若是说相信别人所宣称的“不二法门”是不明智的话,那么坚信本身的设计是“不二法门”简直就是愚蠢了。决不要认为本身找到了最终答案。所以,要为数据格式和代
码留下扩展的空间,不然,就会发现本身经常被原先的不明智选择捆住了手脚,由于你没法既要改变它们又要维持对原来的兼容性。
设计协议或是文件格式时,应使其具备充分的自描述性以即可以扩展。一直,老是,要么包含进一个版本号,要么采用独立、自描述的语句,按照能够随时插入新的、换掉旧的而不会搞乱格式读取代码的方法组织格式。Unix经验告诉咱们:稍微增长一点让数据部署具备自描述性的开销,就能够在无需破坏总体的状况下进行扩展,你的付出也就获得了成千倍的回报。
设计代码时,要有很好的组织,让未来的开发者增长新功能时无需拆毁或重建整个架构。固然这个原则并非说你能随意增长根本用不上的功能,而是建议在编写代码时要考虑到未来的须要,使之后增长功能比较容易。程序接合部要灵活, 在代码中加入“若是你须要……”的注释。有义务给以后使用和维护本身编写的代码的人作点好事。
也许未来就是你本身来维护代码,而在最近项目的压力之下你极可能把这些代码都遗忘了一半。因此,设计为未来着眼,节省的有可能就是本身的精力。
全部的Unix哲学浓缩为一条铁律,那就是各地编程大师们奉为圭臬的“KISS”原则: