《Unix编程艺术》第四章小记
第四章 : 模块性 : 保持清晰,保持简洁
Modularity : keeping it clean , keeping it simple
所谓的模块化原则就是:
定义清晰的接口把若干简单模块拼接起来。
这样多数问题只会出现在某个模块内部,debug和优化的工作可以在局部进行而不至于牵动整体。
1. 封装
- 封装良好的模块不会过多得向外披露自身的实现细节,不会直接调用其他模块的代码,也不会胡乱共享全局数据。模块之间通过API(程序编程接口——一组严密,定义良好的程序调用和数据结构)来通信。
- 检验API设计良好的一个方法是:如果试着用纯人类的自然语言来描述是否能把事情给说清楚?
- 实际上,优秀的程序员一开始总是定义接口,然后编写简要的注释,对其进行描述,最后才编写代码。
2. 紧凑性
- 紧凑性就是一个设计能否被人脑直接理解为一个原语操作的特性
- 一个检验紧凑性的方法就是调用某个模块需不需要对这个模块的实现有过多的了解
- 紧凑不等于薄弱,如果一个设计构建在易于理解且利于组合的抽象概念上,则这个系统能在具有强大且灵活的功能同时保持紧凑性。
- 紧凑也不等同于易于学习,对于某些紧凑的模块来说,在掌握其精妙的内在基础概念之前,要理解这个设计有或多或少的难度。但一旦掌握了这个概念模型以后,整个视角就会改变,紧凑的奥妙就非常简单了。一个经典的例子就是Lisp语言。
- Unix系统调用API是半紧凑型的,而C标准程序库无论如何都算不上是紧凑的。
- 紧凑性不是一个绝对的要求:合理对待紧凑性,设计中尽量考虑,决不随意抛弃
3. 正交性
- 在纯粹的正交设计中,任何操作均无副作用,每一个操作只改变一件事情而不会影响其它。
- 显示器就是一个例子。可以独立改变亮度而不影响对比度,色彩平衡控制也独立于前两个特性。
- unix哲学的第一个基本原则“一个程序只做一件事情”其实也暗含了对正交性至少同等程度的强调。
- 正交性缩短了测试和调试的时间,因为那种既不产生副作用也不依赖于其它代码副作用的代码校验起来要容易得多——需要测试的组合情况较少。
- 重构代码就是改变代码的结构和组织,而不改变其外在行为。
- unix系统在实现正交性方面并不完美,但也颇为成功。
4. SPOT原则
- 任何一个知识点在系统当中都应该有一个唯一,明确而且权威的表述。这个原则称为“Single Point Of Truth”或者SPOT原则。
- 重复会导致前后矛盾,产生隐蔽问题的代码。因为你修改重复点的时候,往往只是改变了一部分而非全部,这通常也意味着你对代码的组织没有想清楚。
- 常量,表和元数据只应该声明一次,并导入其他地方。
- 通常可以通过重构来修改重复代码,也就是说,更改代码的组织而不更改核心算法。
5. 怎么实现紧凑性
- 提高设计的紧凑性的一个方法,就是围绕“解决一个定义明确的问题”的强核心算法组织设计,避免臆测和捏造。
- 形式化往往能极其明晰地阐述一项任务。
- unix的很多行之有效的工具都是围绕一个强大的算法直接转换的thin wrapper.
- diff——一个用于报告相关文件不同之处的工具。使用一个简单而从数学上看很可靠的序列比对方法。
- grep实用程序就是围绕正则表达式模型的形式代数问题实现的。
- yacc——用于生成语法解析器的一个实用程序是围绕LR(1)语法形式理论的thin wrapper.
- 而lex——一个词法分析器,则是围绕不确定有限状态自动机的thin wrapper.
- 与以上相对的是试探法——凭经验法则得出解决方案。在概率上可能正确,但不一定总是正确。
- 试探法设计出的例子有垃圾邮件识别程序,虚拟内存管理。
- 试探法的问题在于这种方案会增生出大量的特例和边界情况。
6. 软件设计的两种方案
- 一般来说,设计函数或者对象的层次结构可以选择自顶向下和自底向上。
- 自底向上,从具体到抽象——从问题域当中确定要进行的具体操作开始,向上进行。
- 自顶向下,从抽象到具体——从最高层面描述整个项目的规格说明或应用逻辑开始,向下进行,直到各个具体操作。
- 要么抽象化硬件:对象封装了实际事物,程序不外乎针对这些实际事物的操控动作表;要么围绕某个行为模型组织代码:在行为逻辑流中嵌入实际执行的硬件操作。
- 当然这两种方式并不容易实现,实际上的代码往往是两者的综合产物,这样导致了胶合层的产生。
7. 胶合层
- unix程序员的经验告诉我们:胶合层是十分麻烦的,所以要让它尽可能地薄起来。
- 薄胶合层原则可以看作是分离原则的升华,策略(应用逻辑)和机制(域原语集)应该清晰地分离。
- C语言就是胶合层的一个例子。
posted on 2012-10-05 23:04 edward1992 阅读(238) 评论(0) 收藏 举报
浙公网安备 33010602011771号