阅读代码小感

📚入职几周以来主要对接了两个技术需求,为了测试两个技术需求(也为了满足我的好奇心),有去看过相关的代码。第一个需求是sdk,跟头条app相对独立,所以代码看得比较舒服,第二个需求是一个二期技术需求,还得把一期的一些代码甚至头条app的一些基础lib了解一下,看得就比较广,印象浅。

两个需求下来,回顾自己工作以来代码写得其实不多,但是也算看过好些代码,各式各样,有粗有细,再加上网上别人总结的一些方法论,也算有点自己的心得。

一般理解一个程序,首先得知道这个程序是干嘛的,黑盒流程怎么跑,对于稍微规范一点的代码,main函数会大致描述程序的核心功能。规范的代码应该是通过命名自描述的,应该是一个函数只干一个事情,大流程有相对统一的入口,而不是随便抓一个函数就是功能大杂烩,又大又全包含各种i判断分支,面条式代码为什么难读,因为它尝试在一个函数里处理尽可能多的事情,也有可能是作者本身没有抓住流程逻辑的本质而妄想用条件判断来覆盖所有场景。

我看过最舒服的代码,是在函数前写清楚函数的流程步骤,如:

"""
1. 啥啥
2. 啥啥啥
3. 啥啥啥啥
"""
def function_name( ):
  pass

像这样先把函数流程事先解释清楚,然后在一些细节上添加注释,特别是比较trick的步骤或者核心代码上。每一个代码块用两个空行隔开(而不是一个空行)。这样下去几乎都不用看具体代码,看注释就明白在干什么,快速获取我想知道的信息。

在大层面上明白程序的结构和设计思想后,source code的精华已经掌握一半了,之后根据需要再继续往下抓细节,一层一层往里剥,最底层便是学习别人的编码技巧、结构运用和算法思想了。忌讳不抓结构抓细节,只见树木不见森林!

带着问题去读代码,比随意从一个入口往里跳着来读,一般效率会更高一些,可以先在已知的功能代码上寻找阅读切入点,阅读代码先一块一块地读,再一行一行地读,先读自己想读的,再读自己需要读的

看代码时肯定会在一块逻辑里面同时出现好几个需要跳转继续深入阅读的地方,可以先在代码旁边打几个标记(IDE打断点就不错),提示自己读到这里,后续从跳转进去的细节出来之后起码可以快速切换回现场继续往下阅读,而不用花时间找自己先前看到了哪里。

  • 【方法】

有一些代码阅读的方法论,知乎的帖子里有不少人提及到,比较常见的是top-down + bottom-up的结合。首先top-down由上往下一层一层记录函数调用关系,然后bottom-up把底层的函数由下往上阅读(因为越是底层的函数功能越是单一,逻辑越是清晰易辨认),在两种模式间反复切换,不断细化两种模式的理解,最后就能出现比较清晰的代码理解路径。

另一种方法(轮子哥)则是基于文档出发,从文档中了解程序的背景需求后,我们可以去猜代码的实现,猜它怎么解决这个问题,这种方法需要更多的经验和更强的代码能力(反正我还不行😷)。如果没有文档,那就看测试case,因为测试case是基于文档编写的,而不是基于具体代码实现写的。

不得不强调,读代码是一个输入的过程,有输入就得有输出,而阅读笔记、注释就是我们的输出,读代码时做笔记很重要!笔记大大降低回忆复习成本!有时后看了这个文件回去看那个文件忘记了意义重头再看再理解一遍真的很烦!

  • 【步骤】

如果要具体到可操作的步骤,更理想的是:

  1. 搭建环境,将代码跑起来

  2. 利用各种手段进行调试,追踪数据流转

很多时候往往第一步就无法成立,代码来到自己的本地环境跑步起来是常态,干巴巴地读确实有点朴实无华且枯燥。假设真的可以跑起来,我们可以把无关的流程代码忽略掉,尽量缩小自己需要理解的范围,减少心智负担。

打点调试是超级重要的事情!如果不方便断点调试,只要能跑起来,那也可以添加调试日志来对保持数据的跟踪关注。

如果实在跑不动代码,肯定也还有办法,一种是已经十分熟悉程序的功能和黑盒表现,然后以单个场景为基础逐步由点到面地理解代码;另外一种是将要理解的那部分代码函数给抽取出来,mock上下文数据(可以拿原程序运行时产生的真实数据)作为输入,再观察输出来理解代码。前一种方法十分契合QA的工作方式,从单点功能入手慢慢铺开理解面,因为QA对于程序的场景很熟悉,而后者适合用来分析一个复杂的函数流程,知道它的输入输出却不清楚数据的中间状态转化,就可以这样操作。

  • 【工具】

阅读代码需要好的工具, 你拿个记事本来看代码,没人会说你强,甚至觉得你像个山顶洞人,读代码至少得有一个方便跳转的ide或者编辑器,比如Android首选android studio,vscode也比较不错。

ide可以帮你整理出当前符号的声明,查找符号被引用的地方,又可以列出当前源码文件中所有类、函数、成员变量,方便调试时监控变量,jetbrain全家桶公司正版是真的香😂。

个人不推荐为了高大上而强行去玩vim、emacs,编辑器只是效率工具,说到底哪个用得更熟手哪个就更适合,不参与无畏的编辑器圣战,有时单纯为了配置个vim就可以忘记了自己本来要干什么。

  • 【意义】

作为QA,以阅读代码的方式辅助测试,我觉得不用执意去理解代码逻辑细节,而应该以业务场景为单位去一块一块逻辑地理解它,进行“情景分析”,我们不是来白盒找bug的,是为了提升测试效率,避免测试盲点才来读代码,为了读代码而读代码,读了一天代码结果连case都没执行完,得不偿失。

了解了RD的实现,很多本不理解的行为就会清晰了。比如配置下发,为什么要重启app?因为只有重启app时才有配置字段初始化赋值的流程,此时才有机会使得新配置生效;为什么清空数据重启app就crash?因为程序直接使用对象而没有进行判空或者判0长度的操作……这类黑盒有时不太好理解的原因,一看代码有时真的简单得不能再简单,恰恰很多bug也正是这种简单得犯错,越是简单人花的心思就越少,也就越容易犯错,哈哈哈我也有一样的毛病😂。

实践出真知,多写多看多思考,延年益寿身体好!

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2017-2022 Zingphoy Han
  • 访问人数: | 浏览次数:

一块钱一个俯卧撑 O_O

微信