写点什么

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

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

评论

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

阿里P8大牛手写《亿级流量并发手册》GitHub下载榜飙升至第一

退休的汤姆

Java 程序员 面试 社招 秋招

何止一个惨字形容,水滴Java面试一轮游,壮烈了,问啥啥不会,数据库血崩,我该怎么办?

钟奕礼

Java 编程 程序员 后端 java面试

MASA Stack 第四期社区例会

MASA技术团队

.net 云原生 dapr blazor MASA

佛山等保测评机构有哪些?怎么做?

行云管家

等保 等级测评 佛山

华为云咨询携手商业伙伴探索咨询业态升级

宇宙之一粟

数字化转型 8月月更

开源一夏 |为什么BigDecimal比较大小一定要用compareTo

六月的雨在InfoQ

开源 equals BigDecimal 8月月更 compareTo

软件测试 | 测试开发 | APK 逆向工程 - 解析 apk 基本信息和方法调用图

测吧(北京)科技有限公司

软件测试 测试 APK

华为初面+综合面试(Java技术面)附上面试题

钟奕礼

Java 编程 程序员 java面试 后端架构

云监控是什么意思?哪个软件好?

行云管家

云计算 云平台 云监控

软件测试 | 测试开发 | 利用 pytest 玩转数据驱动测试框架

测吧(北京)科技有限公司

pytest

阿里P8架构师汇总了史上101个最牛逼的Java技术点

钟奕礼

Java 编程 程序员 架构 java面试

Java:将Excel转换为XPS

Geek_249eec

Java Excel XPS

软件测试 | 测试开发 | RPC接口测试技术-Tcp 协议的接口测试

测吧(北京)科技有限公司

TCP/IP

MobTech 短信验证Android端 API

MobTech袤博科技

android

华为大数据开发平台 DataFactory 行业应用典型案例

宇宙之一粟

华为云 大数据技术 8月月更

数字藏品系统开发:(开发NFT数字藏品源码)

开源直播系统源码

NFT 数字藏品 数字藏品系统

单测增量代码覆盖率统计方案

转转技术团队

测试 测试覆盖率统计工具

表弟面试阿里又挂了,我强烈推荐程序员必备阿里面试的300+面试题(含答案解析)给他后,苦肝两月,成功上岸蚂蚁金服

钟奕礼

Java 编程 程序员 java面试 技术宅

企业应用现代化实用教程 | 微服务架构怎么选?Dubbo、Spring Cloud、Istio终极对决

York

微服务 云原生 Spring Cloud istio Service Mesh (ASM)

全球首创!网易伏羲提出135种人脸表情划分标准,荣登IEEE官网

网易伏羲

人工智能 IEEE 网易伏羲

软件测试 | 测试开发 | MockServer 服务框架设计

测吧(北京)科技有限公司

软件测试

软件测试 | 测试开发 | 文未有福利 | 接口自动化你不懂?听HttpRunner的作者怎么说

测吧(北京)科技有限公司

HttpRunner

APP上架因收集个人信息问题被拒绝该怎么解决?

YonBuilder低代码开发平台

程序员 技术 App 信息安全

leetcode 409 Longest Palindrome 最长回文串(简单)

okokabcd

LeetCode 算法与数据结构

Spring源码解析(五)Spring 加载bean 依赖注入

石臻臻的杂货铺

spring 源码 8月月更

长安链p2p-Liquid学习笔记

长安链

基于 LowCodeEngine 的调试能力建设与实践

阿里巴巴终端技术

前端 低代码

面试 | 百度测试开发岗位面试题目回顾

测吧(北京)科技有限公司

面试‘

微服务日志监控的挑战及应对方案

穿过生命散发芬芳

日志监控 8月月更

Spring源码分析(六)FactoryBean 接口解析

石臻臻的杂货铺

spring 源码 8月月更

软件测试 | 测试开发 | 专项测试技术初识Hook

测吧(北京)科技有限公司

软件测试 hook

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