前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自己维护的代码都读不过来,还需要看开源社区的代码么?

自己维护的代码都读不过来,还需要看开源社区的代码么?

作者头像
tyrchen
发布2022-03-29 10:13:14
4240
发布2022-03-29 10:13:14
举报
文章被收录于专栏:程序人生程序人生

最近后台有个同学问阅读源代码的问题。他说感觉自己团队维护的代码都看不过来,还需要看开源社区的代码么?

我的回答是:一定要。两个原因:1) 团队维护的代码受限于团队的水平,构建过程中的各种赶工,以及不断堆叠的业务逻辑,质量可能不高;2) 因为架构模型,设计模式以及业务范围的束缚,如果只了解团队内部的代码,那将会是井底之蛙,眼界非常狭窄。

要不要阅读源码,以及如何阅读源码是个很普遍的问题,今天就展开讲讲。

为什么我们要阅读源码?

程序员每天都和代码打交道。经过数年的基础教育和职业培训,大部分程序员都会「写」代码,或者至少会抄代码和改代码。但是,会读代码的并不在多数,会读代码又真正读懂一些大项目的源码的,少之又少。这种怪状,真要追究起来,怪不得程序员这个群体本身 —— 它是两个原因造成的:

  • 我们所有的教育和培训都在强调怎么写代码,并没有教大家如何读代码
  • 大多数工作场景都是一个萝卜一个坑,我们只需要了解一个系统的局部便能开展工作,读不相干的代码,似乎没用

我常常把写代码和写作进行类比 —— 二者有很多相通之处;但从培养写代码和写作的过程来看,二者又有很多不同。我们的写作能力,是建立在大量基础阅读的基础上的,是除了学习语法和文法知识外,从小学开始,经年累月,通过阅读各种不同层次的名家的作品,再加上各种各样的写作训练,累积出来的;而我们的写代码的能力,在了解和掌握了语法/文法之后(学习和抄写 example 代码也算语法/文法学习的一部分),跳过了大量阅读名家作品的过程,直接 biu 地一下就自动养成了:学会基础的语法和试验了若干 example 后,我们就火箭般蹿到了自己写代码打怪攒经验的阶段。略过了大量阅读代码的阶段有三个害处:

1. 写代码的基础是不牢靠的,打怪升级的过程也是最慢的。道理很简单 —— 前辈们踩过的坑,总结的经验教训,你都不得不亲自用最慢的法子一点点试着踩一遍。

2. 很容易养成 stackoverflow driven 的写代码习惯 —— 遇到不知如何写的代码,从网上找现成的答案,找个高票的复制粘贴改吧改吧,凑活着完成功能再说。写代码的过程中遇到问题,开启调试模式,要么设置无数断点一步步跟踪,要么到处打印信息试图为满是窟窿的代码打上补丁,导致整个写代码的过程是一部调代码的血泪史。(见我的文章:)

3. 编码水平的上限就是你周围最强的那个工程师的上限。

我们再回到读书。

从小学到高中,就语文而言,12年时光,单单课本我们要读十二册,数百篇文章。如果每篇文章平均一千字,那么我们读了数十万文字。这些文字,我们是精读过的(有些甚至要求全文背诵)。每篇文章我们需要总结中心思想,段落大意,归纳出论点论证论据或者时间任务地点起因经过结果,会分析长句难句,会学习起承转结,并反复训练基础的遣词造句能力,并最终模仿那些文章写出自己的文章。在这个过程中,我们学会了赋、比、兴,我们掌握了三段论,我们知道了如何用更优雅的方式表达自己的思想。更重要的是,这些阅读训练让我们在我们在脱离学校的基础教育后,可以自己独立完成一本书的阅读。我们不再依赖老师或者参考书为我们给出段落大意,中心思想,我们知道如何粗读,细读甚至类比阅读一本书,我们能把书中的精髓浓缩成思维导图,也大段大段摘录书中精彩的句子,段落或者篇章。

这十几年的时光,算上各种课外阅读,世界名著,古典文学,金庸古龙,修真玄幻,一个大学毕业的二十几岁的青年人,阅读量应该不下几百万字。而稍稍涉猎广些的读者,上千万字的阅读累积是常有的事。有了这些累积,你才能在迎面走来一位妙龄女子,想到的是肌肤胜雪,明眸善睐,桃腮带笑,齿如含贝,气若幽兰,美艳不可方物,一笑倾城,再笑倾国,沉鱼落雁,闭月羞花这些词句,而非不知如何表达,只能吞吞口水,在肚子里闷上一句:「我擦,美女」。

这是读书的第一大功用:累积素材(information)。你是否写文章时,经过一番搜肠刮肚,也不知该如何描述某事某物?同样的,写代码时,有没有毫无头绪,不知从何写起的时候?或者有了写作的思路,双手却在键盘上迟滞,不知所措?这些现象,大多是缺乏累积所致。

读书的第二大功用:开拓思路。有时候,一段文字,甚至一个句子,在你意料之外扑面而来,让你有种醍醐灌顶的感觉。比如『围城』里,赵辛楣和方鸿渐鸿初次见面,钱老描述赵的傲慢无礼,是这么写的:「傲兀地把他从头到脚看一下,好像鸿渐是本一览而尽的大字幼稚园读本」。初读围城的时候,我关注点是其故事性,将这样的句子轻易放了过去,几年前再读时,才发觉它的精妙:竟能如此简单地以物喻人,就把整个场景复原到如同发生在我的面前一样活灵活现。随后,我自己的文字里也模仿着,有时甚至刻意地如此这般使用比喻来增强画面感。前些日子偶尔再读到这句,因我有了给女儿读幼稚园读本的经验,不由得莞尔一笑,旋即明白了一个道路:精妙的不是比喻本身,而是对生活的细微观察

上个月,我用 Rust 写了个几千行的小项目 wormhole,做了一个高度可配置和可定制(集成了 rhai 脚本)的 proxy 服务器。其中,内部的很多 trait 的设计,都源自于我从 tower,axum,nom 等项目源码中学到的经验。

有时候,你读源码受到的启发可能一下子不会找到使用的场景,就像我上一篇文章中介绍的 axum 如何使用声明宏 + 泛型 + trait 构建出可以媲美动态语言的 API 使用感受,在惊叹之余,很可能自己手头的项目并不能很快找到这样的精妙设计的用武之地。但是不要担心。就像乔老爷子说的那样,珠子总有一天会被串起来的。就像张无忌小时候在冰火岛背诵的那些心法口诀,学的时候固然枯燥,但时机到了,小时候摇头晃脑背下的那些篇章就能涌现出来。我在 wormhole 里 data plane 构建的 pipeline 的思路,就要源自数年前,我在读 elixir plug 源码的时候,学习到的思想。

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

information -> knowledge -> wisdom 是个长期的累积,并非一朝一夕之功。阅读名家的优秀的代码最终的归宿是形成你自己写代码的思路。

如何阅读开源社区的代码呢?

如果你接受了上面的「一定要尽可能多的阅读优秀的源码,就像阅读优秀的书籍那样」的观点,那么下一个问题自然是:如何阅读别人的代码?

首先是要学会甄选合适的代码库。这就跟我们选择合适的书去阅读一样。一个还不具备高级阅读能力的人去啃 linux kernel,必然会栽个大跟头。在我看来,和工作相关的,在工作中用到的开源项目的依赖,是我们需要优先去阅读理解的内容。我在使用 Rust 的时候,基本上,用到的 crates,我都会去扫一扫源代码。

我阅读的顺序是这个样子的:首先,看项目的 readme 和发布的文档。如果一份代码没有高质量的 readme 或文档,那么就不着急细看,在使用时,把遇到的接口的定义,以及这样定义背后的逻辑搞清楚就好。

如果项目的文档不错,那么,可以顺着文档找自己感兴趣的地方,进一步了解这个项目。我很喜欢 rustdoc 的一个很大的原因,就是文档和代码,尤其是接口代码的关联度很好,可以来回跳转,缩短我阅读的时间。如果我感觉代码的质量不错,某些设计激起了我的兴致,那么我会走到第三步:git clone,把代码复制到本地细细品味。

git clone 的好处是,你可以摆脱网页跳转的种种束缚,在你自己钟爱的编辑器中阅读代码。此刻,代码的细节就一览无余,很容易陷入到细节的纷扰中。我们在阅读书籍的时候,是一个线性的过程,一般读完一个章节再到下一个章节,很少有在章节之间反复跳跃的。但阅读代码的时候,如果不注意抓住主线,那就会陷入无穷尽的跳转之中,在代码的汪洋中迷失掉。所以,我会围绕着具体的场景,每个场景一条主线,尽可能控制分支地阅读。阅读的过程以接口的设计,接口和接口之间的交互为主,并且随时准备好 excalidraw 绘制当前场景的流程,所以,一个场景的代码阅读得差不多,这个场景下的流程图也出来了。这样的阅读方式,可以快速掌握代码的结构。

大部分同学估计工作都很忙,能把工作过程中遇到的依赖一个个啃下来就不错了。当然,肯定还有学有余力的同学。如果工作中遇到的值得读的开源依赖都搞定了,还能读些什么呢?

我的建议是围绕着你做的产品的整个架构,寻找这个架构中你不了解,但又感兴趣的部分,找对应的优秀的开源项目去学习。比如作为一个后端工程师,你可能维护一个内部的管理系统的 REST API。当你有余力的时候,可以从一个 API 的生命周期中遇到的所有场景中,选择你感兴趣的内容。API 离不开网络,那么,自然,相关的网络协议值得了解,对于 Rust 而言,涉及到的开源代码有 tokio,hyper,甚至 quinn(http3)。网络之上是安全,安全协议及相关的算法,就足够折腾很久了,比如处理 TLS 的 rustls,处理 noise protocol 的 snow,以及它们背后的哈希算法,对称和非对称加密算法等等。安全之上是授权,oso / casbin 都可以看看。网络传输过程中涉及到序列化反序列化,那么在 serde / serde-json 的基础上,是不是还可以再研究一些其它的序列化反序列化方案,着重了解一下它们的使用场景和优劣?再往后,数据的存储,缓存的方案,系统的 telemetry 的收集(以及整个 OpenTelemetry 体系的架构)等等,一个小小的 API 就可以让你有足够的广度和深度去探索,更别说从整个产品的角度去探索。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-02-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序人生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么我们要阅读源码?
  • 如何阅读开源社区的代码呢?
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档