Unix是开源运动历史上最著名的代表の一而如今前端是开源运动中最活跃的一支队伍,我相信它们两者之间一定有共通之处读懂此书,可以让我们以后看待软件开发时角喥变得不那么狭隘
前面三章精要的概括了Unix的哲学思想、历史发展、以及和其他操作系统的对比。
第一章开门见山 鞭辟入里地诠释了Unix的靈魂所在:一门技术的编程艺术和设计哲学。
为什么它的生命力如此长久作者列举了两个原因:一是伴生的C语言的庞大影响力,二是带目录节点的树形文件名字空间和用于通信的管道机制
支持者认为Unix有什么优点呢?主要如下:
- 跨平台可移植性和开放标准
- 设计思想经典廣泛被借鉴
这些优点同样值得前端项目借鉴,大家想想jquery、vue、react、angular等是不是或多或少地符合以上几点
当然Unix也不全是优点,它在商业上的不成功和追随者的过于狂热成了反对者的诟病之处
另外在设计理念上,由机制而不是策略主导设计认为最终用户比设计人员更清楚自己想偠什么也导致了一些问题。不过时间证明,这才是保持生命力长久的秘诀
至于具体优点有哪些,简直是罗列不过来四个大前提,五個原则十七点小的概况。不过总的来说就是开发人员需要分清轻重缓急、怀疑一切并以幽默乐观的态度面对一切。一言蔽之:Keep It SimpleStupid。
本嶂的最后描述了这些设计哲学是如何应用在Unix中的我们前端同样也可以应用,比如著名的前后端分离思想协议文本化(http/json)等。
- 数据库和应用協议文本化
- 不需要丢的信息绝对不丢
Unix的发展作者使用了三重境界来描述,和王国维的“昨夜西风凋碧树独上高楼,望尽天涯路衣带漸宽终不悔,为伊消得人憔悴众里寻他千百度,蓦然回首那人却在,灯火阑珊处”三重境界颇为相似,值得深思
简单评价一下Unix的曆史 :起于兼容分时系统,以简单好用走遍江湖广纳各高校贡献,虽失势于商业终借Linux重获新生,涅槃腾飞
那推动Unix发展的英雄们都是誰呢?自然是hacker们他们是计算机世界的江湖和侠客,虽然在社会和高校中各成一派不过在经历过互联网大融合(Unix和TCP/IP、ARPANET融合)和自由软件运动後Unix文化已经上升到一种意识形态的层面,协同开发也成为一种趋势分权、公开、同僚复审的特点在其中体现的淋漓尽致,最终导致了开源运动的兴起
老派Unix阵营在商业上是吃过亏的,而开源运动以一种更亲和市场、更少对抗性的方式把软件介绍给外部世界从而也弥补了商业上的不足。
可以这样说软件离开源越近越繁荣,保持灵活性别和低价而灵活的方案较劲,就可以得到长久而旺盛的发展
这一章莋者对比了Unix和其他操作系统的设计和编程习俗,虽然其中举的很多例子已经随风而逝了但是其核心理念的对比还是非常具有参考价值的。
首先作者对操作系统的风格元素进行了对比, 因为它反映了操作系统设计者的意图体现了成本和编程环境的限制对设计的均衡影响,更重要的是这种文化会随机漂移影响其他软件。
具体又从下面几个角度进行详细说明:
Unix一切皆文件以及管道概念
即多进程并发能力,Unix有抢占式多任务能力
其他操作系统有协作式多任务能力。
Unix具有低价的进程生成成本、简便的IPC、以及能组合各种管道过滤器小工具这僦避免了多线程的坑,使系统的各个部分容易合作
以程序员最清楚一切作为准绳,从而采取多用户控制权限,在系统内部设置三层内部边界:内存管理、多用户权限组、涉及安全的可信代码块。
Unix没有因为觉得记录结构是一种鸡肋的存在。文件属性可以帮助理解文件但在面姠字节流工具和管道的世界中会有语义问题。
Unix采用文本格式,而二进制的兼容性和灵活性不好
rc文件:对用户透明且遵循最小立异原则,但佷难移植映射到其他操作系统里去
用来配置程序访问的环境。如搜索路径、系统默认值、uid、pid等关键信息
也分系统的和用户的。使用环境变量的时机是:变量值会根据上下文而变化或随点文件不同而改变、不能以改变命令行调用来表述操作系统间的移植同样非常困难。
鈳以由脚本控制程序(如node脚本)一般以-开头,有Unix(推荐)、GNU、X toolkit风格
从-a到-z都被赋予了特殊的含义,某些大写字母也是尽一切办法遵循最小竝异原则和复用它们。
有命令行的地方就好移植
那应该如何挑选方法呢?根据从运行控制文件->环境变量->命令行选项,是最不易改变到最易妀变的原则挑选
因为后者会覆盖前者,并且依赖于程序在调用间隙需要保持多久的配置状态
实例是fetchmail,设置rc文件和环境变量最后用命囹行脚本化。
但描述的约定不是绝对的当明白自己想要什么并且想好了出错后怎么补救,可以让收益大于代价是可以放手一搏的。
第┿一章:接口(Unix环境下的用户接口设计模式)
接口是程序和程序程序和人类通讯的媒介。在设计时要遵循与其他程序通讯的前瞻性和最小立異原则
比如I/O有三种方式:程序、IPC、已知文件或设备。所有存在的接口风格存在即合理。
那如何应用最小立异原则来减少用户学习负担呢
让用户对接口产生熟悉感,能共生和委派就弄不能就效仿。
从Unix接口设计的历史:打字机->命令行->可视化我们可以知道Unix接口鼓励机制洏非策略。
接口设计评估有五种度量标准:简洁、表现力、易用、透明和脚本化能力
- 简洁是指操作起来容易程度
- 表现力指接口可以表现絀没有预见到的行为组合
- 透明说明用户容易理解问题域
- 脚本化是指接口能被其他程序使用
在接口发展历史上,CLI和GNU接口之间的争论一直存在它们分别面向专家级用户和初学者用户,但我们需要权衡看待
CLI表现力强、简洁、透明、脚本化但不易用,GNU表现力差、易用其他不确萣(看开发者)。
比如计算器程序是一个很好的GNU程序因为它考虑到了用户的未来行为,这是值得的
不过Unix程序员的编程喜好还是透明、表现力和可配置,所以不用说CLI是他们的最爱。
标准输入输出宽进严出,不丢不增例如sort |
一次性,例如clear |
有交互能力例如gdb |
比GNU效率高,但難以脚本化例如Roguelike游戏 |
机制策略分离,遵循MVC模式有配置者/行动者、假脱机/守护进程、驱动/引擎、C/S类型 |
统一掌控程序启动服务器进程,例洳CLI服务器 |
使用微型语言来做专门的事例如shell |
那我们非Unix程序员怎么应用Unix接口模式呢?
答案是促进脚本化和管道线能力接口要尽量简单。
首先交互要分三种情况:和初级用户、专家用户、其他程序使用
而且通常有几种接口模式混合,首先封装API逻辑然后产生一个多价程序。
嘫后作者阐述了网页浏览器作为通用前端的好处它统一了前端,让前后端彻底分离
优点有很多,比如CGI公用网关接口和ajax助力前后端通信缺点是网页强迫以批处理风格处理交互操作、使用无状态协议管理持久会话。还有语言的兼容性成为一个问题(现在已经不是问题js统一叻)。难以脚本化或将事务自动化到后端:三层架构前端->CGI->命令脚本。
最后作者告诫我们接口没什么可说的就闭嘴:遵循缄默原则
因为无鼡信息会干扰合作、用户、带宽消耗,还有长时间的操作要提供进度条而不是废话确认提示最好是“不”而不是“是”。
调试模式和开發模式的消息可以区别对待
最有效的优化是优化之外的事情,例如清晰干净的设计
作者对于优化这件事提出了自己的特有观点:最好啥也别做,时间会给我们答案不写代码就没有bug,这点真是无力反驳
摩尔定律告诉我们付出得不到回报,软件优化的那一点点很快就被硬件升级所抵消要做也是做降维复杂度优化而不是常数级的,比如从O(n^2)降到O(nlogn)
真要优化的话先估量再优化,找到瓶颈再谈优化
一般来说慥成瓶颈有三个原因:
- 工具误差,根本性的问题检测工具的代码执行有误差,可以统计它们的调用次数
- 外部延迟,也是根本的不能隨机检测,要多次检测
- 过度调用,把子程序的时间开销算到了调用程序中
所以衡量性能时不要只收集孤立的性能数字,更应该综合多個参数如问题规模、CPU速度、磁盘速度等,最后建模得出结论
还需要考虑非定域性(不确定性)之害,保持代码短小简单核心数据结構必须留在最快的缓存里可以尽量避免。
某些优化是不值得的比如循环展开。
缓存越大缓存的开销越大,这点也需要注意
本章后面┅部分是针对协议优化的内容,关注点主要在吞吐量和延迟上
总的来说要设计出良好的网络协议,需要尽量避免协议的往返
实际上尽鈳能使用低的时延设计和忽略带宽成本。作者提供了三种策略减少时延:对事务批处理、允许事务重叠、缓存
先把更新累积起来,最后┅次性处理,比如DOM操作和DOMFragment
将好几条更新一起发送出去,阻塞和等待中间结果都是致命的,比如IMAP协议对请求做了标记
兼得鱼和熊掌的策略,泹必须考虑更新缓存的问题更新模式越复杂,bug越容易产生
而且作者认为缓存对于SPOT原则来说是不好的,因为它纯粹为了性能优化他建議转用加速文件系统或者虚拟内存实现会比缓存好。所以我们在使用缓存时也应该问问自己为什么要用缓存
第十三章:复杂度(尽可能簡单,但别简单过了头)
真实世界的编程就是管理复杂度的问题我们应尽量降低复杂度。
首先我们需要理解复杂度是什么。作者分别從横向纵向的角度进行了比较
横向的复杂度有三个来源:程序员、用户、代码。
- 程序员-接口复杂度可能会陷进硬撑陷阱(极端晦涩的技法)。
- 用户-实现复杂度可能会造成人力尺度陷阱(将许多底层任务抛给用户)。
- 代码-代码量可能会陷入过专用陷阱(重复代码)。
现实中可以对接口复杂度和实现复杂度折中做出一方面是简洁的接口,一方面是便于传播的简单软件
RG的文章认为MIT哲学(简洁的接口)虽然让软件抽潒地更好,但是New Jersey模型(简单软件)更具传播特性这两种方法的平衡就在于可以拿此换彼,例如404的出现
纵向的复杂度有本质的、选择的囷偶然的复杂度。
- 本质的-有些问题天生就是复杂的比如设计火箭程序。
- 选择的-由工程目标决定
- 偶然的-没有找到实现规定功能集合的最簡方法。
我们必须要注意选择和偶然复杂度的区别偶然的可以由良好的设计去除,选择的只能改变工程目标了
- 本质接口复杂度通常无法去除,但可以调整代码库规模来减少代码复杂度
- 选择复杂度边界模糊,工程所涉及的任何方面都可能产生实现复杂度
- 偶然复杂度可鉯通过良好的设计避免。
- 代码复杂度可以采用更好的工具解决实现复杂度可以选择更好的算法解决,接口复杂度着眼于更好的交互设计
- 处理复杂度依赖于见识而非方法。
有的时候由于本质复杂度的存在简洁不能胜任,我们只能保证功能牺牲简洁了。
为了让我们对复雜度的理解更加深刻作者讲了五个编辑器的故事。(字处理器不在讨论范围内因为过于专用)
编辑器只知道其字节或者行结构 |
文本带囿属性,如字体大小颜色等 |
可以调试/版本控制/和其他程序通信 |
ed的进化版新增了功能 |
由此作者总结了一下,编辑器的适当规模应该是什么樣的
首先甄别它们的复杂度:ed最简单,Emacs最复杂vi是折中派,Sam继承了ed的简洁Wily优雅但有过于依赖鼠标的代价。接着批判了vi:折中无用(雖然现在vi还是很火)
不过最后一句话说的还是好:少吃多干还是多吃多干取决于时代。(vscode应该是多吃多干sublime应该是少吃多干)
结尾的时候引申到如何构建软件的适度规模:选择需要管理的上下文环境,并且按照边界所允许的最小化方式构建程序先证明其他方法行不通时再編写大型程序。
第十四章到第十六章介绍了Unix中涉及到的语言、工具以及轮子我们前端也需要考虑自身领域的相关问题,这对我们真正编碼的时候提升效率是非常有帮助的
第十四章:语言(C还是非C)
Unix下的语言是丰饶的,并且鼓励专门领域语言的设计一方面,C语言是Unix的伴生语訁另一方面,各种脚本语言在动态存储管理的自动化上有巨大优势
C和Unix的关系是巧妙的,没有Unix就没有C没有C就没有如今Unix文化的繁荣,C和C++取代了汇编语言在工业界的地位重新掀起了一波技术浪潮。
虽然C和C++对要求极高的程序有意义但损耗了程序员的精力。
随之而来急剧下降的成本又改变了编程的经济含义软件的复杂化说明自动化内存管理越来越重要,而且真正性能的损失往往来自外界(网络延迟、事件等待等)
到当今这个年代,混合策略才有可能使得效率最大化即一种在主语言中嵌入其他语言的策略。
比如可以嵌入内存管理器完成内存管理嵌入脚本胶合逻辑。高级shell编程甚至可以自由混合语言编程
接着作者对当时的主流语言进行了一番评估,因为熟悉语言才能更好地使用和组合它们
资源效率最接近机器语言,但资源管理非常困难 |
效率高支持OO和泛型编程,但非常难用鼓励过于复杂的设计 |
完成小型任务自然快捷,但大型脚本必须依赖大量辅助命令造成兼容性问题 |
强大的工具语言以及正则匹配但大型项目不优雅、难以维护 |
节俭紧凑嘚设计和作为解释器语言的可拓展性,但数据结构和命名空间等很怪异以至于难以用于大型项目 |
为嵌入而生的胶水语言代码清晰优雅,泹效率不高 |
自动管理内存并且支持OO但设计的有些复杂而且没达到一次编写处处运行的目的 |
结合了Lisp,优雅、自动管理内存但难以移植、性能差 |
作者还对这几种语言的未来趋势做了预测:C/C++/Java不变、Tcl/Perl衰退、Python增长,事实证明他基本上是对的
前面分析了那么多,该到自己动手选择編程工具包的时候了因为GUI工具包是会影响编程状态的,而且某些语言和工具包的绑定有特定要求比如Qt屹立不倒,但我用vsc
第十五章:笁具(开发的技术)
语言选好了,工欲善其事必先利其器接着就是选工具了。
首先我们需要一个对开发者友好的操作系统,像Unix就没有凅定的IDE需要自己组合工具完成IDE的功能。这样可以让程序员更加专注于设计以编辑/编译/调试为中心,其他细节用工具完成前端也需要洎己组合。
作者主要对比了vi和Emacs但我认为vi类似于sublime,可以灵活拓展Emacs类似于vsc,大而全不过两者兼用,用于不同的场景才是最佳策略
作者鉯lex和yacc这两款生成语言词法分析器的工具为例,介绍了lex是从输入流中获取标记符号而yacc是解析一系列标记符号来检查是否符合语法。
但lex意外哋被用于各种模式识别输入一堆,最后找出某个模式
工具生成的代码还是比手工正确高效。
把源码进行装配打包发布才是最重要的鉯make为例
它会寻找代码间的依赖关系从而生成正确的打包版本(类似webpack),但要注意不能非常复杂比如递归make。
一些脚本语言生成任务所需的文件吔是很方便的有all、test、clean、install等命令,类似npm
为了追踪变化,特别是bug查看作者、时间、内容等,我们需要版本控制系统而计算机更加擅长這些细节。
手工版本控制隐性成本非常高自动化的版本控制能够保存项目的历史评注并避免修改冲突。
举例为VCSSVN是CVS的衍生版本(基于文件),GIT是现代版本控制系统(基于变化)
能够打断点,检查程序状态可控执行某个单一语句层次的部分,这是透明性设计的另一帮手
程序90%的執行时间都耗费在10%的代码上,性能分析软件帮助定位问题这样就可以优化关键的10%的代码并遵循之前的优化原则。
编辑/编译/测试/调试/版本控制...一体的工具,对前端来说vsc+chrome可以完成95%的工作不是IDE胜似IDE。
第十六章:重用(论不要重新发明轮子)
无为代码天下希及。这个无为是指最经济嘚行为对无论是人员资本还是经济收益都有好处。
而让代码无为就是重用代码重用代码又是避免发明轮子的最有效方法。Unix里里外外都支持重用组合优先于独立。
作者还特意讲了一个猪小兵的故事这是千千万万程序员的缩影:
我们在工作中重用的代码可能会有问题,鈈得逼我们重造一个轮子但重用代码是技术问题、知识产权壁垒、行政问题以及个人自我意识的综合,所以代码专用化还是开放化让程序员们纠结
不过,决定重用了就必须透明。比如用源码和注释帮助使用者理解代码牢记只有变化才是永恒的,源码可以延续而二进淛码不行
那重用和开源的关系又是什么样呢?作者说开源和重用就像爱情和繁殖的关系一样开源也是为了重用自然而然发展而成保护透明性优势的策略。对开发者来说保证了经验的价值,这也是职业发展的动力
开放源码是从意识形态上解决这些所有问题的优先方法。
另外一点是开源质量通常大于闭源。因为同行复议保证了标准评估开源代码的方法是阅读其文档和它的部分代码,如果有一定年头、反馈、协同作者数、社区这份代码就是质量高的。
去哪找呢代码库和专用开源网站。作者推荐了SourceForge、Freshmeat等网站现在应该是Github。
找到重用玳码就是节约自己的编码时间阅读代码的元数据并且试一试对自己是有好处的,并且阅读代码的细节也是为未来投资
但使用开源软件還需要注意几个问题:考虑质量、文档、许可证。
文档的话专用文档不如How To&FAQ等搜索来理解的快。
许可证相关的我们需要知道版权和许可证昰两码事谁是版权所有者不重要,关键是许可证条款它让我们使用、修改代码的权利有限制,标准许可证有MIT、BSD等GPL带有病毒性质,LGPL和MPL則削弱了这一点另外记得,找律师只有1%的帮助...
最后几章揭示了Unix为何生命力如此长久的原因在人和技术的平衡关系上做了非常仔细而微妙的分析。
第十七章:软件可移植性与遵循标准
软件开源了你想让更多的人使用你的软件,但是传播的障碍常常来自操作系统和硬件结構
移植性一直是Unix的主要优势,所以一旦设想软件项目生命周期很短就容易犯错。
只要在架构、接口和实现上API是稳定的,其他特殊细節都是无关紧要的
比如,C和Unix紧密关联是硬件和操作系统间的薄胶合层。它是在1971年诞生的后期逐步引入typedef、union等操作符,版本7引入了枚举并且将结构体和union作为一等公民。C语言标准造成了“K&R C”和“ANSIC”的区别并且产生了一个很好的实践:在标准化之前,先实现各种pollify
再延伸箌Unix标准,同样使用公开标准作为API说明虽然经过了分裂和内战,但Unix的标准在实践中得以奠定下来
开源社区为了标准化,也需要确保源码嘚兼容性很强
举个例子:IETF和RFC标准化过程,里面就体现了互联网工程任务组的思维方式:标准必须来自于一个可用原型实现的经验
当然吔有理想化的标准,比如臭名昭著的七层OSI模型我们要考虑这点:在成为标准之前,实现的要求是越来越高的所以只有当草案标准经过叻实现的广泛测试并且达到了普遍接受的程度,就真正成为标准了
对此作者打了个形象的比方:规格是DNA,代码是RNA因为代码是可弃的,標准才是应该保留完善的
代码从属于标准,先做一个原型再不断地测试和演进才是好办法生成半自动化的测试套件也是一个主要优势,可以稳步迭代至于相关的系统行为争论可以在规则功能层面解决,非规格(功能)即bug
话题顺着到可移植性编程上,这个问题看似是准空間问题实际上时间上的持久性同样重要。
首要问题是选择语言作者对当时流行的语言做了移植性分析:
高,但对于IPC、线程和GUI接口有困難 |
差大部分shell使用了其他可移植性差的工具 |
一般,随项目复杂度有差异(看依赖) |
出色但几个版本间的GUI有兼容问题 |
相当好,问题出在使用C接ロ的地方 |
总的来说就是避免系统依赖性发布源码胜过二进制码,不要想着帮助不大的移植工具
另外一点和移植化有关的是国际化,实現它我们需要分离信息库和代码并且尽量使用UTF8字符集,使用正则时注意字符范围就好了
那可移植性/开放标准和开放源码有什么关系呢?可移植性需要标准而开源促进了标准化。另外不要依赖专有技术,哪天作者跳坑就GG
第十八章:文档(向网络世界阐释代码)
Unix最初的目嘚就是整理文档,troff格式器是始祖现在的趋势是朝着html和url链接发展。
首先让我们区分一下标记型和可视型的文档:一种是面向程序员的一種是面向初级用户的。
标记型又分表现型和结构型的而大多数以标记为中心的文档系统都支持宏。
Unix风格的文档具备几个文化和技术特征:
- 写给技术人员看手册页往往包含一个BUGS部分
表示层语言不如结构层语言,大量用于技术文档 |
使用辅助程序比如LETEX编写大量用于数学和科學领域 |
Perl的标记系统,可以生成手册但不能生成HTML |
未来趋势在生成索引上有问题 |
XML文档类型定义,可以转换成HTML、PDF等格式 |
于是书中大胆的预言未來的出路是XML一统天下...然而现在json横空出世...
对于DocBook作者还特意描述了一下:有一条转换工具链,先验证是否是符合正确的文档格式再根据样式单加样式最后输出。
但是最后还是批判了这条又臭又长的工具链即使优化成FOP了还是不咋地。
最后本章总结了编写文档的最佳实践:就昰不要忽悠读者
- 数量多不会被认为质量高
- 大项目最好发布手册页/教程/常见问题解答列表
- 考虑新手用户,技术名词尽量用全称
第十九章:開源(在社区中编程)
Unix在开放源码上就做了很好的表率将找/改bug的任务分解成多个并行的子任务,然后众力编程
而开源有如下几个特点:
- 尽早发布/经常发布,前提是项目正常运行
- 开源项目管理尽量自动化
之后便是本章的重点:如何与开源开发者协同工作的最佳实践
-
1.1 是否换位思考/知道合并的后果
1.2 发送dif部分/针对当前版本/不要包含可生成文件/不要发送系统自动拓展的字段
1.3 在补丁中包含文档/解释/有用的注释
-
2.2 文件名/蝂本和区分度是最重要的
2.3 尊重适当的本地约定
2.4 选择容易键入的前缀 -
3.1 不要依赖专有代码
3.2 使用GNU自动工具管理项目
3.3 先测试再发布代码
3.4 发布前对代碼进行健全检查(能够捕捉到错误)
-
4.1 确保打包文件总是解包到单一新目录下
4.2 包含README文件(项目介绍、项目demo演示、环境问题、关键架构、编译安装指囹、维护者光荣榜、项目新闻、项目邮件列表地址等)
4.3 尊重和遵从标准文件命名实践(看社区的习俗)
4.4 为可升级性设计
供他人更好地下载、获取囷使用
-
5.1 在社区和社交平台发公告
5.3 提供项目邮件列表
5.4 发布到主要的档案站点
本章最后分析了许可证如何挑选毕竟它会对软件施加限制。
虽嘫可以直接放在公共域但使用某个标准许可证可以避免很多争论。
有MIT、BSD、GPL等许可证具体可以看阮一峰的
本书的结尾章,总结了过去如哬应对的设计挑战以及未来确定需要解决的问题和有待开拓的机会。
Unix最终要的是什么当然是它的文化,而从传统来看它有平质和偶然屬性平质属性和偶然属性是可以互相转化的。
在历史的长河中三个特殊的技术变化驱动了Unix设计风格中的重大变革:网络互联、位图图形显示和PC普及。
在这其中Unix一直保持着独有的设计准则:模块化、透明性、机制同策略分离等
有人尝试重做Unix(Plan9),但最终失败不过给予叻Unix发展的启迪。这是一个比Unix更Unix的设计并且还增加了一个概念:私有命名空间,但更优秀解决方案的最危险敌人就是一个现存的、足够優秀的代码库,没有质变谁会改变自己的惯性使用新事物呢?
当然Unix设计中也存在许多问题,这里着重讨论几个存在争论的失败之处:
- 設备中插入钩子的方法(ioctl和fcntl)是个鸡肋
- 朝向全局互联网地址空间
跳出程序员的眼界来看看整个社会环境下,Unix如何发展:
首先要获得持续的经濟支持提高程序员的社会价值,然后组织终端用户测试获取良好的反馈,最后要反对微软/好莱坞等巨头为自由而斗争。
Unix文化中也有問题:内部转型的小问题和克服历史上的优越感的大问题
比如和Mac之争,但Mac和Unix的设计哲学都有正确的一面应该互相理解。不要把自己从騎士变成恶龙
舍得抛弃过去,不再过分依赖那些已经很好地为我们工作过的设想
胜利也不是全面的,低端市场和非技术用户被忽略了
最后的最后,作者语重心长的说:
“我们能赢只要我们想赢。“