3

周刊(第8期):技术配图的一些心得

 2 years ago
source link: https://www.codedump.info/post/20220304-weekly-8/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

引言:写过不少技术文章,以及给不少技术思路手绘示例配图之后,在这方面有了一些心得,本文权当个人的一些的总结,抛砖引玉。


技术配图的一些心得

我觉得我们理工科出身的,对于可以量化的事情,总是很容易根据量化差异来做出判断,比如一个程序性能优化之后,能比优化之前快出多少,都能有一个量化的数字来说明。

但是对于那些不能量化的东西,就很难说出具体好在哪里了。

本文主题要讨论的“技术配图”就属于这种很难量化的领域,很难有一个标准来量化说明两幅图之间差别在哪里。我也是画了很多图,以及看了别人的很多配图之后,才慢慢有一些心得,本文权当个人的一些的总结,抛砖引玉。

本文并不是一个画图工具的对比说明,尽管现在各种绘图工具已经很多,也各有自己的优缺点以及个人喜好,但是在这里并不讨论具体工具的使用,会把更多的文字放在配图的一些注意事项上。但是,也总有人问我文章的配图使用什么工具做的,在这里再回答一次:OmniGraffle,一款目前仅有Mac版本的工具软件。

一图胜千言

在开始交代具体的配图注意事项之前,有必要先说说配图的重要性。

绘图,某种程度也是辅助自己思考某个技术点的手段之一,以我个人的体会来说,有时候讲不清楚一个技术点的时候,就手绘图出来,比朴素的文字更容易说明问题。其中的原因,有可能是:图片可以有多维的信息,而文字通常只有一维,遇到文字表达能力不太好的人,这仅有的一维能力可能还不好发挥出来。

所以,在交代技术细节、沟通交流的时候,尽量多画图。反向的,图画多了,也自然慢慢会找到感觉,如何更好的通过图示表达思路。

顺便一提,还有比朴素的文字表达更差的技术沟通方式,就是简单粗暴的贴一大段代码上去。这种做法,其实更多时候是没有对作者的思路有太多个人的整理,想偷懒的方式,最后回头再看写过的文字,可能连自己都看不懂了。

个人的一个体会:如果产出某些输出的时候,能假设自己未来就是这些输出的读者、维护者,那么输出起来会更“友善”一些。比如写的代码、文章、甚至于提交代码时候的信息,如果能考虑是写给未来的自己看的,会更清晰、尽可能留下更多的信息。我最开始要在文章里大量配图,也是为了将来自己回看的时候能看懂。

扯远了,总之,尽可能多画图来表达技术思路。

下面开始正题,以下会以简单的几个原则及示例来说明。

区分、联系、组合

配图中,应该尽量将不同的模块、组件等区分开来,“区分”的方式有很多,常见的有:

  • 使用不同的颜色。
  • 使用不同的形状。
  • 使用箭头、曲线等表示数据的走向、趋势。

等等,所有的这些手段,概括起来就是尽量在图中,将不同的元素区分开来,“有区分”意味着至少有一个维度的不同,这样能给读者更加清晰的感觉。可以结合下面的例子来理解区分、联系和组合的绘图表达。

一个模块里,可能由多个组件构成,可以把这些组件分组到一个更大的模块中。

分组是非常常见的一种手段,这里多举几个例子。

上图中,每个CPU Core中有L1、L2缓存,于是把这些组件合并在一起放在Core组件中,周围使用一个正方形包裹起来,同时这个正方形左上角有一个Core的说明文字,这样一目了然:Core模块,由L1、L2缓存构成。

上图出自Raft论文,整体上划分为了Client、Server这两大部分。而每个Server又有以下三部分组成:

  • 一致性算法模块。
  • 持久化的日志。

所以,图示中将这三部分合在一起放在同一个矩形里,表示一个Server有这三个组件。

另外还需注意的是,一般这种分组中外围的矩形,有这样的讲究:

  • 一般使用斜面矩形,即四个角是圆角的矩形,这样圆润一些的边角看起来会更舒服一些,如上图。
  • 如果这个组合,是一种逻辑上的组合,那么线的形状一般用虚线;否则就一般用的实线。

在分组时,有时候可以将相同类型的模块层叠起来,这样会更加简洁,如下图:

上图是出自Raft论文中的状态机模型,其中想要表达的一个点是:

  • 有多个client向server发起请求。
  • server要达成一致,需要将日志在server之间同步。

但是上图中,并没有把这些同类型的组件分开表达,而是巧妙的使用层叠的方式,简洁得表达了有多个client、多个server的情况。

如果不同的组件之间,有不同的趋势,可以在图中使用类似箭头这样的符号表达出来。

下图是描述不同层次存储的访问速度,于是用了两个方式来表达访问速度的变化趋势:

  • 左边的箭头表达速度和成本的变化。
  • 不同大小的多边形表达了这些存储空间的变化:越往上访问速度越快,但是对应的存储空间也更小。

再比如,下图中,是说明sqlite中btree页面的数据组织的。其中的两部分内容,Cell地址数组以及Cell内容区为变长大小,前者从地址低位向高位生长,后者反之,于是在图中,就用箭头示例出地址的高低位区别,以及两者的增长方向:

(出自sqlite3.36版本 btree实现(五)- Btree的实现 - codedump的网络日志

用箭头等表示数据、状态等的走向,或者模块之间的联系。

这在涉及:

  • 状态切换。
  • 数据流向。

等场景下是非常常见的手段,比如经典的TCP状态机切换:

以及TCP三次握手流程,也是典型的“状态切换”:

需要说明的是,以上的图示中:

  • 箭头代表的状态切换走向中,同时也配以文字说明是什么动作导致的状态切换,这样这个图示就更清晰了。
  • 箭头也分为实线和虚线,一般而言,虚线表示数据的走向,实线表示状态的走向。

需要禁止或者错误的行为,可以用特殊的符号,如带颜色的“×”符号示意出来;反之,可以用带颜色的“√”符号示意出来,而且表示禁止的时候,一般用红色会更显眼,下图就是一个示例:

(出自 Memory Barriers in .NET · Nadeem Afana’s Blog

如果不好说明问题,可以在图示中搭配简短的说明文字。注意:这类型文字一定要足够的简短,否则可能会喧宾夺主。

比如下图中,有两部分蓝色注解的文字来说明不同的表类型:

(出自sqlite3.36版本 btree实现(五)- Btree的实现 - codedump的网络日志

再比如下图中,使用注解文字来说明查找数据的两步流程:

(出自sqlite3.36版本 btree实现(五)- Btree的实现 - codedump的网络日志

有时候需要使用类似{这样的符号,对一类元素做一些说明,例如:

下图中,是说明sqlite中btree页面的数据组织的,最右边的以{包起来的文字,对每部分做了简要的说明。

(出自sqlite3.36版本 btree实现(五)- Btree的实现 - codedump的网络日志

下图中,将页面划分为不同的部分,这些不同的组成部分,既使用了颜色进行区分,也使用了向下的{辅以文字说明。

(出自sqlite3.36版本 btree实现(五)- Btree的实现 - codedump的网络日志

如果配图是需要讲解某个操作的步骤的,可以配以数字来辅助理解整个流程。

下图中,表达的是根据帧数查找页面编号的两个步骤:

(出自sqlite3.36版本 btree实现(四)- WAL的实现 - codedump的网络日志

下图中的步骤就更多了,并没有显得很乱,大概原因在于:

  • 最左边表达了每一步的步骤。
  • 每一步写入数据之后,显示WAL文件在写入之后的内容。
  • 最右边使用{表达修改之后的数据。

(出自sqlite3.36版本 btree实现(四)- WAL的实现 - codedump的网络日志

在讲解例如文件格式,或者协议格式等内容的时候,格式由多个部分划分组成,其中又可以针对其中的某些内容展开说明。

如下图中,是用于展示wal index索引文件格式的:

  • 左边示例每部分内容的大小,想说明的是,那个索引块大小为32KB,而第一块的头136字节为索引文件头。
  • 于是,在右边图中,将左边不同模块的具体格式继续展开说明。

(出自sqlite3.36版本 btree实现(四)- WAL的实现 - codedump的网络日志

以上简单总结了一下个人技术配图的一些心得,总的大原则是:

  • 区分:将组件、流程、趋势等之间的”区分“尽可能在图示中通过各种手段(如不同的颜色、形状、箭头)表达出来。
  • 联系:组件之间的数据流动、状态切换等,都是它们之间的联系,也需要通过各种手段表达出来。
  • 说明:可能的话,要在图中加上一些说明文字,如步骤说明、分类说明,等等。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK