《Linux/Unix设计思想》读书笔记

这段时间把《Linux/Unix设计思想》看了一遍,感触颇多,虽然这本书写于2003年,到今天已过去十几个年头,但书中提到的设计思想却丝毫未显过时,反而在时光的打磨下闪耀出更为耀眼的光芒,成为了一波又一波信息浪潮的动力源泉。诚如作者所说:

哲学就是哲学,它不会过时。

小即是美

相对于同类庞然大物。小巧的事物有着无可比拟的优势。其中一点就是它们能够以独特的方式结合其他小事物,而且这种方式往往是最初的设计者没能预见到的。

书中以大众汽车在美国展开的一项主题为“小即是美”的营销活动为例,说明小事物往往更能取得意想不到地成功。和怪物级的复杂程序相比,小程序拥有前者无法比拟的优势:

  • 小程序易于理解
  • 小程序易于维护
  • 小程序消耗的系统资源更少
  • 小程序容易于其他工具相结合

有人可能会说,我也知道应该让程序保持小规模,但是随着业务的不断发展,逻辑变得越来越复杂,程序功能也越来越多,不知不觉中小程序变成了可怕的怪物,稍稍改动下逻辑,系统就可能出问题,而且似乎业务规模变大,变复杂之后,程序就没办法像之前那样保持小规模。

果真如此么?其实不然,小程序的第4点优势已为我们指出了方向,我们可以将怪物重新划分为独立又相互依存的小程序集合,比如“微服务”架构。

我们来看一个类似于Uber或者Hailo的出租车调度软件例子:

image

上图所示的架构虽然已经是模块化的,但依然是个又大有复杂的怪物,因为所有的模块最终会作为一个整体打包部署。一个模块如果出了问题,比如:内存泄露等,往往整个系统也随着崩溃。除此之外,一个模块的小变动往往导致系统级的回归测试,敏捷就无从谈起。对于此,本人有着深刻地教训,深以为然。

image

上图就是一个小程序集合,每个模块都是单独部署的,每个模块就是个小程序(或者小程序集合),一个模块的改动,只需回归测试该模块即可,易于理解,易于测试,易于部署。同时,模块间以RestAPI的方式相互协作,其能对外提供的功能和怪物程序一致。“微服务”架构很好地诠释了“小即是美”原则。(注意:微服务架构也是有局限性的,详细请看文末的参考资料1,软件领域,没有银弹)

另外,让每个程序只做好一件事情原则“小即是美”原则同等重要:

最好的程序应该像Cousteau所拍摄的湖泊飞虫一样,全部能量只用来执行单一任务,并且将她做好。程序被加载到内存中,行使完它的功能,然后退出,让下一个目标单一的程序开始运行。这听起来简单,可你会发现,太多软件开发人员无法坚持朝这个简单方向努力。

尽快建立原型

“尽快”就是越快越好,火速进行。你可以先花少量时间规划整个应用程序,然后便可以创建原型。开始编写代码吧,就好像你的生命完全取决于这个原型一样。记住要趁热打铁,我们根本没有时间来浪费!

注意,这里说的是花少量时间规划,而不是不规划,凡事预则立,不预则废。尽快建立原型的好处:原型的建立是个学习的过程、建立早起原型能够降低风险。

“人类创造的三个系统”理论

1、人类的“第一个系统“

  • 在背水一战的情况下,人类创建了“第一个系统”
  • 没有足够的时间将事情做好
  • 单枪匹马或是一小群人开发的
  • “精简、其貌不扬的计算机器”,却可以激发创造力

2、人类的“第二个系统“

  • 使用“第一个系统”验证过的想法来创建“第二个系统”
  • 由委员会设计的
  • 臃肿而缓慢
  • 被大张旗鼓地誉为伟大的成就

3、人类的“第三个系统“

  • 由为“第二个系统”所累的人们创建
  • 最初的概念保持不变并显而易见
  • 结合“第一个系统”和“第二个系统”的最佳特性
  • 有“充裕的时间”将任务做好

“三个系统”理论,很有趣,在我们的工程实践中,随处可以看到这三个系统的身影。第一个系统通常是刚刚发布上线的新系统,这类系统往往功能精简,但又恰好满足需求,虽然偶尔出些小错,但无伤大雅。因为逻辑精简,所以也易于修改和部署,目前,生活还算美好。

随着业务的发展,逻辑也变得无比的复杂,第一系统正逐渐朝着第二系统的方向演进。而更为糟糕的是,无数Boss本着关心业务的态度,不断挑战,不断进行所谓的迭代改进,第一系统终于不可避免地变成了第二系统,臃肿而缓慢,就像一只正试图在凳子上起舞的大象。每次一发布新版本,系统就问题不断,这时,几乎是以上坟的心态面对工作了。

终于,在某次重大故障发生之后,有人站了出来说,不能再这样下去了,我们优化逻辑,调整架构吧。在砍掉过于复杂却无太大作用的逻辑,优化架构之后,第二系统也得以朝着第三系统的方向继续演进。值得庆幸的是,持续恶化的情况终于得到了遏制,生活又重回美好。但此时,仍需保持警惕,防止重回第二系统。

“三个系统”的理论,告诉了我们一个道理:应当尽早建立第一系统,然后,尽量让系统保持在第二系统和第三系统之间。

可移植性优先

  1. 下一…的硬件将会跑得更快
  2. 不要花太多的时间去优化程序
  3. 最高效的方法通常不可移植
  4. 可移植的软件还减少了用户培训的需求
  5. 好程序永不消失,而会被移植到新平台

“舍高效而取可移植性”原则可以用来解释编程领域里的很多现象,比如:java
的崛起,perl的流行,nodejs的兴起,REPL的复仇等。这和我们的直觉恰恰相反:性能越优秀的软件的生命力不是应该越强么?(理由请参阅以上5点,不再详细论述)

关于第2点,我说明下,这里不是说放弃优化,而是说因为系统的性能往往是由20%的模块决定的,在决定优化程序时,我们应该找出性能瓶颈所在,解决好瓶颈即可。这就是经常说的四两拨千斤。

同时,这也告诉了我们两个道理:1、不要过于相信自己的直觉,事实往往恰恰相反。2、除了性能外,程序还有比性能优先级更高的事情需要考虑。

软件的杠杆效应

想编写大量软件,最好的办法就是借用别人的成果。这里所说的“借用别人的成果”是指将他人的软件模块、程序和配置文件集成到自己的应用程序中。通过制作衍生品,你成倍放大了前任开发人员的努力,将他们的成果发扬光大到新的高度。他们软件变得更有价值,因为它们的身影出现在更多应用程序中。

我们生活在一个最好的时代,同时,我们生活在一个最坏的时代。

说是最好的时代,是因为无论我们面对的是怎么的需求,所处怎样的领域,有太多太多的工具(大多数都是免费的)可供我们挑选,有些甚至理想到无须编写任何代码,只需简单配置即可。软件的杠杆效应使我们受益良多,真可以说是站到了巨人的肩膀上。个人认为GitHub是我们共有的程序持续进化的基因库,我们应该把更多地时间花在这上面,而不是浪费到复制粘贴上。

同时,也请警惕这个最坏的时代,如果我们仅仅满足于会使用工具,仅仅满足于复制+粘贴的话,那我们也就是个“人肉编码机”,编程技艺也无从提高。有太多现成的软件可以使用了,又何必再费力思考呢,一旦产生了类似的想法,是非常危险的,它会让我们满足于现状,止步不前,而终有一天你会发现自己和一台机器又有什么区别呢。

但请注意,这里绝不是提倡大家重复造轮子,这是不必要的,也是非常浪费时间。既然已经站到了巨人的肩膀上,我们就应该好好研究哪些取得巨大成功的开源软件,从它们身上学到更多,学得更快。

我们能不能深入浅出地给别人讲解其中的原理?我们能不能在其基础上进行改进,帮助它持续进化?我们能不能清晰地说出开源软件的典型应用场景在哪里,它的短板在哪里?比起重复造轮子,这些问题的答案才更值得我们关注。

  1. 良好的程序员编写优秀代码,优秀的程序员借用优秀代码
  2. 避免NIH综合征
  3. 允许他人使用你的代码来发挥软件杠杆效应
  4. 将一切自动化
  5. 使用shell脚本来提高杠杆效应和可移植性

非我所创或NIH综合症(英文:Not Invented Here Syndrome),指的是社会、公司和组织中的一种文化现象,人们不愿意使用、购买或者接受某种产品、研究成果或者知识,不是出于技术或者法律等因素,而只是因为它源自其他地方。
来着维基百科

写在最后

书中还阐述了Linux/Unix另外一些原则,比如:允许用户定制环境、寻求90%解决方案,更坏就是更好等,如有兴趣可以到原书中查找,这里不再摘录。

最后,书中所讨论的这些原则不能帮助我们解决某个具体技术问题,但是当我们需要对技术方案进行抉择的时候,这些原则可以很好地帮忙我们避开潜在的水坑,让我们离最佳方案更近一步。

所以,请记住,如果前进的方向都搞错了,不管我们多么努力,永不可能抵达终点,而Linux/Unix的这些原则恰恰就像指南针一样,为我们指明了方向。

参考资料:

Table of Contents