NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

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

作者: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:174270

评论

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

Volcano成Spark默认batch调度器

华为云开发者联盟

云计算 数据分析 后端

openGauss内核:简单查询的执行

华为云开发者联盟

数据库 互联网 华为云

TDengine可通过数据同步工具 DataX读写

TDengine

数据库 tdengine 时序数据库 DataX

牛客java选择题每日打卡Day1

京与旧铺

6月月更

为什么生命科学企业都在陆续上云?

阿里云弹性计算

HPC 高性能计算 生命科学 基因测序

波卡生态发展不设限的奥义——多维解读平行链

One Block Community

区块链 科技

面试官:你说你精通Redis,你看过持久化的配置吗?

阿Q说代码

redis aof rdb 数据持久化

如何做到全彩户外LED显示屏节能环保

Dylan

LED显示屏 全彩LED显示屏 户外LED显示屏

建木持续集成平台v2.5.0发布

Jianmu

开源 DevOps CI/CD Worker 建木CI

架构实战营 第 6 期 毕业总结

火钳刘明

主数据建设的背景

奔向架构师

数据仓库 主数据 6月月更

如何抓手机的包进行分析,Fiddler神器或许能帮到您!

wljslmz

抓包 fiddler 6月月更

《各行业零代码企业应用案例集锦》正式发布

明道云

即构「畅直播」上线!提供全链路升级的一站式直播服务

ZEGO即构

Datakit 代理实现局域网数据统一汇聚

观测云

应用实践 | 海量数据,秒级分析!Flink+Doris 构建实时数仓方案

SelectDB

数据库 flink 数据分析 Doris 数仓

心楼:华为运动健康的七年筑造之旅

脑极体

AntDB数据库在线培训开课啦!更灵活、更专业、更丰富

亚信AntDB数据库

数据库 AntDB 培训学习 数据库·

XTransfer技术新人进阶秘诀:不可错过的宝藏Mentor

XTransfer技术

职场新人 职场经验

“阿里健康”们的逻辑早就变了

科技新知

在shiro基础上整合jwt,可在项目中直接使用呦

阿Q说代码

springboot Java EE 权限验证 shiro整合jwt

架构实战营 第 6 期 毕业设计

火钳刘明

#架构实战营 「架构实战营」

我国SaaS产业的发展趋势与路径

小炮

GitHub 高赞的 Flutter 状态管理插件BLoC 简介

岛上码农

flutter ios 安卓开发 跨平台开发 6月月更

优酷 Android 包瘦身治理思路全解

阿里巴巴文娱技术

治理 包大小

升哲科技 AI 智能防溺水服务上线

SENSORO

大数据 AI 物联网

Redis+Caffeine两级缓存,让访问速度纵享丝滑

码农参上

redis 缓存 JAVA开发 Caffeine

如何化解35岁危机?华为云数据库首席架构师20年技术经验分享

华为云开发者联盟

中年危机 经验分享 华为云

一文理解OpenStack网络

华为云开发者联盟

后端 网络

海泰前沿技术|隐私计算技术在医疗数据保护中的应用

电子信息发烧客

畅直播|针对直播痛点的关键技术解析

ZEGO即构

直播体验升级 首帧秒开

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