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

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

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

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

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

  • 我要接手并长期维护某个模块;

  • 我要给某个模块局部修改一个 Bug(可能是因为使用的第三方模块遇到了一个问题,或者可能是你的上游临时指定了一个模块的 Bug 给你);

  • 我要评估是否引入某个第三方模块;

  • 我要以某个开源模块为榜样去学习;

那么,为什么要把我们的目标搞清楚?

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

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

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

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

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

如何理解架构的核心脉络

首先,有文档,一定要先看文档。

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

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

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

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

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

首先,把公开的软件实体(模块、类、函数、常量、全局变量等)的规格整理出来,这一步往往有一些现成的工具。

当然这一步只能让我们找到有哪些软件实体,以及它们的规格是什么样的。但是这些软件实体各自的业务范畴是什么,它们之间有什么关系?需要进一步分析。

一般来说,下一步我会先看 example、unit test 等。这些属于我们研究对象的客户,也就是使用方。它们能够辅助我们理解各个软件实体的语义。

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

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

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

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

如何理解业务的实现机制

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

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

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

这时候目标就很重要。

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

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

怎么搞清楚业务流程?

程序 = 数据结构 + 算法

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

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

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

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

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

最后更新于