程序員如何高效讀代碼?

最近在看Twitter的Oauth2的庫的源代碼(simplegeo/python-oauth2 · GitHub),看不進去啊...整個庫有些自成體系的感覺,看上去聯繫很緊密,所以從哪裡開始看都不方便。從上往下看代碼的話,肯定會被各種函數看暈。從main()開始看的話,也會被好多層的調用搞暈。因為之前對Python的Http請求的庫並不熟悉(如httplib2, requests),經常會需要看一下其它庫的一些內容,更暈了...

現在總是覺得自己明白大致的流程,但總有大段的函數看不懂,結合文檔看也總有很多地方不明白。自己就是想看明白一些,然後對這個庫做一些改進(因為有些API的Oauth流程和其它API的有區別,所以我想改進一下Oauth的過程)。但現在的理解程度,完全達不到這個要求啊...(這兩天找到了一個新的庫,可以滿足我的要求,但我還是想搞明白怎麼讀代碼比較好...)

各位資深的程序員們,我應該怎麼做才好呢...


先看文檔,再看單元測試。


Code Reading (豆瓣) (副題是 The Open Source Perspective,適合題主需求)

代碼閱讀 (豆瓣) (中譯本)


之前也是讀代碼很慢,後來代碼寫的多了讀這些開源項目的速度就明顯快了。

讀代碼慢就是對常用函數和常用庫不熟,不熟悉python常用的編程技巧,讀代碼的時候精力太分散,讀代碼是一句一句的讀,還需要經常上網查語法什麼的,沒有辦法把精力放在代碼的整體結構上,即使是每行代碼都看明白了還是不知道整個程序的邏輯,同時耗費精力比較大,很快就累了,效率很低。

熟悉了常用庫和編程技巧之後讀代碼的時候很多功能自己都實現過類似的,掃一眼就看明白了,很多函數掃一眼就知道什麼功能,思路不會被不懂得語法或者編程技巧打斷,一直停留在程序的邏輯上,這樣看代碼就輕鬆多了,而且很快,基本上小的項目隨便翻翻就知道它的思路了,大的項目的話其實不用全都把握,只要把與自己要看的部分相關的熟悉了就好了。

讀代碼快的人也並不是什麼都會比你快,當他們碰到一些沒見過的東西時也是需要查詢,自己寫一些例子來熟悉,也要花一些時間,熟悉單個知識點也並不比你快。

文檔和測試用例對於樓主目前的階段來說用處不大,這些東西只能是在你讀代碼變快了以後錦上添花的東西,很多時候看看文檔和測試用例會加快理解這個庫的速度,起個和代碼對照的作用

如果想要通過熟悉這個庫來提高編程水平的話,就把裡面用到的第三方庫和編程技巧自己多寫寫,這樣回過頭來看就知道作者為什麼這麼寫了,很多代碼看起來很複雜其實思路很簡單的。


先罵作者,然後找個小點的例子調試。


原文地址: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可供調用),總之不要被文檔帶著思路走,要被問題帶著思路走.

請大家多拍磚或補充,多謝.


一開始我也覺得是自己沒有掌握方法,一度還想去買一本很著名的教人讀代碼的書,後來沒買,因為不知不覺我就發現我讀代碼越來越容易了。

你覺得調用棧跳來跳去的記不住是吧?你覺得模塊功能聯繫太多反饋迴路太複雜是吧?其實真正原因是你腦子不夠用!

一開始,我讀一個三四千行的代碼要做上千字的筆記看上一倆星期,後來就不用了,讀下來函數調用棧都在腦子裡,最多畫個草圖標一下各模塊依賴關係。後來有一次給新人講模塊,用SI,函數間點來點去點得飛快,最後發現我這一口氣已經走了幾十個函數了。

計算機跑程序,調用棧太多會耗盡內存死機,人讀代碼,大腦的調用棧太多就會耗盡記憶力然後暈掉,解決辦法就是多讀代碼,把你大腦能夠支持更深的調用棧深度的記憶力的潛力開發出來。等突破臨界點了你自然會懂怎麼讀。


我覺得:大項目代碼有自己的"骨架"(或言邏輯體系、架構思路、主體流程、大綱等),其餘細節是"血肉",我看代碼喜歡追求理解"骨架",這樣把握大綱了,才不至於在代碼叢中迷失。

但是理解"骨架"不易,對大項目不是一朝一夕之功。如可能我一般大概按如下步驟走:

  1. 理解背景,理解這項目是拿來做什麼的。
  2. 下載源碼,部署起來操作一番,有個直觀印象。一般即使集群代碼也會有單機部署模式,沒有也可使用本地VM。
  3. 先看偏高層次的文檔,先不看直接深入介紹某細節的文檔。
  4. 切片式看代碼,以某個最想了解的主題為線索。一個成功的切片下來,相信會有更直觀的理解。

在這些思路指導下,我往往也會"不擇手段":改改試試、加日誌、搜博客、搜slide(會有作者的高層次介紹)、加入討論群、訂閱maillist...


多看,猛看,看了幾十萬行規模的系統後再看其他系統就自然如履平地。


這方面有好幾本專門的書和文章,也有朋友提供了具體的、系統性的技巧,就不重複了。

還是從個人角度來建議,不求全面,主要是兩點:

  1. 從弄清楚目標開始,逐層理解目標系統的設計思路到最後如何實現的具體細節;
  2. 如果有能力,甚至換位思考:與其說是閱讀別人的代碼,不如說是自己再設計實現一遍——那你是不是也是從弄清楚目標開始,然後提出解決思路,進一步得到解決方案,再分解成若干模塊......逐層分解下去?那這樣的話還會吃力么?

主要技巧大概說幾個關鍵詞吧:

  1. 自頂向下:從目標代碼實現的功能、解決的問題(需求),逐層分解問題/解決問題的方法,自頂向下來閱讀
  2. 提綱挈領:摸清框架而避免在某個細節停留,如果對某個細節有疑問,記錄下來回頭深入去看
  3. 廣度優先:每次在一個層面上通讀一遍(比如第一次掌握主要的幾個模塊和它們之間的關係,第二次則是幾個主要的類,第三次可能到了方法/函數層面),確保廣度優先而不是深度優先
  4. 理清目的,分離職責:在不同層面弄清楚每個模塊、類、方法的目的/職責,而不是如何實現這個目的/職責。因為任何演算法都是為某個職責、目的服務,弄清楚目的而不在於如何實現目的,弄清楚Why而不是How to

高效閱讀代碼的能力背後:

  1. 大腦的運行方式——和CPU很像,當需要跟進進入到下一個層面(深度)的時候,需要把當前斷點記下來,相關信息壓入「堆棧」暫時放一放,等進入下一個層面回來恢復到之前的斷點工作狀態。想想大腦的堆棧和準確記憶能力顯然不如CPU,所以盡量避免在不同層次來回穿越,甚至過於深入。必要時,藉助一些電腦軟體來幫助你閱讀,例如UML工具的類圖、時序圖等
  2. 重點在目標/職責是什麼,然後才是如何實現目標/職責:任何系統都是為了解決具體問題而存在。如何解決問題則體現在解決方案,代碼只是實現解決方案。而解決方案在不同層面體現為功能模塊的組合、具體函數/方法的組合、具體的演算法實現(方法內部)等等。

    所以需要自頂向下的分解問題、解決問題的思路,自頂逐層往下,每個層面都搞清楚這個層面的全局脈絡(廣度優先)。
  3. 題外:做開發的弟兄們最容易出現的問題就是過於關注「how to」這樣的實現問題,常見的場景例如:看到別人做了一個什麼系統、軟體、功能,第一反應是「這個簡單,我也會」、「喲,這是怎麼實現的?我好像不會」——無論你會不會,請克制你的技術實現衝動。首要問題是:Why——為何要這麼實現?那一定是為某個目標、職責服務的。當你閱讀別人已經寫好的代碼,那些代碼肯定是為一個個大大小小的目標、職責服務的,所以先忽略How to,搞清楚它們每一個目標/職責,暫時忽略細節。待都弄清楚了,再來挑你感興趣的地方深入去分析,有的是時間和機會。

    ——請克制技術衝動、實現衝動,這對你的職業生涯是非常有幫助的。已經度過了類似階段的朋友不妨回顧一下這裡面的心得體會。越是對自己的技術實現能力不自信的階段,越容易出現類似問題。

    其實任何行業,往往隨著經驗和能力提升,越來越熟練的在抽象層面思考、擅長運用「自頂向下」的分解能力,並且有很強的全局觀和邏輯性來保證在任何一個層面的展開都系統而全面(其實基於上一層作為依據展開也不容易遺漏)。舉個自己的例子:曾經我的簡歷上列明我精通、掌握、熟悉各種技術和平台還有各種經驗案例等等,後來改成一句話——擅長高效解決問題,並樂於解決複雜問題和新問題,尤其享受用創新方式解決問題。簡歷上寫的求職方向就不再限制於軟體相關了——當然1,這與其說是個人能力提升了,不如說找到了自己努力和享受的方向。這樣的階段,至少在思維上已經脫離了具體的軟體設計開發相關技術背景的限制,有勇氣面對任何行業任何問題;當然2,不要脫離實際的選擇專業性要求過於強的行業和工作崗位進行比較;當然3,這些行業里的從業人員不也存在同樣的階段性問題么?

思考和討論這類問題,對個人成長有提速作用。

個人以為有幾種基礎能力:

運算能力(大腦的堆棧容量)決定了能處理問題的大小和複雜程度(有生理上限)、思維模式(方法論)決定了處理大和複雜的問題效果和效率(擴充了生理上限)、自我剋制(理解甚至控制生理本能)決定了排除干擾的能力,然後是經驗積累(可重用模塊:分為模式級別和具體實現級別的經驗)。

——如同一個優秀的棋手。

母親說我小時候喜歡玩線團和整理紐扣,可以坐在一個地方一動不動一個下午直到解開一個線團。

隨著成長,我已經不滿足於解開各種線團,甚至解開越來越大、越來越複雜的線團,而是嘗試和追求另外一種方式:各角度觀察、推理,理清頭緒之後找准一個線頭,拎起來輕輕一抖——哇,整個線團優雅的解開了——爽!

一個真正的領導者,在人群中默默觀察,對外接的刺激不要立即有反應(自我剋制),做那個清醒的了解目標和團隊和自己的人(全局觀),找到解決方法後選擇最恰當的方式去影響和驅動周圍的人。未必是聚光燈下的領導者,卻是實際上的領導者,不需要權力就能驅動整個組織往有效解決問題的方向推進的領導者。

看過《安德的遊戲》的朋友,推薦它的姐妹篇《安德的影子》,主角小豆子就是極好的例子(避免劇透到此打住)。

再往後。。。一下子沒想好怎麼表達,先打住吧,有朋友有興趣我再分享進一步的心得。

最後,到這裡也只好匿了,呵呵。


1. 要建立層次和結構

看代碼不是看小說,線性地往下看就行了。看代碼是為了理解代碼,在腦子裡建立起源代碼背後的層次和結構的映射。為此,在開始分析項目之初,就要明確代碼的子項目,包(名稱空間),類的層次和結構,主要由哪些包構成,每個包大致做什麼用。主要的類有哪些,各自的大致職責是什麼。主要的類裡面,又有哪些主要的方法。

2. 要抓住主幹

任何的項目,有相當的代碼是用來做一些瑣碎的,事務性的事情的。要高效地理解和把握代碼,我們就要把握主幹。對於代碼中的一些主要方法,或者流程,可以梳理出它們的主要步驟,次要的東西可以忽略不管,需要的時候再關注。

3. 要形成文檔

如前面的幾位答友所說,人腦子不善於記住方法間的進進出出之類的東西,在我們分析這些東西的同時,用一種有效的方式,把分析的結果記錄下來,既保存了工作成果,更重要的是,幫助我們更容易進行分析,向深挖的時候,知道現在自己在哪裡,向回退的時候,又退得出來,不至於迷路。類圖,序列圖,都是有用的文檔形式,也可以用自己定義的更靈活的圖表。好記性不如爛筆頭,勤快動腦同時也勤快動手,看代碼會容易很多。

4. 要合理運用各種可用手段

靜態分析,當然是分析代碼的基本手段;但是除了靜態分析,如果你的代碼也是可以運行的,運行它,觀察它的調用堆棧,LOG,或者用調試工具進行跟蹤。對於那些主要的方法,流程,有必要用動態跟蹤的方式,弄清楚它的過程。這也會比靜態分析更直接,更快地告訴你它到底走過哪些路徑,執行了哪些方法。


個人習慣先看文檔說明了解功能了再做個 demo,明白基礎的功能後就從這個熟悉的點切入去看。

我還見過直接硬啃代碼的牛人,對他而言,這種方式簡單粗暴,速度快效果好。


如果是業務系統 ,特別是很複雜的 業務系統 ,除非對於業務很熟,否則不太可能 高效。 如果很高效 那麼是 猜的,風險很大 。


自己實現一個oauth再看就懂了啊


可以將代碼轉換成flowchart進行閱讀,有在線試用,code2flow - online interactive code to flowchart converter

歸根結底,還是要讀的多,寫得多,用的多。


手中有糧,心才不慌;


《異類》中說,做成任何事都需要足夠量的積累。中國有句古話說:熟知唐宋元明清,不會吟詩也作文沒(真牽強)←_←


凡操千曲而後曉聲,觀千劍而後識器。故圓照之象,務先博觀。閱喬嶽以形培塿,酌滄波以喻畎澮。無私於輕重,不偏於憎愛,然後能平理若衡,照辭如鏡矣。是以將閱文情,先標六觀∶一觀位體,二觀置辭,三觀通變,四觀奇正,五觀事義,六觀宮商。斯術既行,則優劣見矣。---劉勰的《文心雕龍·知音》共勉


Read The Fucking Source Code


有文檔先大概看看文檔,沒文檔邊運行邊看,debug是個好東西~


先看功能塊,再看這些功能塊的信息交互,最後看實現


在沒有文檔的情況下,我是先了解代碼結構,然後再看看Util部分(這部分沒有太多函數調用等跳轉),最後是看demo或挑選自己感興趣的部分來看。


好的代碼當教科書看,爛的代碼當小說看


一開始不要讀,先跑通,如果一個函數大致你都猜得到怎麼實現的就不用讀了,針對不懂得函數,利用IDE,進去讀。還有,不要加個注釋就夠了,流程分析圖才是最重要的


模仿是為了更好的書寫,就像古代武術,先學其形,再而深入,終而會之!


推薦閱讀:

GitHub上有哪些值得關注和學習的Qt項目?
ubuntu下有沒有原生支持中文顯示和語法高亮的代碼編輯軟體?
下面的代碼什麼意思?
如何在一份垃圾代碼上修改出優秀代碼?

TAG:程序員 | Python | 編程 | 代碼 | 代碼閱讀 |