標籤:

如何閱讀別人的代碼?


謝謝邀請。簡要回答一下吧。

閱讀代碼有兩種模式:top-down 和 bottom-up。

Top-down 模式,就是先設定一個 use case,比如說打開一個文件。然後靜態跟著代碼看,或者用 debugger 跟著看。每次出現函數調用的時候,把函數的執行層次紀錄下來。大致如下:

func1( )
func2( )
func( )
func3( )

這種圖表很隨意,你可以根據自己的需要增加信息。比如我有時會把重要的「實際參數」一直標下來,這樣閱讀深層次代碼不用再回頭查形式參數到底指什麼。這個圖的基本作用是防止在閱讀深層次代碼時忘記總體執行層次。

Top-down 模式進行到一定層次,往往會發現雖然圖畫了出來,但還是無法了解程序再幹什麼。這時需要轉入 bottom-up 模式,一直深入到最底層,給能了解作用的底層函數一個一個的寫文檔。當然這時的文檔是完全底層的觀點。

然後就是不斷在兩個模式之間轉換,不斷的細化兩種模式的理解。


1:讀文檔。儘管讀了文檔你不一定知道每一個代碼的細節,但是如果你了解那個問題的話,你一定知道怎麼寫可以寫出一個滿足文檔的內容。這個時候大腦裡面就可以有個框架,先猜一猜,然後看代碼,事半功倍。這樣你還可以學到新的知識,如果代碼跟你寫的不一樣,要麼就是你傻逼,要麼就是作者傻逼,你總會學到東西的。

2:找不到好的文檔,就看他的測試用例,也是有一樣的功效的。因為測試都是從文檔出發編寫的,而不是從代碼出發編寫的。

3:找不到文檔和測試用例?請聯繫作者。作者不肯給,就換一個庫。


正如@馮東 提到的,我常用的也是top-down模式,畫函數調用圖,然後標註每個函數在幹什麼。不過這個圖無法清楚地表明一個變數的軌跡,需要另外的圖來標示變數的變化軌跡。因為工作中需要讀大量代碼,一直在思考並實踐有什麼更好的方法,無奈這就是目前最有效地方法。

要是想提高閱讀代碼的速度,歸根結底要多讀多寫。熟悉程序的基本構成單元(例如循環、分支)的常見寫法,各種lib, api的調用方式。

一種好的方式是找一個好的開源模塊,按一定的方法閱讀代碼,並記錄閱讀筆記。這樣當你閱讀完代碼之後,不僅學習到了很好的編碼規範,同時也能發現代碼閱讀方法中有哪些不足,不斷改進你的閱讀的方法。

另外,我理解一個代碼閱讀方法的好於不好,一個比較準確的檢測方式就是,用它來閱讀一個純c寫成的lib(例如sqlite)。


這要看閱讀的是一般的規範代碼還是閱讀由於某些原因產生的爛代碼。

規範代碼的閱讀方法,大神們都講,書里都有。

爛代碼的閱讀方式,我覺得就很不一樣。

首先得調整好心態,做好思想準備,避免讀到一半就來了衝動想殺人,還得避免由於一時糊塗直接上手重構導致的不可控。

讀的過程中,一定要處處小心各種意外,

不要想當然的看到函數的名字一定能猜到它的作用,也不要假設一個函數只可能有1到N個作用,也有可能這個函數什麼用都沒有,僅僅是在代碼中存在而已;

不要假設注釋一定是準確的,有可能注釋早就沒人維護了,注釋最多只能反映某一版代碼某個人的理想,而不能反映當前代碼的真正實現。

總之就是一切皆有可能發生,不要有任何假設,既然看了就要耐心的看,心如止水。

並且最好提前用為人處事的技巧避免被看這些代碼,如果實在推脫不掉,就要做好當英雄的心理準備。

在我的印象中,C什麼的語言,編譯器是產生爛代碼的一大障礙,寫代碼的人不敢不好好寫,否則就硬邦邦的提示不讓你通過。

相比之下php什麼的,雖然容易寫,但很多時候都是按照想像隨意寫,並且看起來能用就沒人再管了。閱讀起來反而很難受。


首先你要有個好工具,例如source insight。然後在開始讀具體代碼前定位好所有要讀的文件,知道他們的位置和名字,設計良好的工程光看工程的目錄結構和文件名就能知道個大概功能了。事實上閱讀代碼的難易程度70%取決於代碼書寫的規範程度,寫亂掉的代碼,大師也讀不懂。之後根據你對目錄結構的理解確定文件閱讀的順序(我反正都是從main函數開始讀的)。你最好對設計模式有一定了解,否則你讀面向對象的code時會經常無法理解code為啥要弄得這麼層層嵌套。閱讀代碼一個最重要的提升水平的地方就是理解好的代碼如何合理使用設計模式。基本的閱讀起點都會選擇main函數或者類的構造函數。然後把自己想像成cpu執行程序那樣去閱讀你的代碼。遇到需要跳轉函數時,不要急於跳轉,以了解函數功能和輸入輸出為目標,讀代碼最忌諱的是不抓結構抓細節,只見樹木不見森林,比起某個函數具體功能來說對結構的全局把握更重要。功能了解清楚後繼續跳回來(這裡就可以區分代碼寫的優不優秀,優秀的代碼光看函數名字就知道功能,連跳轉都不用)。結構弄清楚了,知道程序怎麼跑了,source code的精華你已經讀了60%了,之後根據需要再對具體函數深入分析,到這裡整個代碼已經被你扒光了,沒什麼神秘了。

ps:任何關於寫代碼的好書都會提到「界面」這個概念,其實就是把一個功能類相關的所有函數聲明寫在一起(只有聲明沒有實現)便於縱攬全局,這種寫法其實就是給人看的寫法,先從這些界面入手可以讓你快速抓住全局了解類所提供的功能,如果源代碼沒有寫界面,你也可以用工具(source insight或者帶taglist的vim)提煉出界面。總之順序就是先看界面再看細節。


推薦兩個工具吧

一個是樓上有人提到的SourceInsight

還有一個是understand

後者可以以多種樹結構去分析代碼

至少能幫助你從整體上了解代碼的結構


讀代碼還是要層次化、帶著問題去閱讀:

  • 首先整體了解這個軟體是幹什麼?解決什麼問題?包含哪些大的模塊,各個模塊的作用是什麼,各個模塊的調用關係怎麼樣?

  • 然後對於每一個模塊,這個模塊是幹什麼的?為什麼要有這個模塊?這個模塊怎麼實現的?

  • 最後細化到每一個包,每一個類,每一個函數方法。

從上到下,一一擊破每一個問題,認真去思考他這樣設計、寫代碼的好處,因為好的軟體都會滿足這種從抽象-&>具體的原則的。

個人不不喜歡bottom-up的閱讀方法,有時候會一頭扎進去,出不來了。

這種方式適合讀一些比較優秀的開源項目的代碼,也會很好地提高內功。


1. 最好能了解業務功能

2.從啟動入口開始閱讀

3.先整體,宏觀,粗線條的閱讀,明白大體流程和作者的設計思想

4.閱讀第一遍後,進行思考,看看哪些地方自己還不清楚作者怎麼做的,想不通的,矛盾的地方,這時候你是帶著疑問去找答案,跳躍性大,但是會有深入和徹底的領悟,並能快速學到作者的技術

5.如果要徹底的明白,就需要投入更多的時間去細讀,細讀就是讀模塊,讀函數,了解具體實現。

此外,閱讀的時候不要求快,快是你閱讀多了,能力上去後自然的結果。

根據函數名,變數名猜測作者的大體意思,會意比什麼都重要,會意了你就懂了作者,就頓悟了。

多想想換做我這個函數怎麼寫,一般可以猜測個七八,除非作者用了tricky,不過這些地方一般都有doc,

切記不要句讀,要瀏覽式的意會,不要起初就糾結於細節,只要看懂」這段是幹嘛,這段是做什麼」之類的即可!

我覺得閱讀能力和你的coding能力也相關,如果你coding水平高,好的代碼自然有相通之處


拿杯綠茶,邊看邊吐槽


首先應該先了解代碼的功能業務,在了解業務邏輯的情況下,進行代碼閱讀覺得是事半功倍的。

如果有設計文檔或者其他文檔,先閱讀這些文檔也是不錯的。


我一般讀的都是建立在已知功能基礎上的代碼,所以會找個點切入。

切入點未必是從程序運行那裡開始,看個人需要而定。

代碼細節上,先是通讀,有些地方方法嵌套、跳轉比較多的,先記下來方法名稱或者關鍵點,繼續把後面的代碼讀完,然後再深入記下的點讀第二層。(可參考@馮東 答案中的 Top-down 方法。)

曾經也有過先一層一層讀完再繼續後面的經歷,不過感覺不適應,特別是系統代碼規模大的時候,很容易陷入泥潭,導致細節沒弄清楚,前面讀的也沒什麼印象了,又得重來。

讀代碼前,對代碼所實現的業務功能清晰,就容易找到感覺。


一邊讀一邊寫注釋,寫完你就懂了。


讀代碼和看文學作品不一樣,必須有明確目標,然後根據目標來設計case,然後top down。


比如nginx,可能最關注的是性能,那麼就看些對其性能描述較多的文章 ,然後設計用例,然後top down。


再比如python,可能關注垃圾回收,那就從跟蹤對象生命周期開始。


apache可能是插件模塊,諸如此類。

另外動手寫擴展也是個比較好的方法。

否則很多開源發展十年以上,代碼十w行,你一年能看多少。


過去一個月做項目看前人代碼,彙編、C、單片機、VB差不多幾萬行,基本沒注釋沒文檔,到現在也有些許經驗,希望有所幫助:

先從main()開始,top-down地畫出整個程序的流程圖,撿主要的大function出來作為節點,然後看每個節點的作用是什麼,節點之間如何互動,期間穿插bottom-up的方法補充細節。

更多的,其實看陌生代碼整個人的思路是非線性的,重要的是堅持看下來,時間長了自然就熟悉前人思路了。


「代碼閱讀方法與實踐」推薦這本書


個人經驗:

1.經常想如果我是作者會怎麼做

2.可以的話,自己加註釋(例如原作者已離職,下載的開源代碼等)


提倡帶著問題去讀的方法。可能的話先把測試環境搭起來,觀察程序運行的狀態,然後你的腦袋裡會有無數的問題,將這些問題拉個列表,讀代碼過程中一個解決這些問題,問題解決完了,代碼也就讀懂了。


提個工具吧。看別人的代碼,用SourceInsight這個工具


比如我學習源碼的方式是,尋找程序入口,寫測試用例,故意在其中拋異常,看錯誤堆棧信息,就可大體了解程序執行路徑


1.帶著問題去讀,先看他要實現什麼功能;

2.邊看邊加註釋;

3.把自己想像成計算機,看看大概的循環和分支是怎麼實現的;

4.分層閱讀,列出框架;


說到底還是你要明白軟體每個函數,類的功能是什麼。我看的代碼php居多,通常我是一邊看它的功能一邊看,這樣可以將他的形象和代碼聯合起來


討論這個問題首先要看的是語言的分類,而不是具體的方法。


推薦閱讀:

如何較好地理解別人寫的程序?
什麼是真正的程序員?
python3.4寫好的.py文件如何打包成exe?
編程會讓人變得木訥(內向)嗎 ?
如何有效的學會c語言?

TAG:編程 | 代碼 |