> For the complete documentation index, see [llms.txt](https://tech.banchengyun.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tech.banchengyun.com/archives/projectmanagement/20201025.md).

# 优秀开发者的第二步：如何阅读他人的代码

近期，云店、知客两条业务线的开发需求正在逐步递增，开发人员也在扩增。那么，当接手一个新的产品时，如何去阅读前人已经写下的代码？以及如何理解已有业务的实现机制？今天让我们一起聊一聊如何阅读他人的代码这个话题。

## 为什么需要阅读他人的代码

我们去阅读他人的代码，通常会带有一定的目的性。完整把一个系统的代码 “读懂” 是需要极大的精力。所以明确阅读代码的目标很重要，因为它决定了你最终能够为这事付出多大的精力，或者说成本。

大致来说，我们可以把目标分为这样几种类型：

* 我要接手并长期维护某个模块；
* 我要给某个模块局部修改一个 Bug（可能是因为使用的第三方模块遇到了一个问题，或者可能是你的上游临时指定了一个模块的 Bug 给你）；
* 我要评估是否引入某个第三方模块；
* 我要以某个开源模块为榜样去学习；

那么，为什么要把我们的目标搞清楚？

我们知道反编译软件能够将精确软件反编译为汇编，因为这个过程信息是无损的，只是一种等价变换。但是要让反编译软件能够精确还原出高级语言的代码，这就比较难。因为编译过程是有损的，大部分软件实体的名字已经在编译过程中被去除了。（当然，可以通过为了 debug 用途在编译过程同时生成的符号文件来跟踪）

我之所以拿反编译过程来类比，是希望我们能够理解，阅读源代码过程：一方面是很难的，因为读懂源代码真的很难，它其实是架构的反向过程；另一方面来说，也是需要有产出的。

> 当然，对于咱们团队目前所遇到的大多数情况，更多的目标是前面三个，这种情况下是已经有了源码仓库，可以直接拿来进行阅读。

那么阅读源代码的产出应该是什么？

答案是：**设计这个产品的程序思路，也可以叫做单模块的架构设计/产品全貌的架构设计**。

## 如何理解架构的核心脉络

**首先，有文档，一定要先看文档。**

如果原本就已经有写过架构设计的文档，我们还要坚持自己通过代码一步步去反向进行理解，那就太傻了。但是，一定要记住文档和代码很容易发生脱节。比如，我们看到的很可能是上一版本的，甚至是最初版本的设计。

就算已经发生过变化，阅读过时的架构设计思想对我们理解源代码也会有极大的帮助作用。在这个基础上，我们再看源代码，就可以相互进行印证。（当然如果发生了冲突，我们需要及时修改文档到与代码一致的版本）

**其次，看源代码，我们要做到的是理解系统的概要设计。**

概要设计的关注点是各个软件实体的业务范畴，以及它们之间的关系。有了这些，我们就能够理解这个系统的架构设计的核心脉络。

具体来说，看源码的步骤应该是怎样的呢？

> 首先，把公开的软件实体（模块、类、函数、常量、全局变量等）的规格整理出来，这一步往往有一些现成的工具。
>
> 当然这一步只能让我们找到有哪些软件实体，以及它们的规格是什么样的。但是这些软件实体各自的业务范畴是什么，它们之间有什么关系？需要进一步分析。
>
> 一般来说，下一步我会先看 example、unit test 等。这些属于我们研究对象的客户，也就是使用方。它们能够辅助我们理解各个软件实体的语义。

通过软件实体的规格、说明文档、example、unit test 等信息，我们根据这些已知信息，甚至包括软件实体的名字本身背后隐含的语义理解，我们可以初步推测出各个软件实体的业务范畴，以及它们之间的关系。

**接下来，我们需要进一步证实或证伪我们的结论。**

如果证伪了，我们需要重新梳理各个软件实体之间的关系。怎么去证实或证伪？我们选重点的类或函数，通过看它们的源代码来理解其业务流程，以此印证我们的猜测。

**当然，如果你能够找到之前做过这块业务的人，不要犹豫，尽可能找到他们并且争取一个交流的机会（请一定提前准备好自己遇到迷惑的问题列表），这会大幅缩短你理解整个系统的过程。**

## 如何理解业务的实现机制

业务系统的概要设计、接口理清楚后，通常来说，我们对这个系统就初步有谱了。如果我们是评估第三方模块要不要采纳等相对轻的目标，那么到此基本就可以告一段落了。

只有在必要的情况下，我们才研究实现机制。刚才我们谈到系统架构梳理过程中，我们也部分涉及了源代码理解。但是，需要明确的是，前面我们研究部分核心代码的实现，其目的还是为了确认我们对业务划分猜测的正确性，而不是为了实现机制本身。

研究实现是非常费时的，毕竟系统的 UserStory 数量上就有很多。把一个个 UserStory 的具体业务流程都研究清楚写下来，是非常耗时的。如果这个业务系统不是我们接下来重点投入的方向，就没必要在这方面去过度投入。

这时候目标就很重要。

如果我们只是顺带解决一下遇到的 Bug，无论是用第三方代码遇到的，还是上级随手安排的临时任务，我们自然把关注点放在要解决的 Bug 本身相关的业务流程上。

如果我们是接手一个新的业务系统，我们也没有精力立刻把所有细节都搞清楚。这时候我们需要梳理的是关键业务流程。

怎么搞清楚业务流程？

> 程序 = 数据结构 + 算法

还是这个基础的公式。要搞清楚业务流程，接下来要做的事情是，把这些业务流程相关的数据结构先理清楚。

数据结构是容易梳理的，类的成员变量、数据库的表结构，通常都有快速提取的方式。

理清楚数据结构，事情就解决了大半。

剩下来就是理各个 UserStory 的业务流程，并给这些业务流程画出它的 UML 时序图。这个过程随时可以补充。所以我们挑选对我们当前工作最为相关的来做就好了。

## 阅读他人的代码是不可或缺的能力。因为：代码即文档，代码是理解一致性更强的文档。
