如何正確的閱讀源代碼?
寫完「你也可以像 Prisma 一樣渲染圖像」之后,有讀者提了這樣一個問題:
我猜您平時應(yīng)該有閱讀開源項目的源碼,好的開源軟件或者框架,動輒數(shù)萬行的源碼,雖說是寶藏,但我看源碼一直不得要領(lǐng),投入時間不少但收獲甚微,請教下:
您閱讀源碼的關(guān)注點一般有哪些?
您看源碼有沒有什么方法論呢,如何抓住重點下手?有時面對優(yōu)秀的開源框架,想學(xué)習(xí),我甚至都不知從哪看起。
關(guān)于這個問題,我說兩句。
閱讀優(yōu)秀的源代碼是軟件工程師提高自己編程能力和學(xué)習(xí)開源框架的***手段之一。作為一名運動員,除了持續(xù)的刻意練習(xí),還需要觀摩大量對手的比賽視頻。作為一名小說家,除了筆耕不輟,還需要閱讀大量的其他作家的偉大作品。當(dāng)然,觀摩和閱讀不是目的,是手段。路遙在創(chuàng)作《平凡的世界》之前讀了大量的「名著」,然后,他把所有尊敬的作家都安放在遠(yuǎn)方歷史為他們準(zhǔn)備的「先圣詞」中,讓他們各自光芒四射,照耀大地,然后開始創(chuàng)作百萬巨著《平凡的世界》。照耀你的世界的光芒,應(yīng)該是自己發(fā)出的。
程序員亦是如此。在編程的路上,有無數(shù)的大師寫出了偉大的代碼和軟件,去學(xué)習(xí)他們的編程技巧和技術(shù)風(fēng)格,取其精華,去其糟粕,***完成自己的作品。2005年左右我有幸參與了一個類似 CORBA 的分布式應(yīng)用系統(tǒng)的開發(fā),我在那段時間差不多通讀了這個項目的早期代碼,其整體架構(gòu)規(guī)劃和代碼設(shè)計的精巧程度讓人嘆為觀止(代碼的編寫者是早期的 CORBA 規(guī)范制定者)。這個經(jīng)歷對我后來的編程之路產(chǎn)生了深遠(yuǎn)的影響。
與編程一樣,閱讀別人的源代碼永遠(yuǎn)不是一件輕松的事,或者說,是一件困難的事情,需要持續(xù)的投入,閱讀、研究、把玩、實踐。很多人覺得拿到了源代碼就像買了本書一樣,放到書柜上,立刻就產(chǎn)生了一種學(xué)會了的錯覺(我就是這樣,微笑),但真正實踐起來才會體驗到強烈的挫敗感。大部分情況下,讀不下去,不是方法不好,而是投入度不夠。
閱讀源代碼,一定要找到好的開源項目。什么是好的項目?口碑好且應(yīng)用廣泛的項目就是好項目,比如 Docker、Spring、OpenResty,都是非常好的閱讀素材。另外,完善的文檔和足夠的 test case 覆蓋率,都是衡量一個開源項目是否優(yōu)秀的標(biāo)準(zhǔn)。很多人說,代碼即文檔,好的代碼本身就是自解釋的。但是,對于規(guī)模宏大的開源軟件來說,沒有文檔是不可想象的。所以在閱讀源代碼之前,一定要讀文檔。盡管讀了文檔之后,你可能不知道代碼的技術(shù)細(xì)節(jié),但至少可以了解項目的輪廓。結(jié)合開源項目的代碼目錄,差不多可以繪制出一個粗粒度的整體架構(gòu)圖,類似這樣的:
然后為每個目錄(或模塊)做記錄和標(biāo)識,逐一閱讀,或者直接去讀你最感興趣的部分。
我讀源代碼喜歡自頂向下的方式,先把整體脈絡(luò)理清楚,然后按照模塊去閱讀代碼,把類和類、函數(shù)和函數(shù)之間的調(diào)用關(guān)系記錄下來,如果可以進(jìn)行逆向工程,用類似 Intelli IDEA 這樣的工具把代碼之間的調(diào)用關(guān)系用 Diagrams 展現(xiàn)出來,閱讀會更加直觀一些,不同的語言有不同的工具可以選擇。
另外,閱讀 test case 同樣能幫助你理解作者的代碼設(shè)計意圖。正常情況下,測試用例都是從文檔和設(shè)計衍生出來的,而不是完成了代碼再寫 test case。閱讀測試用例,可以讓你更清晰的知道對應(yīng)的類和函數(shù)想要做什么事情。
閱讀源代碼需要順手的工具,我自己喜歡用 Vim,配合 NERDTree、CtrlP、ctags、taglist 等插件,Vim 可以成為一款優(yōu)秀的代碼瀏覽工具,而且非常輕量級。你可以在終端里用命令迅速打開、關(guān)閉、查找和索引程序,并進(jìn)行有效的關(guān)聯(lián)跳轉(zhuǎn)(靜態(tài)代碼)。如果你不習(xí)慣,也可以用 Sublime Text,Atom 等工具。當(dāng)然,如果你要進(jìn)行調(diào)試和跟蹤,那***使用相關(guān)程序棧的 IDE 工具,比如 Eclipse、Jet Brain 系列工具,Xcode 等等,這樣你可以在 debug 狀態(tài)跟蹤所有的函數(shù)調(diào)用和變量參數(shù)在執(zhí)行時間線上的變化。
如果你喜歡 Vim,可以看下這篇「Vim 8.0,姍姍來遲」。
重復(fù)一句,工具和方法永遠(yuǎn)不是最重要的,去讀,并在遇到困難的時候,看不明白的時候,咬牙堅持下去,抽絲剝繭,逐個擊破。最終,你會在冰冷黑暗的二進(jìn)制世界里面看到一張地圖,找到一座燈塔,然后去解釋和還原這個底層世界里每一個細(xì)微方面的語義,重建出高層次的抽象概念和關(guān)系。
***推薦兩本書,《Docker 源碼分析》和《Go 語言學(xué)習(xí)筆記》,這兩本書,都是關(guān)于 Go 語言的,可以說是源代碼閱讀的典范,有興趣可以找來讀讀。