理性设计过程 ============================================================ .. We can produce an html file from this document using the following command: rst2html.py a.rst a.html `Parnas and Clements. 1986. A rational design process: How and why to fake it. IEEE Trans. Softw. Eng. 12, 2 (February 1986), 251-257. `_ .. |date| date:: .. |time| date:: %H:%M 文件更新时间 |date|. .. contents:: 内容目录 通篇总结 ------------------------------------------------------------------------- 伍泰炜 OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 读完全文之后,我感觉作者能把前面十几页的内容写出那么多字,真是十分了不 起,可能这就是科研工作者的特长吧,把一个东西反复讲述,使得论文的篇幅变 得很长,让人看起来好像内容很多。 .. 作者之所以能写那么多,是因为8年前有 A7E Aircraft 需求分析的经验。见 第9篇参考文献:software requirements for the A-7E Aircraft 以下是我没有做第二遍阅读,单凭印象做出的理解。(而且我也相信第二遍和第 一遍不会有很多改变。) 作者核心观点是,一个合理的设计过程需要写一大堆东西,比如“设计文档/需求 分析/母子模型/接口说明”,在设计之初就开始写,在设计过程中每一次改变都 要清晰的更新。然而这是很难的,甚至一般都是不可能也做不到的,作者于是说, 那就假装(尽力)做一个。 有一个合理的设计过程有什么用呢? 在开发过程中,有助于估算一个过程的时 间与金钱花费,减少重复决策,减少大改次数,方便维护,防止因人员变动而对 接困难,等等。这些的前提都是有一个合理的设计过程,如果没有,或实施得不 那么周全,就不会有那么理想的辅助效果。 那么怎么假装呢? 这篇文章有很多方法论式的表述,但缺少举例 —— 可能也很 难举例,毕竟是理想状况 —— 总之就是多花时间写文档。具体而言,在最开始的 时候就照着自己理想目标去写,不要去考虑实际实现的过程,以免后期忘掉了最 开始的想法。开发的过程中,要坚守 **Write Everything Down** 的原则,无 论有什么决策改变或者修改,都要如实的写下原因。 在我看来能做到自然是一件很理想的事情,或许在一个长期的软件开发过程中, 这是重要的。根据我的个人经验,比较多的开发者会写 change log/update log 之类的东西,这也算文档的一种,但是可能更面向用户一些。 像这篇论文中的 文档可能对于短期的私人项目开发太繁琐了,也是有局限性的。 作者在最后几页分析一些他不认同的行为。比如软件做完了再写各种文档。文档 要么是意识流要么是面向实现。或者干脆文档很少,都靠代码注释,这样的文档 很难看懂,过多的注释也会导致后续的修改很麻烦(改了一个注释,还有多少注 释要受牵连呢?) Page 1 ------------------------------------------ 徐梦旗 OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 理性设计过程: 如何、为何要仿制它 摘要 软件工程师们一直在探寻最为理性的软件开发过程: 像从发表的公理中导出引 理与定理那样, 从软件规格说明中导出程序。 在解释为何我们永远无法做到如 此之后,本文描述这样的一个过程。 这个过程由一系列应该在软件开发中产生 的文档来描述。 产生这类的文档有几个方面的目的。 作为初步设计检查的基础, 作为编程的参考,作为维护程序员的指导。 我们讨论使用与软件设计相同的原 则来编写文档。 这样产生的文档远比 “事后考虑” 文档有价值。 如果我们经 常仔细更新所有文档,那么我们就好像有了理性设计过程。 Page 2 ---------------------------------------------------------- 田遍地 OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 理性设计过程: 如何、为何要仿制它 **David L.Parnas** - 加拿大维多利亚大学计算机科学系,美国华盛顿海军研究实验室计算机科学和系统分支 **Paul C. Clements** - 美国华盛顿海军研究实验室计算机科学与系统分支 I. 寻找哲人之石: 为什么要理性设计过程? ````````````````````````````````````````````````````````````` 理性的人做事总有理由。每一步都是实现既定目标的最佳选择。大多数人自认为 是专业人士。 然而,在观察家看来,通常软件设计过程显得相当不理性。程序 员经常在没有理由的情况下做决定,没说清要做什么就动工了。他们做很多决定, 却说不清那么决定的理由。目标不明确,也很少解释如此决定的理由。 很多人不满意这样的设计过程。 所以就有对软件设计、编程方法、结构化编程 以及相关主题的研究。 理想情况下,我们希望像从公理中推出定理那样,从需 求中获得程序。 所有 “自顶向下” 的方法, 都是我们渴望拥有理性、系统的软 件设计方法的结果。 Page 3 ----------------------------------------------- 徐闰钞 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 所有可以被归类为“自顶向下”的方法都是我们希望有一种合理又系统的软件设计方法的结果。这篇文章既带来坏消息,也带来好消息。坏消息是,在我们看来,我们永远找不到哲学家stone。我们永远找不到一个能让我们以完全合理的方式设计软件的过程。好消息是我们可以伪造它。我们可以像是理性的设计师一样向别人展示我们的系统。还有一个好消息:这样做是值得的。 二。为什么软件设计“过程”总是理想化? 我们永远不会看到一个软件项目按照上面的建议进行。部分原因如下: 1。在大多数情况下,委托构建软件系统的人并不确切地知道他们想要什么,也无法告诉我们他们知道什么。 2。我们即使知道了需求,也还需要知道很多其他的事实来设计软件。许多细节只有在我们实施的过程中才会被我们了解,我们从中学到的一些东西会使我们的设计失效,于是我们必须回溯。 3.即使我们在开始之前就已经了解了所有相关的事实,经验表明,人类无法完全理解那些为了设计和建立一个正确的系统而必须考虑的过多的细节。设计软件是一个我们试图分离关注点的过程,因此我们将会处理大量可管理的信息。然而,在我们达到目的之前,我们必然会犯错误。 4. 即使我们能够掌握所有需要的细节,除了那些最微不足道的项目外的所有项目都会受制于外部原因而发生变化,其中一些变化可能会使以前的设计决策失效。 Page 4 ------------------------------------------------------------------- 吴贞娴 OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5. 用人就会有人为错误。无论我们的决策过程多么理性,无论我们的相关事实 收集和组织多么好,我们都将会犯错。 6. 自己发明的、从相关项目获得的、课上听到的先入为主的设计思想经常干扰 我们。 有时候我们会为尝试一个喜欢的想法而去做一个项目。 这种想法也 许不是经由理性过程从需求中产生;而是自发地由其他来源产生。 7. 由于经济因素,我们常被鼓励去使用其他项目开发的软件。在其他情况下, 我们也许会被鼓励与另一个正在进行的项目共享我们的软件。 这会导致最后 得到的软件可能不是任一个项目的理想软件,即不是仅根据需求开发的软件, 虽然这样的软件也能用且开发省力。 出于这些原因,软件设计人员以理性、无错误的方式从需求中获得设计这样的情 形是不现实的。我们相信从来没有系统是以这种方式开发,或许将来也不会有。 即使是教科书和论文中各种小程序开发也不是真实的,是经过了修改和润色了的, 直到作者展示了他希望自己曾经做的,而非实际发生的情况。 III . 尽管如此, 为什么描述理性理想化过程是有用的呢? ```````````````````````````````````````````````````````````````````````````````` 上文所述之困难甚为明显,认真的思考者都知道,其中诚实者也承认如此。 尽 管如此,我们还是看到软件设计过程为主题的会议、软件设计方法论的工作组和 软件设计课程市场(以声称用逻辑方法来设计软件而获利丰厚)。这些人想要达 到什么目的呢? Page 5 --------------------------------------------------------------- 余慧 OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (与吴贞娴翻译的最后一段同: 上文所提及的内容,很明显为每个深思熟虑过 的人所知、为坦诚的人所承认。尽管如此,我们仍旧能看到以软件设计过程为主 题的会议、研究软件设计方法论的工作小组,以及为了丰厚市场利益扬言能描述 软件设计逻辑方法的课程。这些人想达到什么样的目的?) 如果已确定理想过程但不能精确遵循它,我们仍然像遵循理想过程而产生文档一 样,去编写文档。 文档读者会从 **对设计的理性解释中** 受益。 这就是我们 所说的“假装理性设计过程”。 下面,我们列举假装如此的一些理由: 1. 设计师需要指导。 当承担一个大项目时,我们容易被任务的艰巨性压倒。 不能确定首先做什么。 好好理解理想过程会帮助我们知道如何进行项目。 2. 比起依靠临时决策来推动项目进行, 如果我们试着去遵循某一过程,那么我 们会更靠近理想过程、更靠近理性设计。 例如,即使我们无法知道设计一个 理想系统所需的所有事实,在编码前去寻找这些事实的努力会帮助我们更好 设计、更少返工。 3. 承担多个软件项目的机构如果拥有统一标准则会有很多优势。 会使设计审核, 以及人员、想法和软件在项目之间的转移变得更容易。 如果我们要去指定标 准过程,标准过程就应该理性的。 4. 如果我们已经定下理想过程,那么衡量项目进展就会变得容易得多。我们比 较项目目前的成果与理想过程所要求的成果, 确定落后(或领先)的地方。 Page 6 -------------------------------------------------------------------------- 魏含饴 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5.外部人员对项目进展情况进行定期审查会为形成良好的管理造成至关重要的影响。如果项目计划进入一个理想的进程,那么审查就会更容易进行。 IV.开发过程的描述应该告诉我们什么? 我们相信对于开发过程描述的最有用形式是工作产品。对于过程的每一个阶段,我们都会进行描述: -下一步我们应该做什么; -工作产品必须满足什么标准; -什么样的人能够胜任这项工作; -他们会在工作中使用哪些信息; 任何无法描述的对工作产品过程的管理只能从精神方面被理解。只有当我们知道哪些工作产品是适当的,它们必须满足什么标准,我们才能审查项目并衡量进度。 V.合理的设计过程是什么? 在本节中,我们将描述我们所遵循的合理的、理想化的软件设计过程。每个步骤都附有与该步骤相关联的工作产品的详细描述。以下过程的描述既不包括测试也不包括审查。这并不意味着我们忽视了其中的任何一个。在本文中,我们描述的是一个理想的过程;测试和审查属于实际的过程,而不是理想的过程。在应用本文描述的过程时,我们对每一个工作产品进行了广泛而系统的审查,并对生成的可执行代码进行了测试。 Page 7 --------------------------------------------------------------------- 叶红霞 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在实施本文描述的过程时,我们对每一个工作产品进行了广泛而系统的审查,并对生成的可执行代码进行了测试。 A.建立并记录需求 如果我们要成为理性的设计师,我们必须开始知道我们必须做什么才能成功。我们将其记录在一个称为需求文档的工作产品中。在我们开始之前完成这个文档,就可以让我们设计出所有面临的需求。 1.为什么我们需要一个需求文档? - 在设计程序时,我们不太可能偶然随机地去做需求决策。 - 我们将避免重复和不一致。没有这个文档,它回答的许多问题会在整个开发过程中被设计师、程序员和审稿人反复提问。这样花费会很昂贵,且易导致回答不一致。 - 在系统上工作的程序员通常不熟悉应用程序领域。对于外部可见的行为有一个完整的参考可以让他们不必去决定什么是对用户最好的。 - 对构建系统所需的工作量和资金进行良好估计是必要的(但还不够)。 - 这是一种有针对人员流动成本的有价值的保险,当有人离开项目时,我们获得的有关需求的知识不会丢失。 - 它为测试计划的开发提供了良好的基础。没有它,我们不知道该测试什么。 - 它可以在系统就位后长时间使用,为将来的变更定义约束条件。 Page 8 -------------------------------------------------------------------------- 王如韵 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -它可以用来解决争议;我们不再需要成为或咨询应用程序专家。 确定详细的需求很可能是这个过程中最困难的部分,因为通常没有组织良好的信息来源。理想情况下,它应该由未来使用它的用户来制作。事实上,它很可能是由软件设计师来设计的,而他们的想法必须得到用户的认可。 2.需求文档中包含了什么?在理想化的设计过程中,需求文档内容的定义很简单:它应该包含编写正确软件所需的所有内容,仅此而已。当然,如果现有信息准确且组织良好,当然,我们可能会引用。好的需求文件的一般规则包括: -每一项陈述声明应适用于所有可被接受的产品本身;而不应该依赖于可实现的决策。 -文件应是完整的,就是说如果产品符合每一项陈述,则该文件应是可接受的。 -在必须开始开发之前,如果没有可用的信息,则指出不完整的地方,而不是简单地省略。 -该产品应该是由参考文件组织,而不是介绍系统,因为这是最有用的形式。虽然编写这样一份文件需要付出相当大的努力,而且比介绍系统更难于阅读,但从长远来看,它节省了人力,因为在这个阶段获得的信息是以一种便于在整个项目中引用的形式记录下来的。 Page 9 --------------------------------------------------------------------- 蒋佳玲 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 我们使用关注点分离来获得以下部分,从而在我们的需求文档中获得完整性: —— 软件必须在其上运行的机器的一种规格。这台机器不一定是硬件——对于一些系统,这一部分可能只是指向语言参考手册的指针; —— 软件与外界通信必须使用的接口规范; —— 对于每个输出,其值在任何时候都以系统的软件可检测状态表示; —— 对于每个输出,软件需要多长时间或多快重新计算它; —— 对于每个输出,它需要有多精确。 —— 如果要求系统易于更改,则需求必须包含被认为可能更改的区域的定义。您不能设计一个系统,使所有的东西都同样容易更改,而且程序员不应该必须决定哪些东西最有可能更改。 —— 需求还必须包含关于当系统由于不希望发生的事件而不能满足其全部需求时,系统应该做什么的讨论。大多数需求文档忽略了这些情况;他们讨论当一切都完美运行时将会发生什么,但是留给程序员决定在出现部分故障时该做什么。 我们希望清楚地表明,除非定义了每一个需求,否则无法编写正确的软件,并且一旦您成功地指定了每一个需求,您就已经完全指定了系统的需求。 Page 10 ---------------------------------------------------------------------------- 应舸 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 为了确保文档的统一性和完整性,文档编写的组织过程背后必须有一个简单的数学模型。 我们的模型是由我们在实时系统上的工作所激发的,但正因为如此,它具有完全一般性。 所有系统都是实时系统。 我们假设对于实时控制系统,理想的产品不是纯数字计算机,而是由控制模拟计算机的数字计算机组成的混合计算机。 模拟计算机将输入测量的连续值转换为连续输出。当离散事件发生时,数字计算机带来模拟计算机计算功能的离散变化。 实际系统即是该混合系统的数字近似。 与其他工程领域一样,我们首先描述这个“理想”系统,然后指定允许的公差来编写我们的规范。 在我们的需求文档中,我们认为输出的地位远高于输入。如果我们得到输出值是正确的,那么没有人会介意我们甚至采用不读取输入的方法。 因此,该过程第一阶段的关键是识别所有输出。 我们需求文档的核心可以被表述为表格形式的一组数学函数。每个函数都将单个输出的值指定为与应用程序相关的外部状态变量的函数。 以这种方式生成的完整文档的一个例子,我们将在本文[9]中给出并在[8]中讨论。 B.设计和记录模块结构 除非产品足够小,小到能由单个程序员生产,否则我们现在必须考虑如何将工作分成多项工作任务,我们称之为模块,应在此阶段生成的文档称之为模块指南。它通过陈述将由该模块封装的设计决策来定义每个模块的职责。 Page 11 ----------------------------------------------------------------------- 徐焕众 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 模块可以由子模块组成,或者也可以被认为是单个工作任务。 我们需要一个模块指南来避免重复,避免空白,共同实现关注点的分离,以及 最重要的,来帮助一个无知的维护人员找出需要的模块当他有问题报告时必须处理时。再来,记录我们的设计决策的文档与我们在维护阶段使用的文档是相同的。如果我们只是努力地将信息隐藏或关注点分离应用于一个大型系统,那么肯定会产生大量的模块。一个没有其他结构,只是很简单的列出模块的向导,只会帮助那些已经熟悉系统的人。我们的模块是树形结构的,将系统划分成少量的模块,并以相同的方式处理每个模块,直到所有模块都非常小为止。举一个相关文档的完整例子:见[3J]。关于这一办法及其好处的讨论,见[15,6]。 C.设计和记录模块接口 高效和快速的软件生产需要程序员们能够独立工作。模块指南定义了需求与责任,但是它没有提供足够的信息来允许模块的独立实现。每个模块必须指定精确的接口。每个模块都必须编写模块接口规范;它必须是正式的,并提供每个模块的黑匣子图片。它们是由潜在的实现者与高级设计师一起编写的,并由使用这些界面的程序员一起评审。一个模块的接口规范只包含仅仅足够的信息供另一个模块的程序员使用它的设备,而不能做其他事。这也是系统所要求的。· Page 12 ------------------------------------------------------------------------------ 何可人 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 我们生产的文件由两者使用。 虽然,每一此类文件都由一个人专门负责,但它们实际上是由那些负责实现这些模块的人,使用这些模块的人以及对这个模块的设计感兴趣的其他人,例如:评审,谈判产生的。这些规范的主要内容有: - 一系列可被其他模块用程序(被称为“访问程序”)调用的的程序。 - 这些访问程序的参数。 - 这些访问程序对彼此的影响。 - 必要时的时序约束和精度限制。 - 不期望事件的定义(禁止发生的事) 在许多方面,这个模块的规格类似于要求文件。但是,符号和组织的使用更适合于我们在这个过程中所关注的软件到软件的接口。 已发表的例子和解释包括[Ii],[2],[i],[5]。 D. 设计并记录模块的内部结构 一旦指定了模块接口,其实现可以作为独立任务被执行,但评论除外。但是,在我们开始编码之前,我们希望在模块设计文档中记录主要的设计决策。这个文档旨在开始编码前对设计进行有效的检验,并向未来的维护程序员解释代码背后的意图。 在某些情况下,模块只是被简单地分成一个个子模块,而设计文档被当制作是另一个模块指南。在这种情况下,该模块的设计过程应在上面的步骤B处重新开始。而在其他情况下,我们首先应描述其内部数据结构; Page 13 ------------------------------------------------------------------------------- 袁世家 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在另一些情况中,我们从描述内部数据结构开始;还有一些情况是,数据结构被子模块使用(和隐藏)。对于每一个访问函数,我们引用一种函数或者描述数据结构上的影响的LD关系。对于每一个模块所返回给使用者的数值,我们都提供了另一种数学函数,这个抽象函数将数据结构的值和其返回值一一对应。对于每一个不确定的事件,我们描述了怎样去检查它。最后,我们还提供了一种证明方法,这种使用此类性质来编程的观点可以满足模型的规格。 我们继续分解子模块,直到每个工作任务小到我们能够忽略它,并且当程序员离开该工程后可以继续工作。 如果我们不能编写一个可读的高级语言,例如,如果没有可用的编译器,我们使用伪代码作为文档的一部分。我们发现由另外某个人写伪代码而不是最终的程序员写代码,并且让两个程序员负责两种代码的连贯性是很有用的。 E 设计并且记录使用层次结构 一旦我们知道所有的模型和它们的许可程序,就可以设计使用的层次结构。他被方便地记录为二进制矩阵,当且仅当位置(a,b)的入口为真,程序A的正确性取决于系统中是否存在正确的程序B。使用层级结构定义了可以由删除整个程序并且没有重写任何程序获得的子集。这对于分阶段递交,故障弱化系统,和程序集合的发展很重要。 Page 14 ------------------------------------------------------------------------------ 陈肖飞 OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ F. 编写程序 在设计和文档编制完成后,我们就可以编写代码了。我们发现这件事进展的迅速 而顺利。我们认为,代码注释不应该包含文档中已经有的内容。否则,系统维护 会更加昂贵,同时增加了代码与文档不一致的可能性。(因为会出现注释改了, 而忘了更新对应位置的文档。或者文档改了,而忘了更新对应位置的注释。) VI.文档在这一过程中的作用是什么? ``````````````````````````````````````````````````````````````````````````````` A. 当前的文档有什么问题? 为什么它不便使用? 为什么它晦涩难懂? 很明显,文档在我们描述的设计过程中扮演着重要角色。大多数程序员认为文档 是一种必要的累赘,是在事后才做的,只是因为有些官僚需要文档。但我们认为, 在发布之前都没有使用过的文档一定是糟糕的文档。 多数文档不完整不准确,但这并不是主要的问题。如果是的话,只要简单地添加 或者纠正信息就可以纠正它们。事实上,有一些根本的文档组织结构问题才是导 致不完整和不准确的原因,而且这难以修复: - 糟糕的组织。今天的大多数文档可以被描述为“意识流”和“执行流”。意识流写 作将信息放在作者写作的时候突然想到的那个点上。执行流描述了系统在运行 时发生的事情的顺序。 Page 15 ---------------------------------------------------------------------------- 陈俊蕾 OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 文档中多余的注解是没必要的,且会使系统维护变得更加昂贵。 除此之外,还 会增加代码与原文档不符的可能性。 VI. 文件在此过程中充当什么样的角色? `````````````````````````````````````````````````````````````````````````````` 现在的文档到底哪儿有问题? 为何难用? 为何没人读? 显然,设计过程中文档扮演着一个重要的角色。是祸躲不过,许多程序员认为文 档是“事后考虑”之物,只是官僚的要求而作。我们认为那些在发表前从未被使用 的文档都是很差的文档。 大多数文档都不完整、不精确,但这不是主要问题。可以通过添加或修改信息进 行改正。 事实上是引起文档不完整与不正确的内在结构组织问题不容易修复。 - 很差的文档组织结构。 现今的文档,可分为 **意识流** 与 **执行流** 。 意识流写作把即兴想法写在作者正在写的地方。执行流写作按照系统运行时事 件发生的顺序去写。 这两种文档风格的问题是:除作者本人,其他人不容易 找到他们想要的信息。 因此难以判定某信息是否丢失,难以修改错误信息。 软件发生变化时,找不到所有文档对应的位置去修改。 Page 16 ------------------------------------------------------------------------------ 王海榕 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 如何避免这些问题? 文档在理想的设计过程中满足了开发人员和后期维护程序员的需求。上面提到的 每个文档都记录了设计决策,并作为设计其余部分的参考文档。但是,它们也提 供了维护人员所需要的信息。由于这些文档在整个软件构建过程中都被用作参考 手册,因此它们将是成熟的,可以在以后的工作中使用并且始终是最新的。我们 设计过程中的文档不是事后才想到的;它被认为是项目的主要产品之一。可以使 用一些检查来增加完整性和一致性。这种文档处理方法的一个主要优点是改善了 神话中的人月效应[4]。当新程序员加入项目时不需要依赖老员工为他们提供项 目信息。他们将拥有一个最新的和理性的可用文档集合。我们通过花费大量精力 设计每个文档的结构来避免“意识流”和“执行流”文档。我们通过声明文档必须回 答的问题来定义文档并将这一原则贯彻到各个部门。我们试图为每一个必须包含 的事实找到一个位置,并确保只有一个这样的位置。只有在确定了文档的结构之 后,我们才开始编写它。如果我们编写许多特定类型的文档,我们就为这些文档 编写并发布一个标准组织[5]。我们所有的文档都是按照指导软件设计的相同原 则设计的,即关注点分离。系统的每个方面都在一个部分中描述,而在该部分中 没有其他内容。当审查我们的文件时,我们会审查它们是否符合文件规则以及是 否具有准确性。 Page 17.a -------------------------------------------------------------------------------- 周佳威 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 这样生成的文档既不简单也不轻松,但也不枯燥。我们利用表格、公式和形式符 号来增加信息的密度。我们的组织规则防止了信息重复,其结果是文档化,必须 非常认真地阅读,但回报读者详细和准确的信息。为了避免传统文档中出现混淆 和不一致的术语,我们使用了特殊括号和类型化字典系统。我们必须定义的许多 术语中的每一个都包含在一对显示其类型的括号符号中。对于每个这样的类型, 我们都有一个只包含该类型定义的字典。虽然刚开始阅读的读者会发现!+terms+l、 %terms%、#terms#等符号的存在,但是令人不安的是,像我们这样文档的普通用 户会发现括号中隐含的类型信息使文档更容易阅读。使用由类型构成的字典使我 们不太可能为同一个概念定义两个术语,或者为同一个术语赋予两个含义,同时 特殊的括号符号使对已介绍但未定义或已定义但从未使用过的术语进行机械检查 变得很容易。现在,我们如何伪造理想过程? 上面描述了我们希望遵循的理想流程以及在此流程中生成的文档。我们通过生成 文档来伪造这个过程,如果我们以理想的方式做事,就会生成这些文档。我们试 图按我们所描述的顺序制作这些文件。如果我们不能得到一条信息,我们就会注 意到在文档的一部分中,信息应该去哪里并继续设计,就好像该信息会按照预期 发生变化一样。如果发现错误,我们将更改它们,并在随后的文档中进行相应的 更正。我们将文档作为设计的媒介,在所有级别的设计决策都被批准纳入文档之 前,不会考虑任何设计决策。无论我们在途中遇到多少困难,最终的文档都将更 容易理解和适应。我们没有展示事情实际发生的方式,我们展示的是我们希望事 情发生的方式和事情的方式。 Page 18 ----------------------------------------------------------------------------------- 方梓安 OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ vii. 如何假装理想的过程? 上文描述了我们希望遵循的理想过程,以及这一过程所产生的文档。 我们通过 产生文档来假装这个过程。 我们用上文描述的顺序去试着产生一系列文件。 如 果某部分信息缺失,我们在文档相应位置注明此处信息缺失,然后着手设计(设 计时假定该部分信息会改变)。 如果我们发现错误,就会更改错误,并更改后 续文件的错误。 将文档作为设计的媒介。在设计决定在所有层面都获准并纳入 文档前,该设计决定无效。不管中途我们如何经常犯错,最终的文档都会准确、 更容易理解。 我们不展示事情发生的方式,我们展示我们希望它们发生的方式, 以及事情本身。 甚至数学,许多人认为最理性的学科,也遵循上述过程。 数学家不断地改进他 们的初始证明,通常最后的证明与初始证明很不一样。 初始证明往往来自痛苦 的发现之旅。 有了初始证明后, 数学家的理解慢慢加深, 会去简化证明。最 终, 数学家找到了一个更简单的证明,使定理的真实性更明显。 更简单的定 理证明出版了,因为读者对定理蕴含的真理比对定理的发现过程更感兴趣。 我们相信此种类比同样适用于软件。 阅读软件文档是为理解这个程序,而不是 再现程序产生过程。 我们提供读者需要的合理化的文档。 我们的文档在一个重要的方面与理想化的文档不同。 我们 **记录所有我们考虑 过与排除的备选方案** , 包括记录文档的早期版本的决定。 对于每个备选方 案,我们解释为什么当初会考虑它或为什么会最后排除它。 这样不管多长时间 以后,我们(或维护者)有同样的问题就能从这些记录中找到答案。 Page 20 ---------------------------------------------------------------------------------- 刘莉莉 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 从这个过程得到回报的例证是由我们几年前写的软件需求文档提供的,其作为理 想过程演示的一部分[9]。通常,人们认为需求文档在编码开始之前就生成了, 并且不会再使用它。然而,事实证明并非如此。那些满足我们的要求文件的软件, 它的原始版本仍在进行修订。每次更改后就必须测试软件的组织,都会广泛使用 我们的文档来选择他们所做的测试。当需要进行新的更改时,需求文档用于描述 那些必须更改的内容和不能更改的内容。在软件投入使用后,该过程中生成的第 一份文件一直被使用了很多年。可以明确的是,如果一个文档是经过精心制作的, 那么它将在很长一段时间内发挥作用。相反,如果它将被广泛使用,那么正确的 制作是值得的。成为一个理性的设计师是非常困难的,而且我们可能永远不能实 现它。在我们尝试遵循这个过程的过程中,我们经常发现我们继承了一个由于未 知原因而做出的设计决策的地方。例如我们想要使用的等式中常量的值。当我们 要求推导常量时,我们发现它不存在或推导无效。当我们进一步按下时,我们被 告知该决定是“因为它有效”。在这种情况下,设计师可以打开一个研究项目,找 出它的工作原理,或者只是“继续使用它”。那些为我们工作付钱的人已经使用 “GOWI”这样的标准回答去解决许多此类问题,并且我们并不认为真正的工作会有 所不同。然而“因为它们起作用”,所以无论我们做出哪些决定,我们都会对我们 的决定记录诚实的理由,而不是误导未来的维护者认为我们对我们所做的事情有 深刻的哲学理由。