IT 论文精读 · PAPER 43

如何把系统拆成模块 · 信息隐藏

David Parnas · Carnegie Mellon · CACM 1972

EN →

这篇论文干了什么?

把一个大程序拆成几块(模块)来写,几乎是所有软件的必经步骤。可 1972 年,David Parnas 追问了一个当时没人认真回答的问题:到底该按什么标准去切这一刀?他给的答案叫信息隐藏(information hiding)——这正是今天你能悄悄换掉一个模块而不牵动全身、一个大团队能各写各的、以及「面向对象」「API」这些词能存在的根本原因。

先看看大家惯常怎么切

最自然的切法是按步骤:程序先读输入、再加工、再排序、最后输出——那就一步一个模块,照着流程图一刀刀分。听起来天经地义,几乎每个新手都会这么干。

这么切的坏处

问题是,这些「按步骤」切出来的模块,其实共用着一个心照不宣的秘密:数据在内存里长什么样(一行怎么存、一个字怎么摆)。哪天你想换个更省内存的存法,会发现几乎每个模块都得跟着改——因为每块都直接摸着那份数据格式。牵一发动全身,这正是软件难改、难分工的病根。

Parnas 的点子

他说:别按步骤切,按「秘密」切。先坐下来列一张单子——哪些设计决定以后最可能变?(数据怎么存、用什么排序法、外部数据什么格式……)然后让每一个这样的决定,单独藏进一个模块里,只有它自己知道。别的模块想用它,只能隔着一扇「窗口」(一组说好的函数)打交道,永远看不见窗口后面是怎么实现的

为什么这样就好使

把模块想成一家餐厅的厨房:你(别的模块)只在取餐窗口点菜、拿菜,厨房里用什么锅、按什么菜谱、怎么摆盘,是厨房关起门来的秘密。哪天厨房换了灶具、改了做法,只要窗口端出来的还是那道菜,你根本不用知道、也一行都不用改。于是「改动被关在一个房间里」,出不来;而且大家各管一个房间,事先只要把「窗口长什么样」约定好,就能同时开工、互不打扰。

一句话记住

别按「程序的处理步骤」拆模块,按「以后最可能变的设计决定」拆——每个模块藏一个这样的「秘密」,只把一扇稳定的窗口(接口)露给别人。于是改动被关在一块地方、团队能各写各的。这条准则长成了后来的封装、抽象数据类型、面向对象和 API。

(一句诚实的代价:你得猜对「什么会变」。猜错了,就把根本不会变的东西藏了起来白费劲,甚至为了「万一要变」过度设计。)

想看两种拆法的对照图、KWIC 例子和它如何长成面向对象? → 切到精读版