如何閱讀原始碼
今天我們來簡單的談談應該如何去閱讀原始碼。閱讀原始碼是每個程式員都要做的事情,畢竟成為master的先前一步,
就是follow the master
。
學會如何使用
要想知道一個東西怎麼實現的,我們首先要有一個大概的認知,例如,是什麼,大概是怎麼用的。所以我們需要先去熟悉這個專案,通常 我們可以這樣做:
- 讀文件
閱讀已有的,優秀的文件,可以加快了解整個專案的使用,坑和架構,這樣可以快速建立起自己對該專案的認知。
- 寫demo
如果閱讀的是一個庫的程式碼呢?我們可以引用這個庫,寫一些簡單的demo,這也是為了加快我們建立對專案的認知。
- 熟悉如何使用
接下來要做的事情就是多寫demo,多使用,當使用該專案到達一定程度的時候,就可以開始閱讀原始碼,而閱讀原始碼本身又可以促進 對專案的熟悉程度。但是,在什麼時候應當開始閱讀原始碼,因人而異,並沒有一個通用的度,而且會因為自身經驗的積累而變化。 我個人建議當可以寫出demo並且知道demo的每一行都在做什麼的時候,就可以開始一邊閱讀原始碼了,如果發現看不懂,則可以繼續加深 對專案使用的熟悉程度,然後再次嘗試。
通常注意,專案越大,開始閱讀原始碼所面臨的難度其實會越高,一定要有信心。
接下來我們主要聊聊一些常用的閱讀原始碼的技巧。
從main函式入手
你的程式是怎麼執行的?一定是從某個入口點(entrypoint)開始執行。例如 Python 可能是if __name__ == "__main__"
或者python
後面接的那個指令碼名,例如 Go 通常是main
函式,C亦然。如果是閱讀一個已有的專案而非庫,那麼我們可以從入口函式開始跟蹤程式碼,
看具體都做了一些什麼,如果是一個庫,那麼我們可以從我們的demo的入口處開始跟蹤原始碼。
但是注意,從上而下和從下而上這兩種閱讀原始碼的方法論,並沒有哪一種更好,從上而下是從概貌到細節,從下而上是從實現細節到 概況。通常來說,都是結合兩者,但是我個人通常以自上而下為主,瞭解了概貌之後,才會去了解具體的實現。
打斷點
為了跟蹤程式碼具體執行步驟,我們可以利用偵錯程式,單步跟蹤,這樣我們可以看到每一步的執行。我個人並不是特別喜歡這種方式,因為 單步跟蹤通常來說都會比較的細節化。例如閱讀Go的runtime時,就可以用這種手法,在我們自己的main函式處打一個斷點,然後單步跟蹤 這樣就可以看到runtime是如何進行初始化的。
列印呼叫棧
列印呼叫棧這是我最喜歡用的方式,因為我主要使用Go和Python,而這兩門語言對列印呼叫棧這個操作都比較友好。通過呼叫棧,我們就可以
一眼看出函式是怎麼從main函式到最後呼叫到棧頂的。例如閱讀Flask的程式碼時,我們就可以在某個handler出直接把呼叫棧打印出來,可以
藉助日誌庫,也可以藉助偵錯程式列印,然後我們就可以很輕易的看出程式都是如何從app.run
一直到具體的handler的。
列印日誌
有時候我們還可以藉助日誌來觀察程式,根據日誌可以大概看出程式都做了什麼,根據日誌的粒度可以從概貌和細節上都有不同程度的
瞭解。通常日誌都會分成DEBUG
,INFO
,WARN
,ERROR
,FATAL
五個級別。通常對於分散式應用,這是一種比較好用的除錯和
瞭解執行順序的方式。
合理使用跳轉
跳轉?編輯器使用者可享受不到這種福利。那可不行,Vim作為強大的編輯器,可以通過YouCompleteMe或者是微軟貢獻的Languange Server Protocol來進行定義跳轉。
-
Vim
- LSP:ofollow,noindex" target="_blank">http://langserver.org/
- YCM:https://github.com/Valloric/YouCompleteMe
閱讀較為經典的程式碼(比較老舊的提交)
一個軟體隨著不斷地演化,新功能的增加,bug的修復,通常會變的比較晦澀難懂,所以我們可以嘗試從比較早的提交裡開始閱讀,比如tag 0.1
,tag 1.0
, 最開始的10個提交之類的。比較早的提交通常是最簡單的版本,但是同一個專案,萬變不離其宗,這也是有利於
我們理解專案的。