如何写设计文档

1、背景

随着公司的不断发展,业务对技术的要求也比原来更高,项目的数量越来越多、团队人数也越来越多、项目的质量要求也越来越高。随着项目的不断立项,对项目在前期的设计要求也逐步确立下来。于是,项目中技术设计文档的设计也需要留存下来。

目前,技术项目目前没有统一的规范,当前技术设计的文档也层次不齐。另外一方面,更为重要,我们目前的项目设计到底是一个什么样的标准?是否经得起考验?

如果你要写一个技术技术设计文档,本文将介绍如何写好。

1.1、为什么要写技术设计

如同解释为什么要做计划一样,我们写技术设计文档,主要有如下目的:

1、便于沟通。所谓“一图胜前言”,有文档的存在,将帮助大家了解要解决的问题、实现的方法、当前方案的局限、未来的扩展和升级、维护和运维等,用途上可以用于方案review、技术“遗产”等

2、技术的延续与传承。技术的资料帮助后续开发者可以延续之前的技术,而不是在不清楚的情况下,进行重构

3、完善思考。帮助负责人设计出技术方案更合理、有效,降低项目失败的概率

1.2、本文适合哪些人阅读

项目负责人、架构师、工程师,以及其他感兴趣的同学。

2、开始设计

编写技术设计文档,如同整体思路的完整表达一样,需要有一定的逻辑性(思路),这就是我们所谓的轮廓。

2.1、文档结构

背景介绍 → 设计思路 → 详细方案 → 补充材料

换句话说,上面的逻辑可以描述为:

  1. 为什么要做这个技术方案
  2. 我们打算用什么方案做
  3. 这个方案的实现细节是什么样子
  4. 我参考了哪些资料(帮助背书)

2.1.1、万事开始:背景介绍

背景介绍主要描述了,为什么要做这个项目。一般这部分可以分为三部分:

1、背景,重点描述“为什么要做”。一般是两种情况:解决问题和获取收益。(当然,有种情况是,产品经理或者老板要这个功能,属于业务需求,这个一般也算在收益类),比如:

最近一个月出现了7起因网络原因导致的投诉,目前已有的方案处理时间太长(4-24)小时,导致客服与技术这边非常被动。因此,我们发起这个项目,来解决类似的问题。

2、范围,对本文描述的话题设定一个边界,即:在有限的范围内讨论,以避免话题一发不可收拾。这里可以说明一下,这次设计方案的适用场景,要解决的问题的边界在哪里(要准确,不要详细),比如:

本文仅描述在APP网络条件下,基于HTTP协议网络不可达的场景

3、定义(可省略),比如:专有名词,文内涉及到的自创名词,公司内名词的解释等,这部分可以省略;比如:

DNS:DeDao Name Service,服务注册与发现(命名服务)

GW: DeDao Gateway,网关

4、现状,描述了我们目前存在的问题,带来的影响面等,比如:

出现网络问题后,我们解决的时间太长:目前用户出现网络相关的问题,我们只能寄希望于CDN服务厂商来解决,这个周期在4-24小时。

5、目标,描述了这次方案要达成的效果,可以获得的好处,比如:

当网络问题出现后,可以在10分钟内完成处理(总体的好处,与现状中描述的问题相呼应)

至于目标中涉及到的一些其他限制,可以放在附录里面(比如:基础的QPS限制等)。

2.1.2、打算怎么做:设计思路

有了问题,有了目标,接下来就是:怎么做了。

首先,我们要看看问题出现的原因是什么(定位问题),这一步非常关键,因为找准敌人是我们能不能提供有效方案的前提。

比如,网络连通性问题,造成用户连不上服务的原因,归结为两类:

1、DNS将用户调度到了错误的节点,导致这个节点无法连通

2、DNS将用户调度到了正确的节点,但是这个节点故障了(无法提供正常的服务)

那么针对上面的两个原因,我们就得有针对性的提供解决方案:

1、DNS的问题,使用IP访问的方案,或者 httpDNS的方案(两个都是可行的方案)

2、节点故障的问题,目前通知CDN合作方来调整节点,另外也可以提供多个节点做灾备

有些时候,我们需要多方案对比。针对一个问题,理论有无数的解,那么这个时候一般需要思考:哪一种核心思路是最合适的(当下)。一般情况下,我们会列至少两种可行的解决思路,来做对比。

比如:

针对节点故障的问题,有如下解决方案:

1、人工容错,通知CDN合作商进行节点调整(修复),周期4-24小时

2、提供多个CDN节点做灾备,由客户端调度

针对上面两个方案,方案1,成本小,但是周期长(SLA达不到);方案2,实现成本大,但是SLA效果好,另外还能带来CDN成本降低的好处(虽然跟目标不符,但是也是一个好处)

这个时候,得开始描述,用了方案2,打算怎么做了。

2.1.3、说说怎么做:技术设计

有了基本的设计思路,那么如何通过设计把思路实现。这里重点描述怎么做,以及在一些技术的选型上如何取舍。

2.1.3.1、设计的准则

我们做设计,都会有一个好坏的标准(比如做技术设计评审,也会有一个是否通过的标准),那么设计什么样的设计是好的设计?从我接触到的一些人(P8P9大神)对这个问题的理解(这部分可以参考:极客时间里李运华的《从0开始学架构》),我整理总结了一下:

  1. 合适即可,少做过渡设计,不做勉强实现。这里有个度,即:什么程度合适,这个就需要拿捏了(经验的区别就出来了)
  2. 简单即可,如果可以有更简单的办法实现,那么用简单会比复杂的好
  3. 演化改进,“演化优于一步到位”

(上面三个我就不解释了,纯是观念问题,理解即可)

另外,我们对设计上有一些基本的描述,这些会有两个方面:设计原则和设计特性。

所谓的设计原则,一般情况下我们讲的是六大设计原则:单一职责(SRP)、开闭原则(OCP)、里式替换(LSP)、依赖导致(DIP)、接口隔离(ISP)、迪米特法则(LoD)。这部分这里不做赘述,各位可以自行Google(红色加粗表示重要)。

设计特性上,我整理了一份常见的特性:稳定性(鲁棒性)、可测试性、高可用性、可扩展性、最小复杂度、可维护性、松散耦合、可重用性、可移植性、层次性。

一般情况下,遵守上面的设计原则的设计总是比较好的(目前我没有找到反例),满足实现原则的设计,在系统特性上,一般也具备比较多的特性。比如:

满足OCP和SRP的设计,一般都松散耦合和可扩展的,做得好的,还可以满足:可维护、最小复杂度、可重用、可移植和层次性。

以上的原则和特性,需要慢慢练习,至于它的好处,也是慢慢会体现出来。

2.1.3.2、概要设计

一般情况下,我们会使用“总-分”的思路来写内容,即:先写整体框架(架构)是怎么样的,然后再分别写每个模块是怎么做的。概要设计,就是描述技术的整体怎么做。

总体设计中,可以分为以下几种场景:

1、整体设计里面包含各子系统或子模块,那么需要做整体的架构图(可以是框图、也可以部署图),来区分彼此的定义

2、如果是业务类型的设计(如实现某个业务的接口、过程等),可以有流程图来描述。

上面说的需要使用图标来描述,这里是个建议,不是必须的;如果觉得文字能够说明白,那么可以省略画图。

概要设计中,描述了多个子系统或者多模块的“定位”,即满足系统三要素:要素(命名)、关系、定位。

命名(要素):这个模块叫什么,比如:接口层、调度器等

关系:模块和模块之间的关系,这里一般讲的是:越往上越贴近业务,越往下越贴近实现

定位:也可以叫功能、作用,它被设立的目的是什么,这部分需要满足单一职责,即:一个模块干一件事

2.1.3.3、业务设计/模块设计

这部分可以有多个,主要描述各个模块的具体实现。这部分一般有两类:

  1. 业务类,比如:业务接口
  2. 模块类,比如:存储模块、算法模块

这里,如果是业务类,需要写清楚业务的流程,即:业务实现的各种可能性,输入是什么、输出是什么,实现什么feature,实现的逻辑。注意:这部分需要满足:接口的单一职责和接口隔离,即:一个接口干一件事。

模块类,一般根据模块的定位来描述,比如:这个模块主要是做算法的,那么重点写清楚这个算法实现;如果这个模块是做存储的,可以写清楚存储的数据结构;除此之外,有时候也必要提供对外的接口。

2.1.3.4、存储设计

曾经有位大哥讲:计算机系统=数据结构+算法。那么这部分就是我们所谓的数据结构。在目前的分布式系统中,大部分的存储分为:

  1. 缓存(Redis、Memcache等)
  2. 业务数据(Mysql、MongoDB、Redis等)
  3. 基础数据(Mysql、MongoDB、HBase等)
  4. 文件存储(OSS、S3、其它文件存储)

这里存储主要在数据库上面(这部分根据重点,有的项目重点在缓存上,有些在文件上),数据库建议这里写清楚:数据库的建表语句和核心查询SQL。

2.1.3.5、降级与预案

这部分主要描述,当我们的正常业务不可用、使用超出系统限制的时候,会如何反应。这部分可以分场景(分情况)来描述,讲清楚即可。

2.1.3.6、运维与部署

一般情况下可以省略。如果涉及到跨系统调用、中间件,这里建议有一个部署图,并描述清楚,哪些是水平扩容、哪些是主备方式。

2.1.4、补充材料

补充材料可以描述,我们在做调研的过程中,涉及到的一些参考资料(可以是书、文章、论文);另外,有一些不方便在前面描写的,也可以在这里写一写,比如:错误编号等。

2.2、如何做得更好

说完了基本结构,表示我们可以先简单写一个文档了。那么如何将文档写得更好一些,可以让他人读起来更准确、高效理解设计的内容?

2.2.1、方案是完整的

方案设计是完整的,一个设计一般会考虑:

  1. 业务上满足产品需求
  2. 测试上满足质量需求
  3. 时间上满足项目需求
  4. 运维上满足部署需求

(上面的话也不是我说的,是某知名架构师说的)

2.2.2、方案是有条理的

好的设计就像讲故事一样,有前因后果,逻辑清晰,能从一处引出到另外一处。

2.2.3、方案是易读的

并不是晦涩难懂的方式是牛逼的方案,深入浅出的东西容易让他人一目了然(当然也不反对有些人为了写的爽)。那么我们也会有一些技巧可以让方案更容易被读懂。

2.2.3.1、使用结构化表达代替完整的段落

如果某些内容可以用:1、2、3来表达,那么尽量用它来描述,比如:

这个设计讲了如何使用CDN,也讲了CDN的限制,说明的CDN的价格,最后还解释了哪些场景不能使用CDN。

可以修改为:

  1. 如何使用CDN
  2. CDN的限制
  3. CDN的价格
  4. 哪些场景不适合

2.2.3.2、使用表格来描述二维数据

如果可以用表格描述的,尽量用表格,方便一目了然。

2.2.3.3、使用图

一图胜千言,也是这个意思。关于技术设计的五个图,参考:软件工程常用的五种图

这里,其实还少了一张图(这个图在某些场景下也非常有效),叫:用例图,这种图可以更好的描述用户的功能(需求)。

2.2.3.4、合适的粒度,可以帮助表达得更准

当我们在描述一个概要设计的时候,这个时候更关注整体系统有多少个子系统,分为了多少层,那么在这个设计里面,类图就是不合适的。如果我们的设计是关于某个算法的,那么在这里花大量时间描述为什么要做这个算法也不合适。

合适的粒度可以帮助设计更有主次,更容易让表达不跑偏,从而实现准确。

2.2.3.5、标题有层次有序号

如同本文一样,有不同级别的标题、有序号,是不是更清晰一些?

3、附录

3.1、参考资料

  1. 《软件开发过程中的浪费--详细设计》http://www.cnblogs.com/stephen-wang/archive/2012/11/12/2767021.html
  2. 《软件质量模型的6大特性》https://blog.csdn.net/u012841352/article/details/54237654
  3. 《软件的6大特性》https://blog.csdn.net/wyl836662856/article/details/51860732
  4. 《代码大全》第二版
  5. 《设计模式之六大原则》http://www.cnblogs.com/dolphin0520/p/3919839.html
  6. 《架构设计的三原则》 李运华,极客时间《从0开始学架构》
  7. 《UML用例图》https://blog.csdn.net/wrs120/article/details/52612107

3.2、参考样例

下面这些参考样例,来自于不同公司的不同风格,供大家参考。

  1. bilibili 高并发实时弹幕系统的实战之路 ,来自刘丁,重点看文章的逻辑性

3.3、模板

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.埋点是做什么的 2.如何进行埋点 3.埋点方案的设计 近期常被问到这个问题,我担心我的答案会将一些天真烂漫的孩...
    lxg阅读 2,038评论 0 1
  • 一、课程性质与基本理念 (一)课程性质 信息技术作为当今先进生产力的代表,已经成为我国经济发展的重要支柱和网络强国...
    新手老梁阅读 9,112评论 0 5
  • iOS网络架构讨论梳理整理中。。。 其实如果没有APIManager这一层是没法使用delegate的,毕竟多个单...
    yhtang阅读 5,330评论 1 23
  • 添加权限 书写监听广播 清单文件配置 网络变化后的回调 网络判断的工具类 网络状态枚举类 常量类 管理类 方便外部...
    伊泽瑞额阅读 457评论 0 0
  • 昨夜你进入我的梦里 没有了以前的高傲 似乎也缺少了很多贵气 也和我轻轻的诉说 不过是些家长里短的故事 似乎还有儿童...
    吃烟阅读 228评论 0 5