写点什么

代码文档的文艺复兴:代码走读

作者:Omer Rosenbaum,Tom Ahi Dror

  • 2021-11-17
  • 本文字数:3153 字

    阅读完需:约 10 分钟

代码文档的文艺复兴:代码走读

我们正在进入一个代码协作的新时代,一个具有实质性的重大变化即将出现。它到底是什么?更重要的是,它为什么会出现?


本文是“持续文档化宣言”的第二部分。我们在宣言中呼吁将创建和维护高质量的文档纳入开发流程。这一次,我们重点关注经常被低估的第三类文档——代码走读文档。


首先,我们一致认为,开发者和开发团队需要好文档。从理论上看,这个很容易做到。我们每个人都写出好文档,一切都会变得更好,不是吗?


事情并没有那么简单。当前的文档并不是为开发者服务的。在大多数情况下,文档不是缺失就是过期,所以开发者不信任文档,或者干脆从一开始就不创建文档。这会影响到整个团队或业务。要想走出这种困局,需要新的方法和工具。

持续文档化宣言回顾

持续文档化方法有助于创建和维护稳定的高质量文档,确保文档化成为开发过程的关键组成部分,就像测试或编码一样。持续文档化依赖三个原则:


  • 与代码耦合——文档应该显式引用部分代码。

  • 保持最新——随着代码的不断演化,持续保证文档的当前状态与代码的当前状态是保持一致的。

  • 即时创建——在知识最“新鲜”的时候创建文档。

常见的文档类型

内联文档(策略性的底层文档,比如代码注释)和高阶文档(可以为你提供更高层的视图)是最为常见的文档类型。但要向希望了解代码逻辑或者要修改代码的人解释清楚,这两种文档并不是很管用。


内联文档


这是一种策略性文档,用于解释代码行或代码块,最常见的是代码注释。例如,有一行代码包含了除数是 24601 的数学运算,注释里解释了为什么是这个除数,那么这个注释就是一种用于解释这行代码的内联文档。它并不会告诉我们更多东西,也不会告诉我们这行代码在一个更复杂的架构中承担了怎样的角色。另外一个例子是位于函数下面的注释,用于解释这个函数做了什么以及它的参数和返回值是什么。这个注释只解释了函数本身,并没有说明它为什么被用在特定的代码流程中。


有些人不写注释,但会尽力提高代码的可读性,我们认为,这也是一种内联文档。


高阶文档


如果说内联文档提供的是细节,那么高阶文档提供的是大视图,可以是整体的代码架构、代码背后的业务逻辑以及与二者有关的重大决策的缘由。有时候,高阶文档用于描述各种代码库或者某个特定代码库的主要模块。在初次了解一个代码库时,这种文档是非常有用的。不过,它的价值也就止于此。因为,它很少会包含与日常任务有关的东西,开发者不会频繁阅读它。


为什么这两类文档不是很管用?内联代码注释描述的是与之相关的代码块,范围狭小。高阶文档可以提供大视图,但缺乏开发者需要知道的细节。例如,在一份有关如何扩展 Git 的文档中,你可以从高阶视图描述创建一个新 Git 命令的过程,但如果缺乏细节,或者没有代码示例,你就不可能实现。这些细节包括文件的路径、函数的签名等。如果你将这些细节加到文档中,那它就不是高阶文档了。

代码走读文档

代码走读文档至少会让阅读代码的人看到代码的两个地方。它们描述了代码流程和交互,可能还会依赖代码片段。换句话说,它们与代码是耦合的(符合持续文档化原则之一)。


这种文档有点类似在有经验的代码贡献者的帮助下熟悉代码库。就像他们会向你解释代码的各个部分一样,代码走读文档做的是同样的事情。


下面列出了三个例子。


反复出现的代码模式


所谓反复出现的代码模式,可以是添加一个配置文件、继承一个类、创建一个新命令或者从数据库读取数据。这些模式都是很小的模式,很容易理解,通常涉及多次调用一个函数(调用日志函数也是一种模式)。更有意思一点的模式是跨多文件模式。因为这些模式在代码中多次出现,很有必要了解它们。阅读代码的人必须对整体有所了解,还需要知道特定的实现细节。


以给 Git 的 CLI 添加新命令为例。假设你是 Git 的贡献者,想要创建一个新命令,比如git new-command。我们来看一下如何添加这样的一个命令。我们不会涉及太多的细节,因为这不是这篇文章的重点,我们也不是要介绍 C 语言。


为了了解如何增加一个新命令,我们先看一下现有的例子——`git


add命令。这个命令的入口点位于builtin/add.c中,因为每一个命令在builtins`目录都有一个与之对应的文件。


int cmd_add(int argc, const char **argv, const char *prefix)    {
复制代码


这个函数的实现细节并不会影响对这个模式的理解,关键的是这个函数的签名——因为所有命令都有相同的参数。


函数签名声明需要被包含在builtin.h中:


int cmd_add(int argc, const char **argv, const char *prefix);
复制代码


但模式并未结束。要让 Git 知道add命令的存在,需要在git.c文件的commands[]数组中加入一个cmd_struct


static struct cmd_struct commands[] = {    { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },};
复制代码


为了能够构建项目,我们必须在 Makefile 文件的BUILTIN_OBJS中添加这个命令:


BUILTIN_OBJS += builtin/add.o
复制代码


注意,这里有很多与代码库耦合的东西,并带有很多特定的细节:cmd_前缀、文件目录结构(特别是builtin目录)、命令函数的签名、文件名称(builtin.hgit.c等)、变量名称(BUILTIN_OBJS),等等。阅读代码的人还能看到一个跨四个文件的模式,尽管从逻辑上讲它们都与创建一个新的 CLI 命令相关。


直接在一个单独的文档中写明这些有助于理解这个模式:



当然,这是一个简单的例子。对于更为复杂的模式和跨更多文件的情况,代码走读文档的作用就愈加凸显。


代码不同部分之间的交互


代码的某些部分(甚至是关键部分)可能难以理解,因为涉及各个部分之间的交互,而且交互细节不是那么显而易见。以一个简单的 Web 应用为例,为了了解它的流程,我们需要在前端和后端之间跳来跳去。特别是对于一个项目的新人来说,一份解释代码不同部分之间交互的文档可以显著降低他们上手的门槛。


多代码库或服务之间的流程


如果代码跨多个代码库,那么上述的例子就会变得更加复杂。假设前端代码位于一个代码库中,后端位于另一个代码库中。随着涉及的代码库数量的增加,情况会变得越来越糟糕。如果有一份文档对各个相关代码库的代码做了说明,理解整个流程就会容易得多。


那么这些东西有哪些共同点?


  1. 它们对代码做了解释,不仅仅是代码的某个方面。

  2. 它们包含了可用于理解代码的信息。

  3. 当相关的代码发生变化,它们就过时了。


第三点也是为什么如果没有持续文档化就很少会有这类文档,因为开发者倾向于一开始就不创建它们。


不管怎样,创建代码走读文档是一种善意的行为,不管是对你的团队还是对未来的你来说都是好事。如果没有代码走读文档,代码膨胀会成为一个需要你花费数月时间去解决的繁琐流程,还会导致知识孤岛在企业中蔓延。

结论

为什么很难找到详细的描述代码流程和交互的文档?这个与任何一段长期、稳定的关系一样,如果你不持续投入,它就会分崩离析。对于大多数开发者来说,当代码发生变化,用于更新文档的时间、注意力和工作量是很大的开销,他们宁愿选择将时间花在开发新功能和修复 bug 上……


遵循持续文档化实践可以发挥代码走读文档的无限价值。在知识还“新鲜”的时候创建文档,并保持最新,将其作为开发流程的一部分,其价值就会彰显出来。


Omer Rosenbaum 和 Tom Ahi Dror 是Swimm的联合创始人。这家公司专注于在团队之间同步代码。


作者简介:


Omer Rosenbaum 是 Swimm 公司的首席技术官和联合创始人。该公司将持续文档化作为开发生命周期的组成部分。Omer 创立了 Check Point 安全学院,并担任 ITC 的网络安全主管。ITC 是一个教育组织,培训技术方面的人才。


Tom Ahi Dror 是国会预算办公室和 Swimm 公司的联合创始人。该公司将持续文档化作为开发生命周期的组成部分。Tom 是一位在技术、培训、战略和业务发展方面有独特经验的领导者。作为以色列最负盛名的军事学院塔尔皮奥特的毕业生,Tom 后来成为该项目的指挥官。在联合创立 Swimm 之前,Tom 是 ITC (以色列科技挑战)的业务发展副总裁。


原文链接


The Renaissance of Code Documentation: Introducing Code Walkthrough

2021-11-17 09:174682

评论

发布
暂无评论
发现更多内容

为什么企业需要IT外包服务

Ogcloud

IT外包 IT外包公司 IT外包服务 IT外包企业

【程序大侠传】全局变量与并发之战

Disaster

焱融科技发布国产化全闪新品 F8000XC

焱融科技

写一篇最近用DM的总结

TiDB 社区干货传送门

迁移

【故障处理】 统计信息收集失败, enconding failed

TiDB 社区干货传送门

故障排查/诊断

Dashboard 热力图显示不准? 如何定位热点相关sql ?

TiDB 社区干货传送门

故障排查/诊断

ChatGPT4o 如何速写论文

蓉蓉

gpt4o

聚焦于 Melos 数据生命网络,用户如何参与到生态的建设中?

大瞿科技

在 K8s 上用 KubeBlocks 提供的 PG 和 Redis operator 部署高可用 Harbor 集群

小猿姐

postgresql Kubernetes operator Redis 消费队列

观测云:企业级监控的全方位解决方案

可观测技术

监控

以用户为中心:观测云的设计理念

可观测技术

监控

深入解析仓颉编程语言:函数式编程的核心特性

代码忍者

仓颉

夏日清凉计划开启,来华为天气领取出行礼包、影音会员等惊喜福利

最新动态

观测云:零售行业数据分析的利器

可观测技术

Web网页端IM产品RainbowChat-Web的v7.1版已发布

JackJiang

即时通讯 即时通讯;IM;网络编程

从"小白"到"大白":我的TiDB一周年成长记录

TiDB 社区干货传送门

【第八届 TiDB Hackathon】AI 创新应用 TiDB 黑客马拉松正式开启,一起来用 TiDB 构建未来的 AI 创新应用, 瓜分超 ¥210,000 奖金池!

TiDB 社区干货传送门

京东商品列表数据接口:电商数据分析的利器

tbapi

京东API 京东商品列表数据接口 京东商品数据采集

一文了解 PingCAP Clinic 诊断服务

TiDB 社区干货传送门

故障排查/诊断

一次 sysbench 长稳测试过程中连接中断的问题分析排查

TiDB 社区干货传送门

故障排查/诊断

一次 sysbench 长稳测试过程中锁丢失导致事务提交失败的问题分析排查

TiDB 社区干货传送门

故障排查/诊断

【论文速读】| Arondight:使用自动生成的多模态越狱提示对大型视觉语言模型进行红队测试

云起无垠

运维安全审计以及运维安全审计软件定义看这里!

行云管家

安全运维 运维安全 运维安全审计

In-depth analysis-IPQ5332 and IPQ8072 Technical comparison between

wifi6-yiyi

WiFi7 IPQ5332

探讨大模型前沿技术与商业化落地 |【奇绩潜空间】第3季开始报名

奇绩创坛

人工智能 机器学习 深度学习 大模型 视频生成

贝锐蒲公英智能选路:跨地区远程访问更快、更稳、更可靠

贝锐

远程办公 SD-WAN 智能选路 异地组网

职场<火焰杯>测试开发大赛决赛成绩及获奖名单公布!

测试人

软件测试

【YashanDB知识库】服务端是GBK编码,导致从22.2.12.100升级到22.2.13.100失败问题

YashanDB

yashandb 崖山数据库 崖山DB

24年黑龙江正规等保测评机构名单汇总

行云管家

等保 堡垒机 等保测评 黑龙江

淘宝商品详情API:商品规格参数的详细解析

技术冰糖葫芦

API Explorer API 编排 api 货币化 API 文档

sync_diff_inspector 表结构比较功能探索

TiDB 社区干货传送门

迁移

代码文档的文艺复兴:代码走读_语言 & 开发_InfoQ精选文章