0

    再谈如何写好技术文档?

    2023.07.19 | admin | 150次围观

    最近一个月有超过50个客户投诉说系统不好用

    4

    升级依赖库后,该函数运行很快

    将依赖库升级到2.3.1版本后,该函数执行时间缩短到100ms以内

    5

    研发同事很辛苦,每天加班很晚

    研发同事很辛苦,每天23:00之后才下班

    表3-3 形容词/副词使用不恰当举例

    最后,我们来总结一下:

    优先使用方便读者阅读理解的动词和句式(强势动词和主动语句);

    尽量少用形容词和副词,用具体数值代替、或者调整句子表述。

    —4—

    正确使用术语

    序号名词说明

    1

    SDK

    Software Development Kit,软件开发包,开发者基于该工具包开发更丰富的高层应用。

    2

    内存泄漏

    通过new/malloc等方法申请的内存在使用完后未被及时释放,程序运行内存占用越来越高。

    3

    面向对象

    强调对数据和功能的封装,提升代码的可复用性、可扩展性以及灵活性。

    4

    FVM(*)

    Front Video Manager,前端视频管理服务,负责视频接入、分发等业务。

    5

    视频大数据标签服务(*)

    对视频进行结构化处理,生成结构化标签,并对外提供标签检索等功能。

    表4-1 名词解释举例(*为自定义术语)

    有些文档可能篇幅比较短,并不是传统意义上的需求设计类文档,比如对某个线上问题分析的结果汇报、对某个模型检测效果的验证报告、或者研发阶段性的工作总结。这些文档由于本身内容就不多,大部分可能直接进入主题,这时候如果还要在文档中专门增加一块名词解释的版块(并且总共也就一两个术语),就显得比较突兀。

    当视频离线时,FVM(Front Video Manager,前端视频管理服务,负责视频接入、分发等业务。)会产生一条告警记录,并存入节点数据库。

    上面这个术语解释内容太长,不太适合使用小括号的方式,这种情况要么在文档正文中专门对FVM进行解释,要么在小括号中只给出FVM的英文全称即可:

    当视频离线时,FVM(Front Video Manager)会产生一条告警记录,并存入节点数据库。

    使用小括号去做术语解释还需要注意一点的是:只需要在术语第一次出现的时候做一次解释即可,不需要重复多次。下面举一个重复的错误例子:

    当视频离线时,FVM(Front Video Manager)会产生一条告警记录,并存入节点数据库。之后节点数据库会将该条告警记录同步到平台数据库,平台FVM(Front Video Manager)检测到有新的告警记录时,会通过消息中间件通知业务系统,业务系统随后将告警信息以短信(或钉钉)的方式通知到用户。

    上面对术语FVM的解释重复了两次,这种做法是错误的,第二次我们可以直接去掉。

    有些术语存在全称和简称,我们熟悉的SDK全称是“Software Development Kit”,但是现在基本没有人再去使用它的全称。像这种简称已经被大众熟知的术语,我们就不能再标新立异的去用它的全称。

    另外一些在文档中自定义的术语,文档作者为了便于阅读可能也会提供一个简写的版本,在这种情况下,文档前后应该保持一致,即:要么整篇文档都用全称,要么都用简称,尽量做到一致。下面举一个全称简称使用不一致的例子:

    IVA(Intelligent Video Analytics,智能视频分析)服务主要负责视频解码、模型推理、目标跟踪以及目标行为分析,该服务是整个系统中最复杂的一个模块。智能视频分析服务由张三团队开发完成,一共耗时6个月,人力成本开销120万。

    —5—

    正确使用段落

    单一职责

    Excel提供一个组织数据的高效方法。我们可以将Excel想象成一个有行和列的二维表格,每一行代表一个独立的实体,每一列代表该实体的不同属性。Excel还具备数学功能,比如计算平均值和方差等数学操作。如果你想使用Excel来记录图书信息,那么每一行代表不同的书本,每一列代表书本的属性,比如书的名称、价格以及出版社等等信息。

    上面这段话的第一句已经明确了段落主题:Excel能高效地组织数据。可是,这段话中间却穿插了一个不相干的句子,说Excel具备数学功能,能够做一些数学操作,这句话显然跟本段主题不一致,我们需要将其去掉:

    Excel提供一个组织数据的高效方法。我们可以将Excel想象成一个有行和列的二维表格,每一行代表一个独立的实体,每一列代表该实体的不同属性。如果你想使用Excel来记录图书信息,那么每一行代表不同的书本,每一列代表书本的属性,比如书的名称、价格以及出版社等等信息。

    好的开头语

    除了要保证段落的“单一职责”之外,我们还需要给每个段落一句“好的”开头语。那么什么是好的开头语呢?好的开头语要能让读者读完之后就能猜到文档作者在本段中想要陈述的主题,其实就是概括性的句子。

    还是以上面那段话为例子,它的第一句话“Excel提供一个组织数据的高效方法”其实就是很好的开头语,它提示本段内容主要讲Excel如何高效地组织数据。如果我们将上面那段话的开头调整一下,那么效果明显就差了很多:

    Excel由许许多多的单元格组成,每个单元格可以包含不同的内容。我们可以将Excel想象成一个有行和列的二维表格,每一行代表一个独立的实体,每一列代表该实体的不同属性。如果你想使用Excel来记录图书信息,那么每一行代表不同的书本,每一列代表书本的属性,比如书的名称、价格以及出版社等等信息。

    读者读完上面第一句话后,可能还是很懵,需要读完整段话才能明白文档作者在本段中想要表达的意思。段落的开头语可以通过提炼段落内容得到,我们可以在段落写完之后回过头提炼一句话作为本段的开头语,下面这段话描述代码中循环语句的作用:

    目前几乎所有的计算机编程语言都支持循环语句,例如,我们可以编写代码来判断一个用户命令行输入是否等于“quit”(退出命令),如果需要判断100万次,那就创建一个循环,让判断逻辑代码运行100万次。

    上面的这段话本身没什么问题,主要介绍循环语句的功能和应用场合。但是如果我们提炼一下,在段落开头增加一个更好的开头语,效果可能会提升很多:

    循环语句会多次运行同一个代码块,直到不再满足循环条件为止。目前几乎所有的计算机编程语言都支持循环语句,例如,我们可以编写代码来判断一个用户命令行输入是否等于“quit”(退出命令),如果需要判断100万次,那就创建一个循环,让判断逻辑代码运行100万次。

    上面开头第一句话就说清楚了循环结构的特点,读者读完第一句话基本就知道整段内容要讲什么。一个好的开头语能够节省读者的时间,因为并不是每个读者都有兴趣去阅读整段的内容,开头语可以给读者“是否继续读下去”一个参考。

    控制段落长度

    —6—

    适当使用列表和表格

    文字相对来讲其实是一种效率比较低的表达方式。如果你想让人快速地去理解你要表达的意思,图片应该是最好的一种方式,但是图片有一个缺点就是:有时候它只能从宏观上去表达,无法体现其中细节。

    当我们想要尽可能直观地去陈述内容,又想尽可能多的包含细节时,我们可以考虑使用列表或者表格。有些读者非常抵触大段大段的文字(尤其在技术型文档中),一种改进方法是前面提到的“控制段落长度”,尽量让段落内容精简、单一;再一个就是看看段落内容是否能以列表或者表格的方式去呈现,这种方式可以给人“严谨、清晰”的感觉。

    使用列表

    列表简单来讲就是将你原来用段落方式呈现的内容改用项目(Item)的方式去呈现,一般它主要用于枚举、过程描述或者要点归纳等场合。列表中的各项可以是名词、短语,甚至是句子,各项目之间有严格顺序要求的列表叫“有序列表”,相反并没有严格顺序要求的列表叫“无序列表”。下面是以段落的方式陈述小张今天所做的事情:

    白天在公司上班期间,小张一共修复了7个bug,做了3个代码合并(评审),并和项目经理讨论了前天提的新需求。晚上回到家后,小张先做饭,然后给儿子洗澡,23:30上床睡觉。

    上面这段话本身没什么问题,用了合理的标点符号和过渡词,读起来清晰明了。但是,如果在技术型文档编写中,能将这段话改用列表的方式呈现,起到的效果会更好:

    我们将原来的一段话拆成了两个列表,并在每个列表前面做了一个“引入说明”(以冒号结束),介绍了接下来列表的背景上下文。第一个列表是无序列表,因为原文并没有突出强调小张白天在公司每项工作之间的前后关系(无顺序要求),只是一个归纳统计;第二个列表是一个有序列表,原文很明显强调了小张晚上回家之后做事的先后顺序(最后一项还给出了具体时间)。

    在技术型文档中,合理地运用列表这种方式去呈现内容可以给人一种“逻辑严谨、思路清晰”的感觉,让读者更相信你讲的内容。

    在使用列表时,我们应该确保列表中各项内容结构一致,即:要么都是名词,要么都是短语,要么都是句子。这个原则既能保证你使用列表的初衷(逻辑严谨、思路清晰),也能让读者读起来更舒服。下面是一个错误使用列表的示范:

    影响系统检测准确性的因素有:

    上面列表一共包含3项,每项的内容结构各不相同,第一项是一个名词,第二项是一个句子,第三项是一个短语。我们将结构统一后离线文件是什么意思,可以调整为下面这样:

    影响系统检测准确性的因素有:

    上面是将列表中各项内容修改为短语,我们还可以换另外一种方式:

    影响系统检测准确性的因素有:

    使用表格

    表格其实跟面向对象有一定联系,大部分时候表格中的一行相当于一个对象,表格中的列相当于对象的属性(字段),表格和面向对象组织数据的方式本质上是一致的。技术型文档中表格一般用来组织与数字有关的内容,当然也有例外,就像前面章节中用到的表格,纯粹是为了组织文本内容。

    下面是在技术型文档中,使用表格时可以参考的一些经验:

    组织数字相关内容时,一定要用表格(大部分人可能已经有这个意识);

    组织结构化类型的文本内容时,尽量用表格;

    每个表格都应该配一个表格标题,简要说明表格内容;

    文档中的表格应具备一致的样式和风格,比如标题字体、背景填充等。

    在技术型文档中使用表格组织文本内容时,需要控制每个单元格的文本长度。一般情况下建议单元格中只使用短语,如果必须要用段落,也应该控制段落中句子数量(一般建议不超过2~3句)。下面是错误使用表格来组织文本内容的示范:

    序号

    语言

    介绍

    1

    C

    C语言由贝尔实验室发明于1969至1973年,是一种编译型计算机编程语言。它运行速度快、效率高、使用灵活,常被用于计算机底层驱动以及各种语言编译器的开发。C语言是一种面向过程的编程语言,同时它的语法相对来讲较复杂离线文件是什么意思,新人入门门槛比较高。

    2

    C++

    C++语言发明于1979年,是一种编译型计算机编程语言。它衍生自C语言,继承了C语言的一些特性,比如使用指针直接访问内存,同时它也支持面向对象编程,提升了代码的可复用性、可扩展性以及灵活性。由于C++继承了C的大部分语法,再加上本身具备复杂的类型系统以及泛型编程等语言特性,新人入门门槛也比较高。

    3

    Python

    Python语言发明于1991年,是一种解释型计算机编程语言,因此运行速度相对要慢。Python除了支持面向对象编程之外,还支持函数式编程,它语法简单,更贴近人类自然语言,新人入门门槛较低。Python是目前人工智能领域最热门的语言,对应的工具库非常丰富。

    表6-1 三种编程语言介绍

    上面是以表格的形式来介绍C、C++以及Python三种编程语言,但是在“介绍”那一列中的文本内容太长,我们可以换一种表达方式:

    C

    C++

    Python

    由AT&T 贝尔实验室发明于1969至1973年

    再谈如何写好技术文档?

    由BJarne Struistrup发明于1979年

    由Guido van Rossum发明于1991年

    语法比较复杂,新人入门门槛高

    语法比较复杂,新人入门门槛较高

    语法简单,贴近人类自然语言,新人入门门槛低

    编译型语言

    编译型语言

    解释型语言

    支持面向过程编程

    支持面向过程、面向对象编程

    支持面向过程、面向对象、函数式编程

    偏底层、运行速度快、使用灵活

    继承了C语言的一些特性,在其基础之上还支持面向对象等特性

    语法简单,学习难度低

    一般用于驱动、编译器、嵌入式或者其他偏向硬件层面的开发

    一般用于游戏前后端、PC客户端的开发

    一般用于数据科学、人工智能相关开发

    表6-2 C vs C++ vs Python

    上面表格一共还是3列,但是现在每列代表一种编程语言,列中的每个单元格是对该语言的描述,描述内容都比较精简。如果你想继续补充内容,可以对应地增加行即可。

    表格的组织方式有多种多样,行可以变成列、列可以变成行,并没有严格的限制。我们只需要找一个适合自己的方式,比如上面这种每列代表一种语言,是因为该场景需要介绍的编程语言只有三种,如果数量再多点(或者数量不确定,后期会继续增加),那么表格宽度就不太够、这种组织方式就不再合适。

    —7—

    一图胜千言

    人类在发明文字媒介之前,用的是图形符号。图像(或图形、图片)是所有内容表达方式中最直观的一种,同时也能提升读者的阅读兴趣。有人专门做过研究:在文档中增加图像能提升读者对文档的喜爱程度,不管这个图像跟文档内容本身是否有关系()。

    也就是说,哪怕在文档中插入无关紧要的图像,读者也更愿意去尝试阅读文档中其他的内容。我们平时看别人演示PPT时,如果发现整页都是文字描述,大概率就不会有认真去听的欲望。下面是一段对双向链表的文字描述:

    双向链表也叫双链表,是链表的一种。它的每个数据节点中都有两个指针,分别指向直接后继节点和直接前驱节点。所以,从双向链表中的任意一个节点开始,我们都可以很方便地访问它的前驱节点和后继节点。在应用双向链表时,我们一般构造双向循环链表,链表首尾相连。

    双向链表也叫双链表,是链表的一种。它的每个数据节点中都有两个指针,分别指向直接后继节点和直接前驱节点。所以,从双向链表中的任意一个节点开始,我们都可以很方便地访问它的前驱节点和后继节点。在应用双向链表时,我们一般构造双向循环链表,链表首尾相连。下图是双向链表结构示意图:

    图1 双向链表结构

    上面的文本配合图片,能让读者更加直观的理解双向链表的结构特点。当文档中的文本和图片同时出现时,读者大概率会先看图片,然后再结合文字去理解,加快文档阅读速度。

    可抽象也可具体

    技术型文档中的插图不一定都得是流程图、架构图、或者结构设计图这种非常具体的技术相关图片,还可以是抽象的、能形象表达文档主题的图片。下面是在技术型文档中使用卡通和漫画图片的示例:

    示例1:

    Gitlab中有Label和Tag两个概念。

    图1 团队协作

    源码管理并不是软件开发周期的全部,整个软件开发周期涉及到多个流程、多个团队(多人)协作完成,包括立项/结项、进度/任务管理、需求/设计、bug管理、测试、集成上线等环节。另外,搜索公众号互联网架构师后台回复“2T”,获取一份惊喜礼包。

    突出图中重点

    整个视频分析系统由3大服务组成,分别是Intelligent Video Analytics、Front Video Service以及Distribute Load Balance,这3大服务一共包含15个子模块。下面是视频分析系统结构:

    图1 视频分析系统结构

    上面这个例子中插入的这张图既想描述3大服务之间的交互关系、又想描述各个服务内部子模块之间的交互关系(上面只是示意图,实际情况可能比这个更复杂)。文档读者碰到这种情况可能会产生两个感觉:一是图太复杂了,很难看懂,有些地方迫于空间原因字号还小;二是我需要重点关注的点在哪里?如果遵循前面提到的“先宏观,再具体”的原则,上面这个例子可以调整为:

    整个视频分析系统由3大服务组成,分别是Intelligent Video Analytics、Front Video Service以及Distribute Load Balance。下面是视频分析系统中各服务之间的关系:

    图1 视频分析系统服务交互

    其中,Intelligent Video Analytics服务主要负责对视频解码、推理以及行为分析等结构化操作。该服务内部一共包含9个子模块,模块之间的关系见下图:

    图2 Intelligent Video Analytics服务子模块交互

    Front Video Service服务主要负责视频接入、分发、配置管理等功能。该服务内部一共包含3个子模块……

    另外一种情况,插入的图片中包含了不相干内容,文档作者又没有给出醒目的标记,读者看完不清楚关注重点在哪里。下面是错误的示例:

    GitLab中的Release功能主要用来对仓库中的代码以及其他一些相关资料文件进行归档,通常用于版本发布。当有新版本发布时,用户可以基于对应的Commit创建一个Tag标记,给它一个合理的名字,比如“v1.0-pre”(代表发布1.0预览版),然后再基于该Tag发布版本。

    后期,其他人可以通过Release菜单快速浏览、检索项目版本发布记录以及对应时间点的相关代码和资料。用户可以在GitLab主界面的左侧菜单中找到Release功能入口:

    图1 Gitlab中Release菜单

    上面图片在介绍Release功能时给出的图片中包含的菜单项太多,为了让读者更直观看懂图片关注点,可以将图片调整如下(左右两种都可以):

    GitLab中的Release功能主要用来对仓库中的代码以及其他一些相关资料文件进行归档,通常用于版本发布。当有新版本发布时,用户可以基于对应的Commit创建一个Tag标记,给它一个合理的名字,比如“v1.0-pre”(代表发布1.0预览版),然后再基于该Tag发布版本。

    后期,其他人可以通过Release菜单快速浏览、检索项目版本发布记录以及对应时间点的相关代码和资料。用户可以在Gitlab主界面的左侧菜单中找到Release功能入口:

    图1 Gitlab中Release菜单

    有准确的图标题

    图片是为了读者能够更直观地理解文档内容,但是图片毕竟不是文字,不同的人对同一张图片理解可能存在差异,尤其对于那种不包含任何文字的图片。因此,在文档中插入任何图片时,我们应该为它定义一个合适、贴切的标题。图标题一般是一个名词或者短语,作用跟前面讲到的表格标题一样,协助读者理解图片所要表达的含义。

    —8—

    统一样式和风格

    —9—

    把握好整体文档结构

    把握好整体文档结构是一件非常困难的事情,这个其实跟前面讲到的文档内容本身没什么关系。文档作者在动笔之前需要有一个宏观的构思,需要在脑子里先将文档大纲梳理一遍,一级标题可以是什么、二级标题又可以是什么,然后考虑将合适的内容放到对应的章节中去。

    优秀的作者在正式动手之前,可能已经有了很长一段时间的思考准备,尤其对于那种非常复杂的文档。但是这种方式对一些人来讲可能不太现实,难度太大。那么这时候就只能考虑另外一种方式,动手之前先在白纸上打草稿,列出来文档大纲,然后不断修改和调整,直到满意为止。

    其实不管上面哪种方式,文档结构考验的是作者组织内容的思维能力。对于一些需求、设计类型的“主流”技术型文档,考验的是作者对软件需求、系统架构的理解深度,该写什么不该写什么,写到什么程度,这些都需要作者考虑清楚,这类型的文档一般有标准的模板可以参考,大家平时写得/见得也比较多。

    场景说明:

    视频分析系统中,客户要求在事件录像文件中对涉事车辆目标(或区域)进行高亮标框显示,视频录像在播放时会有一个醒目的多边形提醒用户具体事件发生位置。客户懂一些技术相关知识,要求公司技术研发团队针对该需求给出合理的需求反馈,如果需求可实现,评估工作难度;如果需求不可实现,说明具体原因。

    序号

    节标题名称

    主要内容

    1

    背景说明

    用自己的话将客户的需求完整描述一遍,不要有任何偏差,表明我方已认真理解过原始需求。

    2

    已有录像逻辑

    详细描述系统中目前已有的事件录像逻辑。因为我们本次是不响应该需求,所以对后面不响应有利的内容一定要着重强调(要突出已有录像逻辑的优势)。

    3

    录像标框逻辑

    详细描述在事件录像文件中对涉事目标(或区域)进行高亮标框的逻辑。注意这里按照理想逻辑去描述,不用考虑任何外在限制。

    4

    录像标框难点

    结合第3点,重点归纳、整理出在录像文件中标框的难点,比如需要对每一路进行解码再去叠加图形、视频画面不能压缩否则影响分辨率等等,这些对设备性能要求非常高,会增加硬件成本。

    5

    解决方案一 (不计代价去响应)

    按照理想逻辑去响应,但是要提出前提条件或者代价,比如单台设备分析路数降低到原来的一半,硬件成本是原来的2本。(其实就是要排除这个方案)

    6

    解决方案二 (可替代方案)

    提出一种可替代的方案,可以满足客户最开始提出的“有醒目标记提醒用户”。比如当视频录像播放时,可以在播放器上面叠加一个高亮方框,能够大概标记涉事车辆目标(或区域)。同时,强调该方案的优势(比如工作周期短、对成本无影响)。

    7

    结论

    其实根据前面的描述,只要认真读完文档的人基本都能知道结论是什么、应该选哪个方案。但是这里还是要书面写上,根据前面的描述,解决方案二有更大的优势,建议采用方案二。

    需要注意的是,“响应”或者“不响应”的决定很多时候不在技术团队或者写这个文档的人手里。虽然文档中的内容应该为最终的结论服务,但是总体上不应该有偏差。扩展:

    —10—

    明确文档的目标群体

    文档的目标群体是谁?这个其实应该是写文档最开始就需要明确的东西,面对不同的群体,我们文档的内容、结构包括内容描述程度都会不同。尽早确定读者有助于在构思阶段就明确文档内容边界,哪些该写、哪些不该写,该写的又应该如何去写,这些都是编写文档的大方向。

    作者:周智,前微软(中国)Windows工程院员工,目前从事于深度学习计算机视觉相关工作,交通安防领域的视频目标检测、跟踪和行为分析。

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论