RTFSC

  • WHY
  • HOW
    这篇仅仅是参考原作者的观点,进行一次总结。

WHY

  • 为什么应该重视代码?

    • 任何程序员,操起键盘就能写(不管写得好与坏)。但会(擅长)读的人不多,究其原因:
      • 没人教:教育只教了如何写,而没有教读。
      • 没有“用”:至少在低层次、大多数工作岗位上因为工作是局部展开的似乎没有读得必要。
  • 读源码的好处

    • 在你无法了解一件事本质的时候,类比是比较好的方法快速了解这件事。对于写代码,我们用写作去类比,那读代码很显然就用阅读文学做对比。任何人都能写出一点东西来,而在写作的质量、是否言之有物方面就天差地别了。想象一下我们成为一名出色的作家的必要条件:
      • 大量阅读。好处(开阔眼界(Information, “Know you don’t know”),引发思考)
  • 传统成为好的作家的路线:

    • 学习文法/语法 —> 大量阅读不同层次的大家的作品 —> 学习模仿改进 —> 形成自己的文学风格(创新)
  • 我们大多数人学习编程的路线:

    • 学习语言的语法特性 —> 写自己的代码

从上面的路线上,大概都看出不同来了。那缺少大量阅读这个过程会带来什么样的危害?

  • 写代码的基础不牢靠,打怪的过程也是最慢的。— 前辈踩过的坑,总结的经验教训,你依然得再踩一遍。

  • OSP(面向StackOverflow编程),遇到问题,查找stackoverflow,copy+paste。各种怪异的变成姿势(面向print/breakpoint/ide编程,冗长的调试各种丑陋的打印信息)。

    从小学到高中,就语文而言,12年时光,单单课本我们要读十二册,数百篇文章。如果每篇文章平均一千字,那么我们读了数十万文字。这些文字,我们是精读过的(有些甚至要求全文背诵)。每篇文章我们需要总结中心思想,段落大意,归纳出论点论证论据或者时间任务地点起因经过结果,会分析长句难句,会学习起承转结,并反复训练基础的遣词造句能力,并最终模仿那些文章写出自己的文章。在这个过程中,我们学会了赋、比、兴,我们掌握了三段论,我们知道了如何用更优雅地方式表达自己的思想。

    累积素材是基础,被启发出来的思路将这些素材串成线,这就形成了知识(knowledge)。书读得越多,越勤于思考的人,知识也就越丰富。而知识的融会贯通,最终形成读书的第三大功用:通过了解,吸收别人的思想,去芜存菁,最终形成自己的思想,或者说智慧(wisdom)。information -> knowledge -> wisdom 是个长期的累积,并非一朝一夕之功。

HOW

阅读源码的三大目的:

  • 为破案而阅读
    在使用开源代码(别人的),而文档、google、sof、论坛都无法给出完美解答,此时只能看代码了。此时抽丝剥茧般的顺摸瓜。这个时候的战略:

    • 问题为导向,忽略杂音(unrelatively)。这个时候尤其注意时刻把握你的问题是什么,防止跌入细节的深渊。
    • (文件名,类/函数名,变量名)。这个过程【猜】很重要。(打印调试信息是印证猜测(反馈),不要瞎设置打印地址)

    拿我遇到的 nginx cache 的问题来举个栗子。一年前,当我接手 Tubi TV 的性能较低且很难维护的 API 系统后,虽打定主意日后重写,但摆在面前的,刻不容缓的问题是提高性能(note:遇到问题)。应用层可以施展的空间不大(数据已经在 redis 里),所以只能在 web 层打主意(定位问题所在)。在 HAProxy 和 nginx cache 之间,我选择了后者(凭借知识储备做出选择), 因为 nginx 已经在当时的生产环境下大量使用(选择原因)。我虽然没用过 nginx cache,但启用 nginx cache 并不是难事,照着文档设置好 cache 的路径和大小等参数后,在需要使用 cache 的 location 下,设置 cache key 并使能即可,我本地的简单的测试运行正常。然而,在生产环境中,本该命中的请求却一直处在 miss 的状态(测试、遇到新的问题)。我一筹莫展,尝试了网上搜到的各种方案无果。最终,我决定自己编译一个打开 DEBUG 开关的 nginx 版本(–with-debug),记录更多的日志(log记录错误信息(注:log的打印位置也需要认真设计)),然后对着源码找问题。nginx cache 及 upstream 里和 cache 相关的代码量并不算多,几千行,我快速过了一下,然后就着日志上的内容寻找相关的处理流程,并在几个大的 bailout 分支猜想可能出现的情景。由于 nginx debug log 还是不够详细到满足我的需求,我在这些没有被顾及到的分支上各自加了调试代码(增加信息量),重新编译,运行。

    • 编译运行修改过的程序,复现问题(concurrency在这方面比较麻烦),分析调试信息,答对进入第5步。
    • 每答对,restart!

      喜悦是短暂的,记忆也是短暂的。整个过程你的目标是如此清晰,执行力无比强大,为达到目的「不择手段」。三天后老板问你,小程啊,你很棒啊。你用了什么手段征服了这个无比难缠的八阿哥?这时你拼命追忆,却像拿筛子盛水,忙乱半天一无所获。你开始怀疑人生:三天前的我和现在的我究竟是不是一个人?

    • 复盘 (迈向砖家之路)

      • 关键代码,关键路径,到达终点的整个猜测过程,以及那些日志验证了猜测是对的,哪些日志验证了猜测走不通(恭喜你 —— console 或者 terminal 在这个时候应该还没关),总之,你在不择手段的过程中用过的一切手段,都应该像记流水账一样记录下来。
      • 总结
        • 这个问题的 root cause是什么?
        • 读代码过程中,哪些我猜对了,哪些没猜对?
        • 有功夫的话,哪些代码值得细细品读把玩?
        • 下次再出现,我应该怎么更快地从源代码中定位出问题?

  • 为明理而阅读
    • 何谓明理?读的那些专业书是不是觉得似懂非懂?RTFC!!!
      • 算法:red black tree是如何实现的?filter?backtracking的过程到底是怎样的?
      • 基础知识:socket为什么尽量不使用stdio?mmap/munmap 与 malloc/free的区别是什么?malloc内部又是怎么实现的?什么是dynamic content on web,web server如何执行可执行文件的?
      • 理论:啥是exceptional control flow?
    • 你读的越多,收获的知识点越多,心中的疑问越多,越知道自己不懂什么(know you don’t know)
    • 这代码有可以优化的地方么?有潜在的安全漏洞么?是否有未处理的状态或者异常?
  • 总结一下:
    1. 先使用前面所述的检视阅读法把整个代码过一遍,找到值得阅读的核心代码。

    2. 粗读这部分代码,将其内容进一步 breakdown。手边准备好笔和纸(或者其他趁手的工具),随时记录。记录最好的方式是图表。这个阶段的记录不建议用软件工具(除非有用着特别舒服的,能够人件合一的)。

    3. 精读这部分代码,结合你已有的知识,理解这个代码所需要的资料,猜测和还原代码中某种事件,消息,或者某个流程发生的场景。把猜测记录下来。这时,如果遇到外围的代码(调用了外部的函数),只要对理解不产生障碍,可以先放一下,把整个过程完整而详细地捋一遍再说。这个过程一定要多问问题,把「我以为我懂了但实际没懂」的情形尽可能减少。

    4. 用检视阅读法粗度剩下的代码,如果找到其他值得精读的代码,跳至 2。

    5. 使用对比阅读(或者说,主题阅读)方式,把类似功能的 repo 都扫一遍。尝试着用自己的语言消化不同作者的实现,关注其实现的差异,并试图评判这种差异。

    6. 用软件将手稿电子化,便于将来回顾。文字可以直接上笔记本工具(甚至可以尝试 gitbook),图表如果买不起 visio,omniGraffle 这样的工具,可以用 plantuml。使用方法参考我的文章:那些年,我追过的绘图工具

可以用来读leveldb的代码,从中可获得的好处:

  • 检视阅读法读文件的组织方式、命名方式。(如何构建一个工程)

  • 读文件的文档,了解整体架构。找到值得阅读的核心代码

  • 选定要读的模块,从测试函数读起(他想干什么?)。main

    • 测试一下,修改一下,查看反馈(先想好逻辑),精读这部分代码,结合你已有的知识,理解这个代码所需要的资料。
  • 猜测和还原代码中某种事件,消息,或者某个流程发生的场景。把猜测记录下来。这时,如果遇到外围的代码(调用了外部的函数),只要对理解不产生障碍,可以先放一下,把整个过程完整而详细地捋一遍再说。这个过程一定要多问问题,把「我以为我懂了但实际没懂」的情形尽可能减少。

  • 用检视阅读法粗度剩下的代码,如果找到其他值得精读的代码,跳至 2。

  • 使用对比阅读(或者说,主题阅读)方式,把类似功能的 repo 都扫一遍。尝试着用自己的语言消化不同作者的实现,关注其实现的差异,并试图评判这种差异。

  • 用软件将手稿电子化,便于将来回顾。文字可以直接上笔记本工具(甚至可以尝试 gitbook),图表如果买不起 visio,omniGraffle 这样的工具,可以用 plantuml。使用方法参考我的文章:那些年,我追过的绘图工具


  • 为能力跃迁而阅读
    这种积蓄能量为跃迁准备的一种方式是读代码。读什么?读那些基础地不能再基础,你认为自己一辈子都不会去写的那些代码。比如 linux kernel,比如 OTP。这种读法,你不知何时能够完成,所以,要有足够的耐心和时间。检视阅读 + 主题阅读 + 思维导图是经常用到的方法。
    • 粗读 + 精读
    • knowledge gap都是你提升的地方。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值