1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
|
理性设计过程
============================================================
.. 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. <https://link.springer.com/content/pdf/10.1007%2F3-540-15199-0_6.pdf>`_
.. |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 - 徐闰钞 OK
-----------------------------------------------
(所有可以被归类为“自顶向下”的方法都是我们希望有一种合理又系统的软件设计方法的结果。)
本文既带来坏消息,也带来好消息。坏消息是,在我们看来,我们永远找不到哲
学家之石。 我们永远找不到一个能让我们以完美地理性去设计软件的过程。好
消息是我们可以伪造它。 我们向别人展示我们的系统, 就像理性设计师那样。
进一步的好消息是这样做是值得的。
II. 为什么软件设计“过程”总是理想化?
`````````````````````````````````````````````````````````````
实际上软件项目永远不会按照上面的建议(像从公理中推出定理那样,从需求中
获得程序)进行。 部分原因如下:
1. 大多数情况下,委托构建软件系统的人并不能确切地知道他想要什么,也无
法告诉我们他确实想要的东西(说不清楚)。
2. 即使我们知道了所有需求,也还需要知道很多其他事情来设计软件。 许多细
节只有在我们开始实施时才会浮出。 期间我们学到的东西会使我们原先的设
计失效,我们必须回溯。
3. 即使没有2的困难,经验表明,人类无法完全一下子理解那么多细节。 为了
设计和建立正确的系统,我们必须考虑所有细节。 设计软件的过程就是试图
分离各个关注点的过程。 我们在每个关注点上工作,因其信息量可管理。
然而,在我们达到可管理的信息量前,我们必然会犯错误。
4. 即使我们能够掌握所有需要的细节,稍大点的项目都会由于外部原因而发生
变化。 其中一些变化可能会使以前的设计决定失效。
Page 4 - 吴贞娴 OK
-------------------------------------------------------------------
5. 用人就会有人为错误。无论我们的决策过程多么理性,无论我们的相关事实
收集和组织多么好,我们都将会犯错。
6. 自己发明的、从相关项目获得的、课上听到的先入为主的设计思想经常干扰
我们。 有时候我们会为尝试一个喜欢的想法而去做一个项目。 这种想法也
许不是经由理性过程从需求中产生;而是自发地由其他来源产生。
7. 由于经济因素,我们常被鼓励去使用其他项目开发的软件。在其他情况下,
我们也许会被鼓励与另一个正在进行的项目共享我们的软件。 这会导致最后
得到的软件可能不是任一个项目的理想软件,即不是仅根据需求开发的软件,
虽然这样的软件也能用且开发省力。
出于这些原因,软件设计人员以理性、无错误的方式从需求中获得设计这样的情
形是不现实的。我们相信从来没有系统是以这种方式开发,或许将来也不会有。
即使是教科书和论文中各种小程序开发也不是真实的,是经过了修改和润色了的,
直到作者展示了他希望自己曾经做的,而非实际发生的情况。
III . 尽管如此, 为什么描述理性理想化过程是有用的呢?
````````````````````````````````````````````````````````````````````````````````
上文所述之困难甚为明显,认真的思考者都知道,其中诚实者也承认如此。 尽
管如此,我们还是看到软件设计过程为主题的会议、软件设计方法论的工作组和
软件设计课程市场(以声称用逻辑方法来设计软件而获利丰厚)。这些人想要达
到什么目的呢?
Page 5 - 余慧 OK
---------------------------------------------------------------
(与吴贞娴翻译的最后一段同: 上文所提及的内容,很明显为每个深思熟虑过
的人所知、为坦诚的人所承认。尽管如此,我们仍旧能看到以软件设计过程为主
题的会议、研究软件设计方法论的工作小组,以及为了丰厚市场利益扬言能描述
软件设计逻辑方法的课程。这些人想达到什么样的目的?)
如果已确定理想过程但不能精确遵循它,我们仍然像遵循理想过程而产生文档一
样,去编写文档。 文档读者会从 **对设计的理性解释中** 受益。 这就是我们
所说的“假装理性设计过程”。
下面,我们列举假装如此的一些理由:
1. 设计师需要指导。 当承担一个大项目时,我们容易被任务的艰巨性压倒。
不能确定首先做什么。 好好理解理想过程会帮助我们知道如何进行项目。
2. 比起依靠临时决策来推动项目进行, 如果我们试着去遵循某一过程,那么我
们会更靠近理想过程、更靠近理性设计。 例如,即使我们无法知道设计一个
理想系统所需的所有事实,在编码前去寻找这些事实的努力会帮助我们更好
设计、更少返工。
3. 承担多个软件项目的机构如果拥有统一标准则会有很多优势。 会使设计审核,
以及人员、想法和软件在项目之间的转移变得更容易。 如果我们要去指定标
准过程,标准过程就应该理性的。
4. 如果我们已经定下理想过程,那么衡量项目进展就会变得容易得多。我们比
较项目目前的成果与理想过程所要求的成果, 确定落后(或领先)的地方。
Page 6 - 魏含饴 OK
--------------------------------------------------------------------------
5. 外部人员对项目进展定期审查对良好的管理不可或缺。 如果项目试图紧随
理想过程,审查就会更容易。
IV. 开发过程描述应该告诉我们什么?
``````````````````````````````````````````````````````````````````````````
我们相信开发过程描述的最有用形式是工作产品。对于过程的每一个阶段,我们
描述:
- 下一步应该做什么;
- 工作产品必须满足什么标准;
- 谁做这项工作;
- 他们工作中应使用哪些信息;
无法用工作产品描述的任何过程管理只能由会读心的人来做。 只有知道需要哪
些工作产品,以及它们必须满足的标准,我们才能审查项目并衡量进度。
V. 理性设计过程是什么?
``````````````````````````````````````````````````````````````````````````
本节我们描述我们所遵循的理性的、理想化的软件设计过程。 每个步骤
都伴随着与该步骤相关的工作产品的详细描述。
以下过程的描述既不包括测试也不包括审查。 这并不意味着我们忽视了其中的
任何一个。 本文我们正描述的是一个理想的过程;测试和审查属于实际的过程,
而不是理想的过程。 在应用本文所描述的过程时,我们包括了广泛而系统的对
每一个工作产品的审查以及对生成的可执行代码的测试。
Page 7 - 叶红霞 OK
---------------------------------------------------------------------
(在实施本文描述的过程时,我们对每一个工作产品进行了广泛而系统的审查,
并对生成的可执行代码进行了测试。)
A. 建立并记录需求
````````````````````````````````````````````````````````````````````````````````
要成为理性的设计师, 为了成功,我们必须知道我们必须做什么。 我们将其
记录在称为需求文档的工作产品中。 在我们设计之前就完成此文档,这样我们
设计时手边就拥有所有的需求。
1. 为什么需要需求文档?
- 减少设计程序时偶然地去做需求决定的可能性。
- 避免重复和不一致。 没有这个文档,许多问题会在整个开发过程中被设计者、
程序员与审核人反复问及。 这样开销很大, 且会产生不一致的回答。
- 程序员通常不熟悉程序具体的应用领域。 有一个外部可见行为的完整参考,
他们就不必去决定什么是对用户最好的。
- 是估计开发系统所需工作量与资金必要文档之一。
- 是针对人员流动的有价值的保险。 我们所获得的需求不会因为有人离开项目
而丢失。
- 为制定测试计划提供良好的基础。没有它,我们不知道测试什么。
- 在系统投入使用长时间后,需求文档可以用于为将来的需求变更定义约束条件。
Page 8 - 王如韵 OK
--------------------------------------------------------------------------
- 它可以解决争议; 我们不再需要成为应用程序专家或咨询应用程序专家。
因为通常没有组织良好的信息来源, 确定详细的需求很可能是这个过程中最困
难的部分。 理想情况下,需求文件应该由用户代表来写。 而实际上,它很可能
是要软件设计者写,然后由用户代表同意。
2. 需求文件包含什么内容?
在理想化的设计过程中,需求文件内容的定义很简单: 它应该包含编写正确软件
要知道的所有内容,不需要再多了。 当然,如果现有信息准确且组织良好,
我们可以引用它们。 书写理想需求文件的一般规则有:
- 需求文件中每句话应对所有可被接受的产品有效, 不应依赖于实现决定。
- 文件应是完整的。 如果产品符合文件中每一句话,则产品应是可以接受的。
- 在开发之前,如果信息还没有,则指出缺失的地方,而非简单地略过。
- 需求文件应该按照参考文件的结构来组织,而不是按照系统介绍来组织,因为
参考文件的形式是最有用的。 虽然写这样一份文件需要付出相当的努力,而且
比系统介绍更难于阅读,但从长远来看,它节省了人力,因为在这个阶段获得
的信息是以易于在整个项目中参考的形式记录下来的。
Page 9 - 蒋佳玲 OK
---------------------------------------------------------------------
我们通过把关注点分离( **Separation of Concerns** )到章节,来获得需求
文档的完整:
- 指定软件运行的机器。 机器不必是硬件 -- 对于一些系统,这一节可能仅仅包含语言参考手册的名字;
- 指定软件与外界通信必须使用的接口;
- 对于每个输出,指定所有情况下的值(用软件可检测到的系统状态表示);
- 对于每个输出,指定软件需要多频繁或多快速重新计算它;
- 对于每个输出,指定精确度。
- 如果要求系统易于更改,则需求文件必须包括可能发生更改的地方。 你无法设计一个系统,可以让所有东西都同样容易更改。 哪些东西最有可能更改,不应该由程序员判断。
- 需求还必须讨论由于不希望发生的事件发生了,系统无法满足需求时系统应该做什么。 大多数需求文档忽略了这些事件; 它们只讨论当一切都完美的情况,却把出现部分故障时该做什么留给程序员去决定。
我们希望大家清楚,除非定义了每一个需求,否则无法编写正确的软件。 一旦成功地指定了每一个需求,您就已经完全指定了系统的需求。
Page 10 - 应舸
----------------------------------------------------------------------------
为了确保文档的统一性和完整性,文档编写的组织过程背后必须有一个简单的数学模型。
我们的模型是由我们在实时系统上的工作所激发的,但正因为如此,它具有完全一般性。
所有系统都是实时系统。
我们假设对于实时控制系统,理想的产品不是纯数字计算机,而是由控制模拟计算机的数字计算机组成的混合计算机。
模拟计算机将输入测量的连续值转换为连续输出。当离散事件发生时,数字计算机带来模拟计算机计算功能的离散变化。
实际系统即是该混合系统的数字近似。
与其他工程领域一样,我们首先描述这个“理想”系统,然后指定允许的公差来编写我们的规范。
在我们的需求文档中,我们认为输出的地位远高于输入。如果我们得到输出值是正确的,那么没有人会介意我们甚至采用不读取输入的方法。
因此,该过程第一阶段的关键是识别所有输出。
我们需求文档的核心可以被表述为表格形式的一组数学函数。每个函数都将单个输出的值指定为与应用程序相关的外部状态变量的函数。
以这种方式生成的完整文档的一个例子,我们将在本文[9]中给出并在[8]中讨论。
.. _B:
B. 设计并记录模块结构
````````````````````````````````````````````````````````````````````````````````
除非产品很小,小到能由单个程序员来做,否则我们必须想一想如何将工作分解为任务,即模块。 此阶段应生成的文档为 **模块指南 (Module Guide)** 。 模块指南定义各模块的职责, 把我们的设计决策 (design decision) 封装在该模块。 模块里可以有子模块,也可以单独作为一个工作任务。
Page 11 - 徐焕众 OK
-----------------------------------------------------------------------
模块指南用来避免重复,避免空隙,实现 **关注点分离 (separation of concerns)** 。 最重要的, 当产品有问题时, 用来帮助维护人员找出对应的模块。 记录设计决策的文档与在维护阶段使用的文档是同一个文档。
如果我们努力地将信息隐藏 (information hiding) 或 关注点分离 (separation of concerns) 应用于大型系统,那么肯定会产生大量模块。 没有其他结构,只是简单列出模块名的指南,只对熟悉系统的人有帮助。 而我们的模块指南是树形结构的, 它将系统划分成几大模块,并以相同的方式细分每个模块,直到所有模块都非常小为止。 这种文档的例子, 参见[3]。 对这一办法及其好处的讨论,参见[15,6]。
C. 设计并记录模块接口
````````````````````````````````````````````````````````````````````````````````
高效快速的软件生产需要使程序员能独立工作。 模块指南定义了模块职责,但没有给出足够的信息使得每个人能去独立实现模块。 为此,每个模块必须指定精确的接口。 每个模块都必须有 **模块接口规范 (Module Interface Specification)** ; 规范必须正式,并提供每个模块的黑箱图片 (black box picture)。 规范由资深设计师撰写, 并由接口实现者与接口使用者一起评审。 一个模块的接口规范只需包含足够使其他模块的程序员使用该模块功能的信息, 而不需要其他信息。 接口实现者也需要 **模块接口规范** 。· 我们写的文件由两者使用。
Page 12 - 何可人 OK
------------------------------------------------------------------------------
虽然,每人负责写一个文件, 但这些文件实际上是在模块实现者、模块使用者, 对模块设计感兴趣的人(如审稿人)商议过程中产生的。 这些规范文件的主要内容有:
- 被访程序 (access program): 可被其它模块中的程序调用的程序列表。
- 被访程序的参数。
- 被访程序对彼此的影响。
- 时间约束与精度约束 (如果需要)。
- 意外事件 (undesired events) 的定义(禁止发生的事)
许多方面,模块规范类似需求文件。 但是,模块规范所使用的符号与文档结构更适合描述软件与软件的接口。 已发表的例子和解释有 [11],[2],[1],[5]。
D. 设计并记录模块内部结构
````````````````````````````````````````````````````````````````````````````````
一旦指定了模块接口, 实现可以作为独立任务去执行。 但是,开始编码之前, 我们想在模块设计文档中记录主要的设计决策。 这个文档允许我们编码前对设计有效的评审, 并向未来的维护程序员解释代码背后的意图。
在某些情况下, 模块只是被简单地分成几个子模块, 设计文件是另一个模块指南。 在这种情况下,该模块的设计过程在上面的步骤 B_ 处继续。
Page 13 - 袁世家 OK
-------------------------------------------------------------------------------
在另一些情况下,我们从描述内部数据结构开始; 还有一些情况是, 这些数据结构被子模块实现(并隐藏)。 对于每个被访程序,我们包括一个函数 [1] 或者 LD-关系 [14], 用来描述对数据结构的影响。 对于模块返回给调用者的每个数值,我们提供叫做抽象函数的数学函数,这个函数将数据结构的值映射到返回值???。 对于每个意外事件, 我们描述了怎样去检查发现它。 最后,我们还提供一个"验证", 一个拥有这些属性的程序会满足模块说明的论据???。
**继续分解设计子模块,直到每个工作任务足够小, 小到万一负责这个模块的程序员离开项目, 我们也可以承担丢弃它并重新开始的代价** 。
如果无法用易读的高级语言编程,例如,如果没有可用的编译器,就把伪代码作为文档的一部分。 写伪代码的不是最终程序员, 并让他与最终程序员负责确保两种代码一致。 这么做很有用 [7]。
E. 设计并且记录使用层级 (uses hierarchy)
````````````````````````````````````````````````````````````````````````````````
一旦知道所有的模块与它们的被访程序, 就可以设计使用层级。 为记录方便, **用一个真值矩阵表示使用层级** ,当且仅当程序A的正确性取决于程序B的正确性, 矩阵的(A,B)位置为真。 使用层级定义了一组子集组成的集合, 这个集合可以由删除整个程序并且不需要重写任何程序获得。 使用层级对于分阶段交付, 软失败(fail-soft)系统,和开发程序家族很有用。
(蓝珲的理解: 文中提到的程序, 容易引起混淆, 其实就是模块。 真值矩阵其实描述了模块之间的依赖关系。 例如, 有1,2,3,4四个模块, 3依赖1, 1依赖2, 2依赖4。 {4}, {2,4}, {1, 2, 4}, {3,1,2,4} 这些子集都可以组成独立程序。)
Page 14 - 陈肖飞 OK
------------------------------------------------------------------------------
F. 编写程序
````````````````````````````````````````````````````````````````````````````````
在设计和文档编制完成后,我们就可以编写代码了。我们发现这件事进展的迅速
而顺利。我们认为,代码注释不应该包含文档中已经有的内容。否则,系统维护
会更加昂贵,同时增加了代码与文档不一致的可能性。(因为会出现注释改了,
而忘了更新对应位置的文档。或者文档改了,而忘了更新对应位置的注释。)
VI.文档在这一过程中的作用是什么?
```````````````````````````````````````````````````````````````````````````````
A. 当前的文档有什么问题? 为什么它不便使用? 为什么它晦涩难懂?
很明显,文档在我们描述的设计过程中扮演着重要角色。大多数程序员认为文档
是一种必要的累赘,是在事后才做的,只是因为有些官僚需要文档。但我们认为,
在发布之前都没有使用过的文档一定是糟糕的文档。
多数文档不完整不准确,但这并不是主要的问题。如果是的话,只要简单地添加
或者纠正信息就可以纠正它们。事实上,有一些根本的文档组织结构问题才是导
致不完整和不准确的原因,而且这难以修复:
- 糟糕的组织。今天的大多数文档可以被描述为“意识流”和“执行流”。意识流写
作将信息放在作者写作的时候突然想到的那个点上。执行流描述了系统在运行
时发生的事情的顺序。
Page 15 - 陈俊蕾 OK
----------------------------------------------------------------------------
文档中多余的注解是没必要的,且会使系统维护变得更加昂贵。 除此之外,还
会增加代码与原文档不符的可能性。
VI. 文件在此过程中充当什么样的角色?
``````````````````````````````````````````````````````````````````````````````
现在的文档到底哪儿有问题? 为何难用? 为何没人读?
显然,设计过程中文档扮演着一个重要的角色。是祸躲不过,许多程序员认为文
档是“事后考虑”之物,只是官僚的要求而作。我们认为那些在发表前从未被使用
的文档都是很差的文档。
大多数文档都不完整、不精确,但这不是主要问题。可以通过添加或修改信息进
行改正。 事实上是引起文档不完整与不正确的内在结构组织问题不容易修复。
- 很差的文档组织结构。 现今的文档,可分为 **意识流** 与 **执行流** 。
意识流写作把即兴想法写在作者正在写的地方。执行流写作按照系统运行时事
件发生的顺序去写。 这两种文档风格的问题是:除作者本人,其他人不容易
找到他们想要的信息。 因此难以判定某信息是否丢失,难以修改错误信息。
软件发生变化时,找不到所有文档对应的位置去修改。
Page 16 - 王海榕 OK
------------------------------------------------------------------------------
如何避免这些问题?
理想设计过程中, 文档既满足了开发人员需求, 也满足了维护人员的需求。上
面提到的每个文件都记录了设计决策,并在剩余的设计中作为参考文件使用。
这些文件也提供了软件维护人员所需要的信息。由于这些文件在整个软件开发过
程中被用作参考手册,因此它们将是成熟的,并且已经准备好在以后的工作中被
用到。 这些文件总是及时更新的。 在我们设计过程中, 文档不是事后才想到
的产品; 而是被看作是项目的主要产品之一。 一些检查可用来增加其完整性和
一致性。
这种产生文档的方法,其主要优点是可以减轻 **神话的人月效应 (The
Mythical Man Month effect)** [4]。 当新人加入时, 不需要依赖老员工来提
供项目信息。 因为新人拥有一个最新的且理性的文件集。
为避免“意识流 (stream of consciousness)”和“执行流 (stream of
execution)”, 我们花大力气来设计每个文件的结构。 通过声明文件必须回答
的问题, 我们来定义文件; 我们将这一原则贯彻至文件的每小节。 在文件中,
我们试图为每一个必须要包括的事实找一个位置,并确保只有一个这样的位置存
在。 只有在确定了文件的结构之后,我们才开始写。 如果我们要写许多特定类
型的文件,我们就为它们编写并发布一个标准结构[5]。 我们所有的文件都是按
照与指导软件设计相同的原则来设计的,即关注点分离。 我们要开发的系统的
每个方面都只在一节中描述, 且在该节不含其他内容。 当我们的文件被审查时,
我们会审查它们是否符合文档规则以及是否准确。
Page 17.a - 周佳威
--------------------------------------------------------------------------------
这样生成的文档既不简单也不轻松,但也不枯燥。我们利用表格、公式和形式符
号来增加信息的密度。我们的组织规则防止了信息重复,其结果是文档化,必须
非常认真地阅读,但回报读者详细和准确的信息。为了避免传统文档中出现混淆
和不一致的术语,我们使用了特殊括号和类型化字典系统。我们必须定义的许多
术语中的每一个都包含在一对显示其类型的括号符号中。对于每个这样的类型,
我们都有一个只包含该类型定义的字典。虽然刚开始阅读的读者会发现!+terms+l、
%terms%、#terms#等符号的存在,但是令人不安的是,像我们这样文档的普通用
户会发现括号中隐含的类型信息使文档更容易阅读。使用由类型构成的字典使我
们不太可能为同一个概念定义两个术语,或者为同一个术语赋予两个含义,同时
特殊的括号符号使对已介绍但未定义或已定义但从未使用过的术语进行机械检查
变得很容易。现在,我们如何伪造理想过程?
上面描述了我们希望遵循的理想流程以及在此流程中生成的文档。我们通过生成
文档来伪造这个过程,如果我们以理想的方式做事,就会生成这些文档。我们试
图按我们所描述的顺序制作这些文件。如果我们不能得到一条信息,我们就会注
意到在文档的一部分中,信息应该去哪里并继续设计,就好像该信息会按照预期
发生变化一样。如果发现错误,我们将更改它们,并在随后的文档中进行相应的
更正。我们将文档作为设计的媒介,在所有级别的设计决策都被批准纳入文档之
前,不会考虑任何设计决策。无论我们在途中遇到多少困难,最终的文档都将更
容易理解和适应。我们没有展示事情实际发生的方式,我们展示的是我们希望事
情发生的方式和事情的方式。
Page 18 - 方梓安 OK
-----------------------------------------------------------------------------------
vii. 如何假装理想的过程?
上文描述了我们希望遵循的理想过程,以及这一过程所产生的文档。 我们通过
产生文档来假装这个过程。 我们用上文描述的顺序去试着产生一系列文件。 如
果某部分信息缺失,我们在文档相应位置注明此处信息缺失,然后着手设计(设
计时假定该部分信息会改变)。 如果我们发现错误,就会更改错误,并更改后
续文件的错误。 将文档作为设计的媒介。在设计决定在所有层面都获准并纳入
文档前,该设计决定无效。不管中途我们如何经常犯错,最终的文档都会准确、
更容易理解。 我们不展示事情发生的方式,我们展示我们希望它们发生的方式,
以及事情本身。
甚至数学,许多人认为最理性的学科,也遵循上述过程。 数学家不断地改进他
们的初始证明,通常最后的证明与初始证明很不一样。 初始证明往往来自痛苦
的发现之旅。 有了初始证明后, 数学家的理解慢慢加深, 会去简化证明。最
终, 数学家找到了一个更简单的证明,使定理的真实性更明显。 更简单的定
理证明出版了,因为读者对定理蕴含的真理比对定理的发现过程更感兴趣。
我们相信此种类比同样适用于软件。 阅读软件文档是为理解这个程序,而不是
再现程序产生过程。 我们提供读者需要的合理化的文档。
我们的文档在一个重要的方面与理想化的文档不同。 我们 **记录所有我们考虑
过与排除的备选方案** , 包括记录文档的早期版本的决定。 对于每个备选方
案,我们解释为什么当初会考虑它或为什么会最后排除它。 这样不管多长时间
以后,我们(或维护者)有同样的问题就能从这些记录中找到答案。
Page 20 - 刘莉莉
----------------------------------------------------------------------------------
从这个过程得到回报的例证是由我们几年前写的软件需求文档提供的,其作为理
想过程演示的一部分[9]。通常,人们认为需求文档在编码开始之前就生成了,
并且不会再使用它。然而,事实证明并非如此。那些满足我们的要求文件的软件,
它的原始版本仍在进行修订。每次更改后就必须测试软件的组织,都会广泛使用
我们的文档来选择他们所做的测试。当需要进行新的更改时,需求文档用于描述
那些必须更改的内容和不能更改的内容。在软件投入使用后,该过程中生成的第
一份文件一直被使用了很多年。可以明确的是,如果一个文档是经过精心制作的,
那么它将在很长一段时间内发挥作用。相反,如果它将被广泛使用,那么正确的
制作是值得的。成为一个理性的设计师是非常困难的,而且我们可能永远不能实
现它。在我们尝试遵循这个过程的过程中,我们经常发现我们继承了一个由于未
知原因而做出的设计决策的地方。例如我们想要使用的等式中常量的值。当我们
要求推导常量时,我们发现它不存在或推导无效。当我们进一步按下时,我们被
告知该决定是“因为它有效”。在这种情况下,设计师可以打开一个研究项目,找
出它的工作原理,或者只是“继续使用它”。那些为我们工作付钱的人已经使用
“GOWI”这样的标准回答去解决许多此类问题,并且我们并不认为真正的工作会有
所不同。然而“因为它们起作用”,所以无论我们做出哪些决定,我们都会对我们
的决定记录诚实的理由,而不是误导未来的维护者认为我们对我们所做的事情有
深刻的哲学理由。
|