最近在看Twitter的Oauth2的库的源代码(simplegeo/python-oauth2 · GitHub),看不进去啊...整个库有些自成体系的感觉,看上去联系很紧密,所以从哪里开始看都不方便。从上往下看代码的话,肯定会被各种函数看晕。从main()开始看的话,也会被好多层的调用搞晕。因为之前对Python的Http请求的库并不熟悉(如httplib2, requests),经常会需要看一下其它库的一些内容,更晕了...
现在总是觉得自己明白大致的流程,但总有大段的函数看不懂,结合文档看也总有很多地方不明白。自己就是想看明白一些,然后对这个库做一些改进(因为有些API的Oauth流程和其它API的有区别,所以我想改进一下Oauth的过程)。但现在的理解程度,完全达不到这个要求啊...(这两天找到了一个新的库,可以满足我的要求,但我还是想搞明白怎么读代码比较好...)
各位资深的程序员们,我应该怎么做才好呢...
回复内容:
先看文档,再看单元测试。
Code Reading (豆瓣)
(副题是 The Open Source Perspective,适合题主需求)
代码阅读 (豆瓣)
(中译本)
之前也是读代码很慢,后来代码写的多了读这些开源项目的速度就明显快了。
读代码慢就是对常用函数和常用库不熟,不熟悉python常用的编程技巧,读代码的时候精力太分散,读代码是一句一句的读,还需要经常上网查语法什么的,没有办法把精力放在代码的整体结构上,即使是每行代码都看明白了还是不知道整个程序的逻辑,同时耗费精力比较大,很快就累了,效率很低。
熟悉了常用库和编程技巧之后读代码的时候很多功能自己都实现过类似的,扫一眼就看明白了,很多函数扫一眼就知道什么功能,思路不会被不懂得语法或者编程技巧打断,一直停留在程序的逻辑上,这样看代码就轻松多了,而且很快,基本上小的项目随便翻翻就知道它的思路了,大的项目的话其实不用全都把握,只要把与自己要看的部分相关的熟悉了就好了。
读代码快的人也并不是什么都会比你快,当他们碰到一些没见过的东西时也是需要查询,自己写一些例子来熟悉,也要花一些时间,熟悉单个知识点也并不比你快。
文档和测试用例对于楼主目前的阶段来说用处不大,这些东西只能是在你读代码变快了以后锦上添花的东西,很多时候看看文档和测试用例会加快理解这个库的速度,起个和代码对照的作用
如果想要通过熟悉这个库来提高编程水平的话,就把里面用到的第三方库和编程技巧自己多写写,这样回过头来看就知道作者为什么这么写了,很多代码看起来很复杂其实思路很简单的。
一开始我也觉得是自己没有掌握方法,一度还想去买一本很著名的教人读代码的书,后来没买,因为不知不觉我就发现我读代码越来越容易了。
你觉得调用栈跳来跳去的记不住是吧?你觉得模块功能联系太多反馈回路太复杂是吧?其实真正原因是你脑子不够用!
一开始,我读一个三四千行的代码要做上千字的笔记看上一俩星期,后来就不用了,读下来函数调用栈都在脑子里,最多画个草图标一下各模块依赖关系。后来有一次给新人讲模块,用SI,函数间点来点去点得飞快,最后发现我这一口气已经走了几十个函数了。
计算机跑程序,调用栈太多会耗尽内存死机,人读代码,大脑的调用栈太多就会耗尽记忆力然后晕掉,解决办法就是多读代码,把你大脑能够支持更深的调用栈深度的记忆力的潜力开发出来。等突破临界点了你自然会懂怎么读。
先骂作者,然后找个小点的例子调试。
多看,猛看,看了几十万行规模的系统后再看其他系统就自然如履平地。
原文地址:Aaron Liu - Welcome to my blog! • 阅读源代码的几个步骤
需要技能:程序调试能力.
1,跑通程序.
2,运行程序的核心功能,从外部了解它的运行方式.
3,阅读核心功能相关的官方文档.
4,读核心功能对应的源代码(即核心模块)和单元测试,从内部大概了解一下核心模块之间的联系.
5,提出一个关于源码的问题(比如状态机如何运作,filters分为几层等),试图解决.
6,浏览该问题相关代码和测试,然后边调试边解决问题,(不要在代码非常不熟悉的情况下就开始调试,过长的程序栈会消耗太多时间).
7,继续提出问题,直至核心模块烂熟于心.
8,(可选)与同学同事交流学习该模块,或写成博客与网友分享,以加深记忆,获取反馈.这次你很有可能会发现理解上的漏洞或错误,进行查漏补缺吧.
9,开始阅读次核心模块,并重复3-7步骤.
10,如果还嫌不足,为该程序开发插件或库吧.
11,理解源码.
详情请查看我的PPT:如何阅读源代码.pptx_免费高速下载
问题导向阅读代码的方法分为外部和内部两个部分.
外部阅读:带着问题去看,自己提出一个程序常用的应用场景,然后自己去在程序上测试一些主要逻辑,比如后台添加了A,前台是否就生成了B?服务端修改了C,客户端会不会出现D之类.
内部阅读:带着问题去看,提出一个如何写程序拓展的场景,(你以后想拓展这一块逻辑该怎么做?有没有内建的现成API可供调用),总之不要被文档带着思路走,要被问题带着思路走.
请大家多拍砖或补充,多谢.
这方面有好几本专门的书和文章,也有朋友提供了具体的、系统性的技巧,就不重复了。
还是从个人角度来建议,不求全面,主要是两点:
- 从弄清楚目标开始,逐层理解目标系统的设计思路到最后如何实现的具体细节;
- 如果有能力,甚至换位思考:与其说是阅读别人的代码,不如说是自己再设计实现一遍——那你是不是也是从弄清楚目标开始,然后提出解决思路,进一步得到解决方案,再分解成若干模块......逐层分解下去?那这样的话还会吃力么?
主要技巧大概说几个关键词吧:
- 自顶向下:从目标代码实现的功能、解决的问题(需求),逐层分解问题/解决问题的方法,自顶向下来阅读
- 提纲挈领:摸清框架而避免在某个细节停留,如果对某个细节有疑问,记录下来回头深入去看
- 广度优先:每次在一个层面上通读一遍(比如第一次掌握主要的几个模块和它们之间的关系,第二次则是几个主要的类,第三次可能到了方法/函数层面),确保广度优先而不是深度优先
- 理清目的,分离职责:在不同层面弄清楚每个模块、类、方法的目的/职责,而不是如何实现这个目的/职责。因为任何算法都是为某个职责、目的服务,弄清楚目的而不在于如何实现目的,弄清楚Why而不是How to
高效阅读代码的能力背后:
- 大脑的运行方式——和CPU很像,当需要跟进进入到下一个层面(深度)的时候,需要把当前断点记下来,相关信息压入“堆栈”暂时放一放,等进入下一个层面回来恢复到之前的断点工作状态。想想大脑的堆栈和准确记忆能力显然不如CPU,所以尽量避免在不同层次来回穿越,甚至过于深入。必要时,借助一些电脑软件来帮助你阅读,例如UML工具的类图、时序图等
- 重点在目标/职责是什么,然后才是如何实现目标/职责:任何系统都是为了解决具体问题而存在。如何解决问题则体现在解决方案,代码只是实现解决方案。而解决方案在不同层面体现为功能模块的组合、具体函数/方法的组合、具体的算法实现(方法内部)等等。
所以需要自顶向下的分解问题、解决问题的思路,自顶逐层往下,每个层面都搞清楚这个层面的全局脉络(广度优先)。
- 题外:做开发的弟兄们最容易出现的问题就是过于关注“how to”这样的实现问题,常见的场景例如:看到别人做了一个什么系统、软件、功能,第一反应是“这个简单,我也会”、“哟,这是怎么实现的?我好像不会”——无论你会不会,请克制你的技术实现冲动。首要问题是:Why——为何要这么实现?那一定是为某个目标、职责服务的。当你阅读别人已经写好的代码,那些代码肯定是为一个个大大小小的目标、职责服务的,所以先忽略How to,搞清楚它们每一个目标/职责,暂时忽略细节。待都弄清楚了,再来挑你感兴趣的地方深入去分析,有的是时间和机会。
——请克制技术冲动、实现冲动,这对你的职业生涯是非常有帮助的。已经度过了类似阶段的朋友不妨回顾一下这里面的心得体会。越是对自己的技术实现能力不自信的阶段,越容易出现类似问题。
其实任何行业,往往随着经验和能力提升,越来越熟练的在抽象层面思考、擅长运用“自顶向下”的分解能力,并且有很强的全局观和逻辑性来保证在任何一个层面的展开都系统而全面(其实基于上一层作为依据展开也不容易遗漏)。举个自己的例子:曾经我的简历上列明我精通、掌握、熟悉各种技术和平台还有各种经验案例等等,后来改成一句话——擅长高效解决问题,并乐于解决复杂问题和新问题,尤其享受用创新方式解决问题。简历上写的求职方向就不再限制于软件相关了——当然1,这与其说是个人能力提升了,不如说找到了自己努力和享受的方向。这样的阶段,至少在思维上已经脱离了具体的软件设计开发相关技术背景的限制,有勇气面对任何行业任何问题;当然2,不要脱离实际的选择专业性要求过于强的行业和工作岗位进行比较;当然3,这些行业里的从业人员不也存在同样的阶段性问题么?
思考和讨论这类问题,对个人成长有提速作用。
个人以为有几种基础能力:
运算能力(大脑的堆栈容量)决定了能处理问题的大小和复杂程度(有生理上限)、思维模式(方法论)决定了处理大和复杂的问题效果和效率(扩充了生理上限)、自我克制(理解甚至控制生理本能)决定了排除干扰的能力,然后是经验积累(可重用模块:分为模式级别和具体实现级别的经验)。
——如同一个优秀的棋手。
母亲说我小时候喜欢玩线团和整理纽扣,可以坐在一个地方一动不动一个下午直到解开一个线团。
随着成长,我已经不满足于解开各种线团,甚至解开越来越大、越来越复杂的线团,而是尝试和追求另外一种方式:各角度观察、推理,理清头绪之后找准一个线头,拎起来轻轻一抖——哇,整个线团优雅的解开了——爽!
一个真正的领导者,在人群中默默观察,对外接的刺激不要立即有反应(自我克制),做那个清醒的了解目标和团队和自己的人(全局观),找到解决方法后选择最恰当的方式去影响和驱动周围的人。未必是聚光灯下的领导者,却是实际上的领导者,不需要权力就能驱动整个组织往有效解决问题的方向推进的领导者。
看过《安德的游戏》的朋友,推荐它的姐妹篇《安德的影子》,主角小豆子就是极好的例子(避免剧透到此打住)。
再往后。。。一下子没想好怎么表达,先打住吧,有朋友有兴趣我再分享进一步的心得。
最后,到这里也只好匿了,呵呵。
1. 要建立层次和结构
看代码不是看小说,线性地往下看就行了。看代码是为了理解代码,在脑子里建立起源代码背后的层次和结构的映射。为此,在开始分析项目之初,就要明确代码的子项目,包(名称空间),类的层次和结构,主要由哪些包构成,每个包大致做什么用。主要的类有哪些,各自的大致职责是什么。主要的类里面,又有哪些主要的方法。
2. 要抓住主干
任何的项目,有相当的代码是用来做一些琐碎的,事务性的事情的。要高效地理解和把握代码,我们就要把握主干。对于代码中的一些主要方法,或者流程,可以梳理出它们的主要步骤,次要的东西可以忽略不管,需要的时候再关注。
3. 要形成文档
如前面的几位答友所说,人脑子不善于记住方法间的进进出出之类的东西,在我们分析这些东西的同时,用一种有效的方式,把分析的结果记录下来,既保存了工作成果,更重要的是,帮助我们更容易进行分析,向深挖的时候,知道现在自己在哪里,向回退的时候,又退得出来,不至于迷路。类图,序列图,都是有用的文档形式,也可以用自己定义的更灵活的图表。好记性不如烂笔头,勤快动脑同时也勤快动手,看代码会容易很多。
4. 要合理运用各种可用手段
静态分析,当然是分析代码的基本手段;但是除了静态分析,如果你的代码也是可以运行的,运行它,观察它的调用堆栈,LOG,或者用调试工具进行跟踪。对于那些主要的方法,流程,有必要用动态跟踪的方式,弄清楚它的过程。这也会比静态分析更直接,更快地告诉你它到底走过哪些路径,执行了哪些方法。
个人习惯先看文档说明了解功能了再做个 demo,明白基础的功能后就从这个熟悉的点切入去看。
我还见过直接硬啃代码的牛人,对他而言,这种方式简单粗暴,速度快效果好。