[知乎回答]如何提高阅读源代码的能力?

谢邀,这是一个非常好的问题,也正是我想要认真思考,然后回答的问题!

@johnniechau 推荐的《代码阅读方法和实践》,是一本好书,我只打算在这里简单的聊一聊自己的经验与思考。

我们先假设一种最恶劣的状况,你被迫接手一个遗留项目,原来做项目的家伙,全都四散逃亡了,不但没有任何说明文档,而且还找不到人,老板给你一段并不宽裕的时间,你得读懂他们的代码,然后接着维护……通常,这是噩梦的开始。

当然,从提高能力的角度而言,这是一个好机会。所以,@刘立 虽然只说了两个字“压力”,我认为的确正中要害!

我们可以用拼图这样的游戏,来做一个比喻。一地的碎片,你如何将他们尽快的拼在一起?

  1. 寻找边角的块(除了四边都是凹凸的块之外,其他有一到两条边是直线的块,会少得多,也更容易辨认与拼接。)
  2. 将碎块按大的色块分类,从一次查找,变成二次查找。
  3. 一开始碎块最多的时候,是最困难的时候,需要足够的耐心、细心,以及一点点的运气。
  4. 如果你的记忆力足够的好,碰到的碎块能够在脑子里留下一定的印象,那么有助于你快速找到匹配的碎块。
  5. 经验能够帮助你提高效率,熟能生巧。

回到代码阅读,我们来做一个类比:

  1. 寻找代码中最明显的入手处,比如main函数,core文件夹,model、view、controller的三种大类等等。
  2. 从理解文件夹、文件名开始,而不是一上来就埋头进入源代码之中。
  3. 一个好的全文搜索工具,能够帮你找到相关的代码与片段,渐渐的,看起来一团乱麻的代码,就会显现出各种可以被理解的关联出来。
  4. 记忆力总是有用的,在脑子里绘出整个系统的架构,并且补充越来越的,越来越清晰的细节。
  5. 一样是熟能生巧。
  6. 相比拼图,代码阅读还要容易一些,你不需要理解全部的代码,有一个大致的理解以后,就可以先放过一些不太重要的细节。

另外推荐阅读我目前正在写作的一份文档《借助开源项目,学习软件开发》——第五章:理解开源项目:link
引用较为相关的一段在下面,供参考:

5.5. 知其所以然
有一句俗语叫做:“知其然,更要知其所以然”。用在任何学习科目上,几乎都是恰当的。本章叫做《理解开源项目》,而之前的4个小节,可以说都是属于“知其然”的功夫。如何才能知其所以然呢?

所以然包括哪些内容?
往大了说,整个这份文档,希望帮助读者达到的,就是能够对于开源软件“知其所以然”。这样才算是真正提高了软件开发的能力。因此,我们可以将“架构决策”、“代码风格”、“领域知识”、“编程技巧”等等内容,都算作是所以然的一部分。
架构决策 通过深入阅读和分析源代码,理解整个项目,为何像这样,而不是那样做架构设计。其间蕴含着项目作者的经验和智慧,理解了这个,将是一种巨大的收获。
代码风格 每一种语言、每一个社区、每一个开发者群体,甚至每一个开源项目,都有其独特的代码风格,这种风格,有其背后的合理性,也有很多是来源于某种开发哲学的思 考。理解一种代码风格,就是理解一种思考的模式,一种思想的体系。能够多了解一些不同种类的代码风格,对于提高软件开发能力,将有很大的帮助。
领域知识 有些代码不容易看懂,很重要的一个原因,是这个项目所涉及的领域,我们没有什么深入的了解。多年的程序员经验告诉我,要做好某一个行业的软件,一定要成为 某一个行业的内行。甚至要比那个本行业的业内人士,更加精通。因此,一个优秀的程序员,通常是能够跟你聊多个不同行业的话题的。强大到你几乎无法分别他的 是不是业内人士。因此,通过理解开源项目,进而理解相关的领域知识,会有很多收获。
编程技巧 阅读优秀的开源项目的代码,有时候很像是看一本好书。细细品味,慢慢的体会。我们会发现一点一滴的“妙处”。这些妙处凝聚了程序员的巧思妙想,能够体会得越多,对我们的帮助也就越大。

所以然还包括的一些内容:
个人偏好 开源作者也是普通人,他们有很多观点和取舍,未必能够说服他人,只能算是他们自己的偏好。而他们将自己的偏好表达在代码里,有些时候,我们能够很容易理解 (因为我们也是这样想的)。有些时候,我们就会感觉很不解,而且,常常会发生的一类故事就是:某某大牛写了一个开源项目,另一个大牛有感觉不爽的地方。提 了意见建议,人家又不肯改。结果,这另外一个大牛,就一怒之下,另起炉灶,写了一个新的开源项目。
历史原因 有一篇很有意思的文章,解释了《为什么Vim使用HJKL键作为方向键 》,其实原因很简单。当Bill Joy创建Vi文本编辑器时,他使用的机器机器是ADM-3A终端机,这机器就是把HJKL键作为方向键的。

如何搞清楚这些所以然呢?
思考 当然,这种思考应该伴随我们“通过开源项目,学习软件开发”的始终。但是,从方法论来说,可以尝试从以下一些角度出发来思考:

  • 如果我来做一个,会如何去做?
  • 如果能够对这个项目做减法,我可以去掉那些模块和代码?真的能够去掉吗?
  • 通过阅读单元测试,理解开发者的设计思路。
  • 尝试做一些破坏或者修改,来理解项目中的那些做法。这个在下一章会更详细的讨论。

讨论 到开源社区去,发起一些讨论。当然,前提是你必须经过足够深入的思考。不要尽是问一些傻问题
向作者提问 与上面的讨论类似,前提是要先思考。当然,还有一个讨巧的办法,你可以提出:翻译这个开源项目的英文文档,然后,对方当然会很高兴——国际化了嘛。然后,你可以在翻译的过程中,提出各种各样的问题。。。
阅读指南 有些著名的开源项目,本身也非常复杂,所以会有一些文档与书籍:linux内核代码分析、MySQL源码解读、PHP源码分析等等。如果有心学习这样的大 型开源项目,这种入门指南,也是很有价值的。但是,这毕竟是别人嚼过的饭,肯定不如自己去啃来的香。所以,还是回到那句老话,源代码才是最有营养的。

与12306相关的一些思考

铁路购票的12306网站,我也在上面购买过火车票,虽然的确存在着各种各样的问题,但是最终确实成功的买到了票,而且也顺利的坐上了火车。也许因为不是在春运期间购买的缘故,说实话,我对它的印象没有那么糟糕。

当然,如果我们看看网络上的新闻,搜索微博里的各种人对12306的批评、责骂与嘲讽…是的,他们做得糟透了。
但是,在我看来,痛骂他们的技术如何垃圾,并没有追踪到问题的本质,本文试着继续深入的追究下去。

一、不要外包

分布式系统的第一原则是:不要分布式!而外包系统的第一原则是:不要外包!前一句,有很多高人说过,后面这一句,是我杜撰的。而我之所以会提到这个问题,是因为网络上有很多类似的观点,似乎是因为这次的外包开发没有找好,如果将这个活包给淘宝、支付包、京东、亚马逊之类的大型成熟电商来做,就万事大吉了。事实上,这些成熟电商之所以成熟,恰恰是经过了长期的改进完善之后的结果,而且,一定是他们自己的开发团队完成的。另一个近在眼前的例子,想想苏宁易购吧。直接一点说,如果这事外包给淘宝来做,就算淘宝有人有时间也愿意接这个活,也肯定干不好。

为什么外包通常搞不好呢?因为他们不是自己人,他们没有跟着一个企业同步成长的体会。因为他们希望获得整理明白后的一本“需求汇总”,他们害怕反复不断变动的需求。当然,我这个观点,可能存在着某种偏见,但是,越是变动复杂,极其核心,影响巨大的系统,我都强烈的不建议交给外包来完成。

二、循序渐进

一个非常庞大的电商网站,都不是一天建成的,淘宝不是一天建成的,亚马逊、京东也不是一天建成的。我们怎么能够希望12306在第一次推出的时候,就能够支撑春运购票这样变态的需求呢?

为了限制需求,其实可以有很多种办法:比如限制特定的班次(只卖高铁票、卧铺票、只卖从起点到终点的票等等)、比如网络购票加价,比如只在平时提供使用而不是在春运期间投入使用。总之,不需要一开始就服务所有的用户,选定一个较小的范围,先服务好,再循序渐进,逐步扩大服务的范围、提升服务的效率与质量,才是较为稳妥的办法。

三、排队系统

在12306网站推出之前,我们的购票体验同样糟糕,客观的说,只怕更糟。但是为什么反而没有什么人来骂呢?很多人在说,因为12306的用户体验做得不够好,但是我想要反其道而谈之。如果网站的用户体验能够像当初的实际购票一样差,只怕反而更加好一些。

回顾一下传统的购票流程吧:来到购票大厅,首先要选择一个窗口排队,运气不好的时候,自己选择的那一队恰恰是最慢的。经过几个小时甚至十几个小时的排队,我们来到了窗口前,遇到的是心烦意乱的售票员大妈,她们通常态度恶劣却动作迅速,到哪里?没有!卖完了!只有站票了,要不要?不要就换下一个!看清楚了吗?确认我就出票了。

窗口前的购票者,在身后巨大的目光压力之下,在面前不耐烦的语言压力之下,做着迅速的购买决定。这种购票体验,真的是太烂了。唯一的好处是:当我们拿到了那张纸片,就放下心来,肯定能回家了。

假设,我们一开始就把12306做成一个售票大厅的模式,总共就100个窗口,每个人都登录以后先排上10个小时的队,一旦排上了,轮到自己了,购票时间不会超过2分钟。那么,虽然是漫长的10小时的等待,却不需要时刻守在电脑前站着。这种体验,我想就足够了。

从12306的角度而言,完全可以将系统按照每个城市一个售票大厅的方式来部署,一开始假设只有100个窗口,人再多也是这么排着。等到系统稳定了,能力上去了,再慢慢的增加窗口的数量,缩短排队的时间。痛骂的人,将会少很多很多。原因很简单,不要一开始就给用户一个很高的期待值,然后再让他们失望,而是基于现状,小步快跑的做着改进。反而会有较好的效果。

这种做法,其实在网游行业是基本常识,随着用户数量的增加,新增一组一组的服务器,以容纳更多的玩家,而不是一开始就放开让所有的人进来玩。宁可不让他们进来,也不是让他们进来以后,在游戏场景里玩排队的游戏。

四、代售机制

火车票代售网点,其实在很多年前就已经出现了。我认为这个模式其实很不错,是一个分散客流提高效率的好办法。假设,我们不做12306的网站,而是开办成千上万,甚至上百万的火车票代售网店,情况会变成什么样子呢?假设,我们降低火车票代售点的准入门槛:交XX万押金,下载一个代售点客户端,自备电脑,自寻场地,自寻客源,自己去做生意。搞一个简单的审批流程,每年新增批准10万个个体户代售点。

这样的好处是:每个企业,每个公司,每个街道办事处,都可以自己申请成为一个代售网点,然后解决身边人购票的难题。在最大限度内,减少集中排队的压力。另一方面,由于审批流程可以控制代售点的数量,同时也就保证了系统的压力始终以可控的方式增长。

我在内心默默推理了一下,似乎是一个较为简单可行的办法。

五、抓大放小

说起用户体验糟糕,每个人都可以滔滔不绝的说很多话。我们常常会看到这样一种言论:铁道部的官员,他们用12306吗?如果他们也用,难道不会更加促使12306网站更快的改进吗?

其实,从技术人员的角度而言,怕的就是大老板亲自抓用户体验。当然,比这个更加糟糕的,则是每个领导,都对用户体验,说三道四。

对于12306的改进,我想不必过于关注细节,追踪一些统计数据的变化情况就好。比如:平均购票等待时间;退票率与废票率;列车上座率等等。至于如何提高这些数据,领导们千万不要事无巨细的参与讨论,大家各自努力就好。有更多的事情得靠领导们努力:比如切实提高运力…

六、架构演进

在网络上,我们常常能够看到很多给12306支招的方案,总之各种前卫,各种先进。但是,在我看来,越是复杂的系统,越是怕这种“革命”,哪怕过去的架构再不合理,也最好不要贸然引入过于激进的架构,在原有的架构下逐步演进,逐步扩展,逐步寻找小范围的、能够被改进的点来推进,才是较为合理的做法。

我能够看到的很多对于12306的批评,常常是一直站着说话不腰疼的姿态,说实话,并不可取。就目前来看,我们最乐观的估计是,12306能够顶住压力,逐渐改进、完善,在3~5年之后,渐渐淡出人们的视线,成为一个普通的,日常必须使用的,生活服务类网站。