本文摘自UNIX编程艺术
模块性体现在良好的代码中,但首先来自良好的设计。在编写代码时,问问自己一下这些问题,可能有助于提高代码的模块性:
* 有多少全局变量?全局变量对模块化是毒药,很容易是各模块轻率、混乱地互相泄露信息❶。
* 单个模块的大小是否在Hatton的“❷最佳范围”内?如果回答是“不,很多都超过”的话,就可能产生长期的维护问题。知道自己的“最佳范围”是多少,吗?知道与你合作的其他程序员的最佳范围是多少吗?如果不知道,最好保守点,坚持Hatton最佳范围的下限。
* 模块内的单个函数是不是太大了?与其说这是一个行数计算问题,还不如说是一个内部复杂性问题。如果不能用一句话来简单描述一个函数与其调用程序之间的约定,这个函数可能太大了❸。
就我个人而言,如果局部变量太多,我倾向于拆分子程序。另一个办法是看代码行是否存在(太多)缩进。我几乎从来不看代码长度。
----------- Ken Thompson
* 代码是不是有内部API----即可作为单元向其他人描述的函数调用集和数据结构集,并且每一个单元都封装了某一层次的函数,不受其他代码的影响?好的API应是意义清楚,不用看具体如何实现就能够理解的。对此有一个经典的测试方法:通过电话向一个程序员描述。如果说不清楚,API很可能就是太复杂,设计太糟糕了。
* API的入口点是不是超过7个?有没有哪个类有七个以上的方法?数据结构的成员是不是超过七个?❹
* 整个项目中每个模块的入口点数量是如何分布❺?是不是不均匀?有很多入口点的模块真的需要这么多入口点吗?模块复杂性往往和入口点数量的平方成正比
----------- 这也是简单API优于复杂API的另一个原因。
❶ 全局变量意同时也意味着代码不能重入;也就是说,同一个进程的多个实例可能彼此干涉。
❷ 模块分解的越彻底,每一块就越小,API的定义也就越重要。全局复杂度和受bug影响的程度也会相应降低。软件系统应设计成由层次分明的嵌套模块组成,而且每个层上的模块粒度应降至最低,计算机科学领域从二十世纪七十年达就已经渐渐明白了这个道理。然而,也可能因过度划分造成模块太小。如下:绘制一张缺陷密度和模块大小关系图,发现曲线呈U型。
❸ 很多年前,我(本书作者)从Kernighan和Plauer的《编程风格的袁术》(The Elements of Programming Style)一书中学到一个非常有用的原则,就是在函数原型之后立即写一行注释。每个函数都是这样,绝无例外。
❹ 《魔数七,加二或减二:人类信息处理能力的局限性》是认知心理学的基础性文章之一。这篇文章表面,人类短期记忆能够容纳的不连续信息数就是七,加二或者减二。这给了我们一个评测API紧凑性的很好的经验法则:编程者需要记忆的条目数大于七吗?如果大于七,则这个API可能不太算是严格紧凑的。
❺ 收集这种信息由一个简便的方法,就是分析etags(1)或ctgs(1)等工具生成的标记文件。