本系列文章将分为三篇来介绍设计文档的可读性:
3. 设计文档的最佳实践
如果你不能写清楚,你可能没有你想象的那么聪明。
——小库尔特·冯内古特
措辞
使用词语要微妙、精确、直截了当。
1)正确使用技术术语。
2) 省略程度补语
3) 使用数据
4)避免写八股文章
造句
1)使用句子,而不是具有多个谓词的复杂句子。
“系统方法问题如下:如何在系统中安排各个对象类,使得较高的对象类总是可以从较低的对象类构造出来,也就是说,后者可以简化为前者。为了要解决这个问题,就必须从各种对象的相互还原性出发来研究,因此,为了达到目的,我们应该根据所涉及对象领域的实际科学知识,找到每个待研究对象的基本事实。存在的充分和必要条件。我们可以通过要求实际科学给出基本事实的(确定且恒定的)表述来以这种方式进行。”
——摘自:【德国】鲁道夫·卡尔纳普。 《世界的逻辑建构》。
2)简单的表达,去掉无意义的修饰,去掉试图缓和语气的句型。
示例:“我们可以看到NewDB在一定程度上可以满足我们对事务支持的需求。”
——>更改后:“NewDB支持事务”。
示例:“MR 提交信息作为读者在查看变更历史记录时听到的第一个信息,其重要性是不言而喻的。”
——> 变更后:“读者查看变更历史时,首先会关注MR提交信息。”
本段讨论另一个问题,即……
例:【是的,重要的大臣】Humphrey 教你如何将 Yes 扩展成段落()
3)保持语气平静。 避免过于口语化。
4)描述要准确
段落
段落应尽可能短。 一般来说,一个段落中不超过8个完整的短语。
每个段落都有一个且只有一个明确的主题。 每个段落都应该以一个主题句开头软件详细设计编写目的,以便读者能够快速理解该段落的主要思想。 段落中的每句话都应与主题密切相关; 否则,应另起一段,或删除。
注意段落的流畅性。 段落句子应源自读者已经熟悉的概念,并在句子末尾放置新的内容。 这样,读者就能更连贯地理解。
使用列表
使用Bulletpoint来标记无序列表,并使用数字序列号来阐明顺序。
如何正确使用列表,本文不会详细阐述,会在后续文章中介绍(如果有后续),也可以参考文末的参考资料。
结构
1)使用模板
使用模板可以作为思维辅助,同时也提供了比较完整、规范的结构。
文末提供了设计文档模板供参考。
2)使用图表
一张图片胜过千言万语。 合理使用图表可以大大降低用户的理解成本。
图表的制作本文不会详细阐述,会在后续文章中介绍(如果有后续),也可以参考文末的参考资料。
3)使用标题
(图片来源于网络)
空间
设计文档不宜太长。 一份文档中堆积太多内容可能会让读者失去兴趣。
对于小型项目,大约 10 页(约 5000 字)是合适的厚度。 当超过这个宽度时,可以考虑将问题拆分为子问题分别编译设计文档,并将子设计文档链接到总体设计文档中。
要逐步改进小问题,请考虑使用单寻呼机。 一般来说,此类文档的范围较小,解决问题也比较简单,目标用户群仅限于已经对问题有充分了解的内部成员。 此时,可以省略背景等内容,仅采用目标计划两段论证的结构。
排版
使用一致的字体。 用户没有意识到不同的字体意味着不同的东西,他们只是感到困惑。
谷歌雅黑是安全的选择。
不要使用不同的颜色来区分内容。 不要在文本中使用超过三种颜色。 您可以将您的标志性颜色用于标题和分级标题,同时使用白色作为正文。
时间表:设计文档模板
设计文件没有公式。 即便如此,笔者这里还是提供了一个设计文档模板供菜鸟们参考。 您可以使用此文档模板作为思考的基础。 一般不需要每部分都详细填写,不相关的内容可以直接跳过。
7.1 目标
“我们想解决什么问题?”
用几句话解释一下设计文档的关键用途,让读者一眼就知道自己对设计文档是否感兴趣。
例如:“这篇文章描述了 Spanner 的阁楼设计”
然后,使用要点来描述设计试图实现的重要目标,例如:
非目标也很重要。
非目标并不是对纯粹目标的否定,也不是其他与解决问题无关的目标,而是一些读者可能意想不到、可以作为目标但又不可以的目标软件详细设计编写目的,比如:
如果可能的话,解释一下是什么因素使它成为非目标。 喜欢:
设计不是试图达到完美,而是试图达到平衡。 明确地说明什么是目标、什么不是目标,有助于帮助读者理解下面设计决策的合理性,也有助于在以后迭代设计时检测原来的假设是否仍然成立。
7.2 背景
“我们为什么要解决这个问题?”
向设计文档的目标受众提供理解详细设计所需的背景信息。
按读者提供上下文。 请参阅上面关于目标受众的圆圈。
设计文档应该是“独立的”,即它应该为读者提供足够的背景知识来理解设计,而无需进一步参考。
保持简单,一般几段就可以了,每段简单介绍一下就够了。 如果需要向读者提供更多信息,最好只提供链接。
谨防知识的诅咒。 知识的诅咒(Curse of Knowledge)是一种认知错误(%E8%AA%8D%E7%9F%A5%E5%81%8F%E5%B7%AE),这意味着人们在与他人交流时,下意识地自信地假设对方具有理解交流主题所需的背景知识。
背景一般可以包括:
不要在后台写下你的设计或问题的解决方案。
7.3 总体设计
“我们如何解决这个问题?”
在一页上描述高级设计。
描述系统的主要组件,以及一些关键的设计决策。 应该解释系统的模块和决策如何满足上面列出的目标。
本设计文件的评审者应该能够理解您的设计思路,并根据整体设计进行评估。 对于不参与该项目的新腾讯工程师来说,该描述应该是可以理解的。
建议使用系统图(%E7%B3%BB%E7%BB%9F%E5%85%B3%E7%B3%BB%E5%9B%BE)来描述设计。 它可以让读者清楚地理解文中的新系统与已经熟悉的系统之间的关系。 它还可以包含新系统内部配置文件的构建块。
注意:不要只放图片而不做任何说明,请按照上一节的要求用文字描述设计思想。
这里不描述细节,放在下一章; 这里不描述背景,放在前面的章节里。
7.4 详细设计
在本节中,不仅介绍了设计方案的细节,还介绍了主要设计思想以及形成最终方案过程中的权衡。 本节的结构和内容可以根据设计对象(系统、API、流程等)自由确定,并且可以定义一些小节以更好地组织内容,并以简洁明了的结构解释整个设计越多越好。
不要在实现细节中写太多内容。 正如我们不建议仅添加注释来解释代码的作用一样,我们也不建议使用仅准确描述您想要如何实现系统的设计文档。 不然为什么不直接实现呢?
以下内容可能是实现细节反例,不适合在设计文档中讨论:
一般可以包含以下内容(注意小节的命名可以改为能够清晰突出内容的标题):
1)各子模块的设计
解释一些复杂模块的内部细节,可能会包含一些模块图和流程图来帮助读者理解。 可以用时序图来解读,比如各个子模块中某个调用的运行过程。
每个子模块都需要解释其存在的意义。 除非必要,否则不要添加模块。
如果没有特殊情况(例如设计文档是描述和实现一个核心算法),不要在系统设计中添加代码或伪代码。
2)API套接字
如果正在设计的系统公开 API 套接字,则简要描述 API 将帮助读者理解系统的边界。
防止将整个套接字复制粘贴到文档中,因为特定编程语言中的套接字通常包含一些可以快速更改的语言详细信息。 重点表达与设计最相关的 API 套接字的主要部分。
3)储存
引入系统相关的存储设计。 如果答案不明显,本节应回答以下问题:
系统的数据/存储要求是什么?
根据前面的事实,数据库应该如何选择呢?
数据的可视化和数据之间关系的描述至关重要。 可以使用ER(%E6%A8%A1%E5%9E%8B)、图(%E6%A8%A1%E5%9E%8B%E6%A8%A1%E5%9E%8B)的形式( EntityRelationship)解释数据关系。
回答上述问题时,请提供尽可能多的数据,作为答案或辅助。 不要回答“数据规模大,读写频繁”,而是回答“预计数据规模300T,读取3M天,写入0.3M天,峰值QPS 300”。 这样可以为下一步具体的数据库建模提供详细的决策依据,让读者信服。
注:尺寸选择中还应包括可能产生重大影响的非技术激励措施,例如成本。
防止将所有数据定义(数据模式)复制粘贴到文档中,因为数据模式更多的是实现细节。
7.5 其他解决方案
“我们为什么不这样解决这个问题呢?”
在介绍最终方案之后,可以有一个部分来介绍设计过程中考虑过的其他设计方案(AlternativesConsidered),它们各自的异同和权衡,以及选择最终方案的原因。 一般有经验的读者(尤其是该方案的评审者)自然会想到一些其他的设计方案。 如果这里的介绍描述了不选择该方案的原因,就会妨碍读者带着疑问阅读整个设计然后寻找。 问作者。 这一部分可以体现设计的严谨性和全面性。