什么是好的系统设计?我不知道,但依我看,LaTeX 是坏的系统设计的一个典型,MFC 也如此,而坏的系统最重要的一个特点是,使用者不能把它作为一个黑匣子看待,而必须了解其内部构造才能有效使用它。
凡系统构造的时候,总希望隐藏内部的复杂性于简洁的接口背后,这样,用户只需要知道如何调用接口、这个接口实现了哪个功能就可以了,而不必了解其实现的细节。尽管 LaTeX 也是如此宣称的,可事实上并非如此,不了解实现细节,终究只能用到一些皮毛,稍微复杂一点的问题便解决不了。
举个例子,前些日子我希望实现这么一个功能,把每个章节标题的序号单独放在一列中,而正文与章节标题的文字对齐。如下:
1 Hello world..
A quick brown fox jumps over
a lazy dog.
按照默认的情况则是:
1 Hello world
A quick brown fox jumps over
a lazy dog.
可是,就算是实现书籍排版上这么常见的一个功能,LaTeX 也没有提供任何接口做到,不仅标准的文档类里面没有,连附加的宏包也没有实现这一功能的。所幸辗转所得一段代码能解决这个问题:
\makeatletter
\def\@seccntformat#1{\protect\makebox[0pt][r]{\csname
the#1\endcsname\quad}}
\makeatother
然而这段代码,根本是重新定义了 article 文档类中所用到标题数字格式,用到的纯属 TeX 的方法,和 LaTeX 简直毫无关系,试问若不看 article 的代码,怎能写出这段重定义的代码来,而这样一来,LaTeX 又怎么能算提供了一个黑匣子?
为什么说 LaTeX 对开发者来说也是糟糕的呢?是因为要写出这段代码来解决问题,首先你得对 LaTeX 的编程有所了解,否则 `\makeatletter`、`\makeatother` 是什么意思无从得知,第二得对纯 TeX 有了解,不然 `\def` 是什么意思也肯定不大了然,第三,你还得对别人写好的 article 文档类分析透彻,否则 `\csname` 是什么?`\@seccntformat` 又该放在哪里,有几个参数,从何得知?
这是 LaTeX 这种以编程的形式来排版的坏处,当然,也不能全归咎于形式,从 Knuth 始,大量的 LaTeX 开发人员,以及宏包的作者,都有一种把简单问题复杂化的倾向,好像不说得那么复杂无以显得自己水平多么高。明明一个参数就能解决问题的函数,非搞得七八个参数,看似灵活性高了,实则让人学起来、用起来头痛,没事谁愿意记你这个参数是干什么的?
最重要的是,这种方式不像 WYSWYG 的形式那么容易让人举一反三:同样一个功能,Adobe FrameMaker 中也没提供具体实现它的选项,但 FrameMaker 提供了几个很直观的功能:
首先,标题可以自动编号,你可以定制标题编号的格式
第二,可以创建一个在正文左侧的 column,成为 side-head,这一列保持空白,但标题可以跨越到这一列中
第三,标题编号的格式可以包含制表符
因此我自己就发现了可以用下述方法实现上边提到的功能:
首先,创建两个制表符:
* *
然后,把正文放在 side-head 右边的 column 里,标题则跨越到 side-head 中,但标题编号设置为 `\t
接下来,只需要保证第二个制表符的位置,和 side-head 的右边界相同便可以实现我需要的功能了。
这让我想起 Web 标准推行中表格与 CSS 之争,表格该不该用于排版,现在倒是没什么好争的了,但大家却甚少考虑,为什么表格用于排版会会这么流行?W3C 可从来么鼓励过大家这么做,但为何只需要一人介绍,便应者云集?其实正是因为表格比 CSS 直观得多,表格一画,哪边居左,多少留右,上边高度多少,底部留多长,一目了然,设计者容易构思,而不像 CSS,还要考虑什么绝对宽度、相对宽度、固定位置,甚至还要用浮动之类的方法来扭扭捏捏的实现……
好的技术首先应该是易学的,否则纵然再好,也必然为公众所抛弃。
* 前面提到 MFC,这里权且补充两句,君不见《深入浅出 MFC》,《MFC Internals》之类的书卖得一直很好,倘若耍耍 AppWizard 便能精通 MFC,大家还用得着费那么大的劲,通过看 MFC 的代码来理解其深刻含义么?