UNIX 编程艺术
UNIX 哲学浓缩为一条铁律,那就是 KISS 原则:Keep It Simple, Stupid! 通俗地讲就是:一个程序只做一件事,并做好。
1. 概括:
-
模块原则:使用简洁的接口拼合简单的部件。
计算机编程的本质就是控制复杂度。
-
清晰原则:清晰胜于机巧。
为了取得程序的一点性能就大幅的增加技术复杂度和晦涩性是不值得的。
-
组合原则:设计时考虑拼接组合。
程序/接口 独立、正交、通用。
-
分离原则:策略同机制分离,接口同引擎分离。
MVC 模型。
-
简洁原则:设计要简洁,复杂度能低则低。
-
吝啬原则:除非确无他法,不要编写庞大的程序。
-
透明性原则:设计要可见,以便审查和调试。
便于监测和调试。
-
健壮原则:健壮源于透明与简洁。
保证软件健壮性一个重要策略就是避免在代码中出现特例。
-
表示原则:把知识叠入数据以求逻辑质朴而健壮。
将代码复杂度转移到数据中。
-
通俗原则:接口设计避免标新立异。
最小立异原则。
-
缄默原则:如果程序没什么好说的就保持沉默。
重要信息不应该混杂在冗长的程序内部信息行为中。
-
补救原则:出现异常时,马上退出并给出足量错误信息。
4XX, 5XX 状态码。
-
经济原则:宁花机器一份,不花程序一秒。
高级语言的内存自动管理。
-
生成原则:避免手工 hack,尽量编写程序去生成程序。
例如:makefile
-
优化原则:明确性能问题再优化。
匆忙优化会使代码杂乱无章,过早局部优化可能会影响全局优化。
-
多样原则:绝不相信所谓「不二法门」的断言。
-
拓展原则:设计着眼未来,未来总比预想快。
为数据格式和代码留下拓展空间。
2. 模块化:
代码划分的方法有一个自然地层次体系,随着程序员面对的复杂度增加,这个体系也在演变中。一开始,一切都是一大块机器码。最早的过程语言首先引入了用子程序划分代码的概念。后来发明了了服务程序库,在多个程序间共享函数。再后来发明了独立地址空间和可以相互通信的进程(IPC)。今天已经习以为常地把程序系统分布在通过网络连接的多台机器上。
封装和最佳模块大小
封装良好的程序不会向外部披露过多自身细节(接口设计尽可能简单),不会直接调用其他模块实现码(调用其定义的标准 API),不乱共享全局数据。实际上,一些最有能力的开发者的开发模式总是:先定义接口,然后编写简要注释,对其进行描述,最后才编写代码。同时控制模块的长度,太长会使得代码难以阅读。
紧凑型和正交性
- 测试软件紧凑型的一个很好方法就是:有经验程序员是否需要操作手册?程序员很容易记住常用接口的调用子集。实现功能时尽量设计为某一常用功能的子集,减小功能冗余,永远不会太差。强紧凑型的程序总是围绕「解决一个定义明确的问题」组织设计。
- 正交性:每一个动作只完成一件事,无其他副作用。常见的错误设计:从磁盘某处文件读取文件,同时进行解析。但这会造成程序很难复用,文件读取和解析分布去完成设计更好。正交性高的程序 bug 量通常较低。重构的原则性目标就是提高正交性。
- SPOT 原则:不要重复自身(Don’t Repeat Yourself)。即任何一个知识点在系统内部都应该是唯一、明确、权威的描述。程序设计中应该无任何 重复数据、重复文档、重复接口。
3. 透明性和可显性:
- 透明性是一种被动品质,当可以预测程序行为大部分或全部情况,那么程序就是透明的。透明性的另一种表现就是程序对监控和调试的处理,通常把调试和探测开关的存在视为良好程序的标志。对用户的操作能够恰当地给出中间结果、有用反馈和错误通知。
- 可显性可由很多因素影响:程序正交,尽量保持少的特殊处理情况,降低 Magic Number 的使用量,控制程序的调用深度,增加必要注释和文档等都可提高代码可显性,降低代码的维护成本。
4. API 设计
在 UNIX 接口设计传统中最重要的两个主题:前瞻性设计和最小立异原则(子集)。
通常使用五种度量标准对接口风格进行分类:简洁、表现力、易用、透明和脚本化能力。
-
简洁
最少的动作和复杂度。函数参数严格控制,减少冗余参数。
-
表现力
最具表现力的接口可以启动程序设计者没有预见的行为组合,并返回用户一致的结果。例如:数学函数通用类型支持。
-
易用性
尽可能降低用户对接口的记忆成本。(最小立异原则)
-
透明性
对用户的操作能够恰当地给出中间结果、有用反馈和错误通知。所见即所得(What You See Is What You Get)。
-
脚本能力
接口能够容易被其他程序调用。(模块化)