如何写一份高可读性的软件工程设计文档 作者:marinewu,腾讯 PCG 客户端开发工程师 导语:设计文档是软件工程设计中的重要组成部分。本文根据 Google 及其它公司编写设计文档的经验,并结合实际应用加以完善,系统地介绍设计文档的目的、结构及参考模板,希望推动设计文档在团队中落地,传承并沉淀经验,构建良好的文化氛围。 1、设计文档是什么? 设计文档是软件工程设计中的重要组成部分,是对一个技术问题的解决方案的系统性描述。设计文档的目的,是阐明设计的总体思想和设计中考虑的权衡点。 作为一名软件工程师,我们的工作本质不仅仅是编写程序代码,而是解决真正的问题。因此,相比最终的程序代码,文字形式的设计文档,在早期能够更加简明扼要地传达信息,便于让读者理解问题,找到解决方案。 除了作为系统设计的最初体现,设计文档在软件工程的开发周期中起到下面重要作用: 通过设计文档,我们可以:在可以低成本迭代的时候,尽早发现设计中的问题 – 设计左移,代价左移,快速失败(fail fast)在团队中对设计达成一致 – 设计的本质是取舍(tradeoff)。几乎所有的架构设计决策都会被挑战,原因之一是:读者并非对所有的取舍都知晓,且与作者达成共识。在设计文档中清晰地列出取舍,有利于帮助读者了解(并认可)你的决策思路,减少被挑战的可能。将资深工程师的经验和思想扩展到整个团队,帮助团队成长 – 作为作者,可以供资浅工程师学习 – 作为读者,可以审核资浅工程师的设计并提供建议形成团队软件设计的一致方式,沉淀团队/公司技术积累 – 企业的生命力在于知识价值的积累 2、什么时候需要设计文档? 本身撰写设计文档是需要编写成本的。 如果问题的解决方案非常清晰,没有明确的取舍,设计文档中基本都是实现描述,则应该省略设计文档而直接实现。换言之,如果编写设计文档的时间主要消耗在“写”而不是在“思考”上,则这个设计文档可省略。 当你考虑编写一个设计文档时,想一想以下这几点:软件的规模是否较大,值得付出额外的编写评审设计文档的时间来降低失败的风险?高级工程师无法确保 CR 每一份代码,让他们参与设计评审是否回报更高?软件设计决策是模糊的,甚至有争议。有必要围绕设计文档在组织上达成共识?是否需要通过设计文档强调项目交叉问题,如隐私性(Privacy)、安全性(Security)、日志记录?是否有必要写一份文档来对有关遗留系统的设计问题提供高层次的分析? 如果以上的问题的答案为“是”,那么设计文档可能是开始你的下一个软件项目的绝佳方法。 3、设计文档要怎么写? 在考虑通过用设计文档解决问题,开始着手准备设计文档前,需要厘清设计文档易混淆的三个概念,它们也是创作设计文档的根基。一旦出现偏差,我们认真撰写的文档很有可能完全不可用,在纠正偏差时也会出现大量工作返工,造成资源的浪费。所以,撰写设计文档前需要搞清楚这些前提! 3.1 撰写设计文档的三个前提 前提一:设计文档的读写比最高 实现代码、系统接口、设计文档,读写比(内容被所有人阅读花费的时间:内容写作花费的时间)是逐步上升的。通常,设计文档供阅读读的时间往往远多于写的时间。因此,编写设计文档时就更多考虑读者的体验而非作者的体验。为提升设计可读性的时间非常值得投资。 前提二:设计文档不是文学写作 设计文档的目的是为了沟通设计,而不是为了自我表达。把精力放在如何清晰、简洁地表达,而非放在文采上 前提三:设计文档为谁而写 首先先了解你的读者是谁?在良好的文档分享文化下,读者不应该只是你的 TL 以及该设计文档的实施者,你的设计文档实际读者的范围往往大得多。在不确定的时候,经验做法是,假设的读者群体为:公司内部的、有一定工程经验的、但对该系统的上下文只有初步了解的软件工程师。 通常,设计文档的范围越大,假定的受众群也会更大。这意味着受众对目标系统的平均了解程度更低,也就意味着设计文档往往需要:更加详细的背景介绍更少使用内部术语或缩写更多阐述设计思路、取舍,更少解释具体实现细节 其次,考虑读者喜欢如何阅读?大部分读者不会逐字逐句阅读你的设计文档。大家都很忙。读者通常只会扫描大体结构,然后阅读(或者跳读)自己感兴趣的部分。 读者喜欢“故事”。将内容以故事的结构呈现最容易被接受,即使我们并不是需要讲述一个传统的打怪升级的故事。虽然故事内容各有不同,但大部分故事都遵循一些基本的范式。例如,约瑟夫·坎伯 总结提出全世界大部分神话故事都符合“ 英雄之旅 ”– “启程、启蒙、归程”三幕 — 这个模式。 对于设计文档/科技论文写作,通用安全的选择是 Writing Science 所介绍的 OCAR 故事结构。Opening:开场,背景介绍Challenge:挑战,所要解决的问题Action:行动,执行的实验/设计/…Resolution:结果 设计文档通常遵循特定的组织结构,我们可以将每一个结构对应到 OCAR 的不同部分,以此讲述故事。 最后,辩证看待设计文档可读性。设计文档可读性 vs. 代码可读性都称作可读性,两者有些共通之处:文档着重强调的内容应该是并非显而易见的事项:设计文档代码文档说明背景说明上下文强调 Why/权衡/其它方案强调 Why注意事项注意事项代码可以清晰表达的内容不需要文档代码可以清晰表达的内容不需要文档没有绝对的正确答案:没有完美的代码,也没有完美的设计文档。 – 不同的读者对可读性的理解有细微的不同。 可读性是主观的。在实践中,我们追求让更多(而非所有)读者更顺畅地阅读设计文档。 – 不要为完美主义付出过重代码。平衡可读性与时间成本。我们的目标是有意识地提高文档写作/代码水平。高质量的写作是一种习惯。提高水平的方法有: – 多读他人优秀的设计文档。 – 评审(Design doc review/Code review)有益。 – 设计文档评审往往主要系统设计合理性,但是可读性方面的评审也有必要。 多写作、多修改、多重写。 3.2 撰写设计文档的三个前提 在搞清楚设计文档撰写的三个前提后,就会进入文档的编写阶段。设计文档是非正式的文档,因此他们的内容不会遵循严格的准则,一个首要原则是,针对项目的具体情况可以用相对合理的方式来编写。尽管如此,笔者也参考文献并结合自身经验给出一些建议。 写作风格的三要素 设计文档的写作也是技术写作(Technical Writing),因此同样强调以下三要素:清晰简洁优雅 设计文档的五个要点 系统设计及编写设计文档时需要注意的 5 个要点。 1. 任何架构问题都是取舍。 在软件设计中,没有任何一个维度有绝对意义上的优劣。 每一个设计决定都需要考量很多相违背的因素。例如,可扩展性和效率相背; 长期效率和短期收益相背;规模化提升了效率,但降低了灵活性。“高内聚低耦合” 便于迭代,但是会增加短期的开发成本。 NoSQL 比 SQL 性能高,但代价是功能的大幅降低。 如果一个设计决策看上去没有任何的取舍,往往是因为取舍还没有被识别。在设计时应从取舍视角切入,寻找不同需求间的平衡。 2. “为什么” 比 “怎么做” 更重要。 设计所解决的问题往往是复杂而模糊的,因此,解决方案往往是不唯一的。对工程设计,方案的论证通常比方案本身更重要。 3. 考虑时间维度 做设计取舍时不能忽略时间维度,只设计某个阶段的终态。设计需要考虑以下方面:可维护性与可扩展性考虑实现路径考虑未来计划 4. 避免过度设计 设计伊始,界定问题的范围。 一个良好界定的问题是一个良好设计的必要条件。 不要迷信设计模型、设计模式、XX 驱动设计。这些是工具,而非法则。不要为了制造问题而解决问题。不要通过复杂的设计来体现工作的难度和深度: 一个困难的问题可能会有一个简单的答案。也不要过于担忧设计被迅速淘汰。保留可扩展性,但不要在未知时浪费精力扩展。 5. 总结 最重要的是要知道如何设计,知道自己在设计什么。列宁·克鲁格效应告诉我们,这未必显然。 I think test-driven design is great. I do that a lot more than I used to do. But you can test all you want and if you don’t know how to approach the problem, you’re not going to get a solution. ——Coders at Work, Peter Norvig 3.3 设计文档的最佳实践 遣词 用词要简练、准确、直白。正确使用专业术语。 – 合理地使用常见术语可以降低沟通成本。 – 不要过多使用过于小众或自创的术语。如果有必要,需要在文中 – 必要时提供对照的英文术语以方便理解。 – 避免无上下文的缩略词。省略程度副词 不管作者意图为何, “非常重要” 和 “重要” 在读者看来大同小异。使用数据 – 与其说明“该系统的性能提升明显”,不如“该系统的性能提升了 42%”更为可信,也更方便读者做出自己的判断。忌佶屈聱牙 例如上文,应改为“不要使用过于生僻的词汇,不要过度使用书面语”千万不要写文言文 造句 使用短句,不要使用多从句的复杂句式。 – 读者不是来考 GRE 的。 – 写文档也不是为了炫耀自己可以驾驭长难句。 “_系统形式问题就是下面这样一个问题:怎样把各种不同的对象种类安排在一个系统中,以使较高的对象种类总能从较低的对象种类构造出来,也就是说前者可还原为后者。为了解决这个问题,我们必须从其相互可还原性来研究各种不同的对象种类。为此目的,我们要根据所涉及的对象领域的实际科学知识为每一个要考察的对象寻找其基本事实存在的充分而必要的条件的各种可能性。对此我们可采取下面的办法来进行,即要求这门实际科学给出基本事实的一个(确实而常在的)表征_。” Excerpt From: 【德】鲁道夫·卡尔纳普. “世界的逻辑构造.”简单表达,去掉无意义的修饰,去掉试图缓和语气的从句。 – 反例:“我们可以看到, TencentDB 在一定程度上可以满足我们对事务支持的需求。” – 修改后:“TencentDB 支持事务”。 – 反例: “MR 提交信息作为读者查阅修改历史时第一时间看到的信息,其重要性不言而喻。” – 修改后:“读者查阅修改历史时会首先 MR 提交信息。” – 本段讨论另一个问题,即…… 语气要冷静。避免过于口语化。 – 不要加顺口溜 – 不要使用语气词 – 不要使用叹号! 如果希望强调,使用粗体或者斜体!也可以使用分级标题! 准确。描述客观事实,避免加入主观情绪。 段落 段落应该尽量短。通常,一个段落不要超过 8 个完整的句子。每个段落有且仅有一个清晰的主题。每个段落开头应该是主题句,方便读者快速了解段落大意。段落中的每一句话应该与主题紧密相关; 否则,它应该另起段落,或者应该删掉。 注意段落的流动。段落句子应该始于一个读者已经熟悉的概念,将新的内容放在句子结尾。这样,读者可以更连贯地理解。 使用列表 使用 Bullet point 标明无顺序的列表,使用数字序号明确前后顺序。如何正确使用列表不在本文详细展开,会在后续文章介绍,也可参见文末的参考文献。 结构 使用模板:使用模板可以作为思考辅助,同时也提供了相对较完整且规范的结构。文末提供了一份设计文档模板以供参考。使用图表:一图胜千言。合理地使用图表可以极大地降低用户的理解成本。使用标题:标题要分级、要简短清晰 篇幅 设计文档不要过长。太多内容堆积在一个文档中会让读者丧失兴趣。 对于一个大型项目来说,10 页(~5000 字)左右是一个合适的长度。当超过这个长度时,可以考虑将问题拆分成子问题分别编写设计文档,并在总体设计文档中链接子设计文档。 对于小问题做增量的改进,考虑使用单页文档(one-pager)。通常这类文档的范围较小,解决问题较简单,目标用户群体仅限于对问题已经有充分了解的内部成员。这时,可以省略背景等内容,而仅使用 目标 — 方案 两段式论证的结构。 排版 使用统一的字体。 用户不会意识到不同的字体代表不同的含义,只会感受到混乱。微软雅黑是安全选择。 不要使用不同颜色来区分内容。不要在文中使用超过三种颜色。 可以在标题及分级标题使用标志性的颜色,同时正文使用黑色。 附录:设计文档模板 设计文档没有定式。即使如此,笔者参考谷歌设计文档的结构和格式,并结合实际工作经验加以完善。在此提供一个可供新手参考的设计文档模版,您可以使用此文档模板作为思考的基础。通常,无须事无巨细地填写每一部分,不相关的内容直接略过即可。 目标 “我们要解决什么问题?” 用几句话说明该设计文档的关键目的,让读者能够一眼得知自己是否对该设计文档感兴趣。 如:“本文描述 Spanner 的顶层设计” 继而,使用 Bullet Points 描述该设计试图达到的重要目标,如:可扩展性多版本全球分布同步复制 非目标也可能很重要。非目标并非单纯目标的否定形式,也不是与解决问题无关的其它目标,而是一些可能是读者非预期的、本可作为目标但并没有的目标,如:高可用性高可靠性 如果可能,解释是基于哪些方面的考虑将之作为非目标。如:可维护性: 本服务只是过渡方案,预计寿命三个月,待 XX 上线运行后即可下线 设计不是试图达到完美,而是试图达到平衡。 显式地声明哪些是目标,哪些是非目标,有助于帮助读者理解下文中设计决策的合理性,同时也有助于日后迭代设计时,检查最初的假设是否仍然成立。 背景 “我们为什么要解决这个问题?” 为设计文档的目标读者提供理解详细设计所需的背景信息。按读者范围来提供背景。见上文关于目标读者的圈定。设计文档应该是“自足的”(self-contained),即应该为读者提供足够的背景知识,使其无需进一步的查阅资料即可理解后文的设计。保持简洁,通常以几段为宜,每段简要介绍即可。如果需要向读者提供进一步的信息,最好只提供链接。警惕知识的诅咒(知识的诅咒(Curse of knowledge)是一种认知偏差,指人在与他人交流的时候,下意识地假设对方拥有理解交流主题所需要的背景知识) 背景通常可以包括:需求动机以及可能的例子。 如,“(tRPC) 微服务模式正在公司内变得流行,但是缺少一个通用的、封装了常用内部工具及服务接口的微服务框架”。 – 这是放置需求文档的链接的好地方。此前的版本以及它们的问题。 如,“(tRPC) Taf 是之前的应用框架, 有以下特点,…………, 但是有以下局限性及历史遗留问题”。其它已有方案, 如公司内其它方案或开源方案, “tRPC v.s. gRPC v.s. Arvo”相关的项目,如 “tRPC 框架中可能会对接的其它 PCG 系统” 不要在背景中写你的设计,或对问题的解决思路。 总体设计 “我们如何解决这个问题?” 用一页描述高层设计。说明系统的主要组成部分,以及一些关键设计决策。应该说明该系统的模块和决策如何满足前文所列出的目标。 本设计文档的评审人应该能够根据该总体设计理解你的设计思路并做出评价。描述应该对一个新加入的、不在该项目工作的腾讯工程师而言是可以理解的。 推荐使用系统关系图描述设计。它可以使读者清晰地了解文中的新系统和已经熟悉的系统间的关系。它也可以包含新系统内部概要的组成模块。 注意:不要只放一个图而不做任何说明,请根据上面小节的要求用文字描述设计思想。


2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/68987.html