開源專案學習方法ABC

luckyfriends發表於2015-01-30
lytword2015-07-16樓主
學習各種開源專案,已經成為很多朋友不可迴避的工作內容了。筆者本人也是如此。在接觸並學習了若干個開源專案之後,筆者試圖對自己工作過程中的若干體會加以總結,以期對一些希望借鑑的朋友有所裨益。
需要說明的是,筆者本人接觸的開源專案大多屬於計算機系統領域,例如Linux kernel,KVM,QEMU,OpenStack等。因此,此處介紹的經驗必定也有些侷限。請讀者們自行分辨,區別對待。
1.        學習分層和目標管理
對於一個開源專案,可以將與之相關的各種知識和技能的學習大致劃分為如下五個層次:
第一層次:瞭解專案的基本概念、基本用途、邏輯結構、基本原理、產生背景、應用場景等基本知識。
這個層次的基本定位其實就是“科普”。如果對於一個專案只需要有些基本瞭解,且短期內並不需要上手進行實際技術工作,則學習到這個層次也就可以先應付一下了。
第二層次:掌握專案的基本安裝流程和使用方法。
這個層次的基本定位是“入門”,以便對這個專案獲得直觀認識,對其安裝和使用獲得親身體驗。如果只是需要以as-is方式使用這個專案,則初步學習到這個層次即可。
第三層次:瞭解程式碼的組織,找到各個主要邏輯/功能模組與程式碼檔案之間的對應關係,通過程式碼分析走通幾個關鍵的、有代表性的執行流程。
這個層次的基本定位是“深入”,開始理解這個專案的實際實現,能夠真正將專案的功能、工作原理和程式碼實現對應起來,獲得對這個專案工作過 程的直觀認識。這個層次是學習開源專案程式碼的真正開始。如果希望基於這一專案進行應用開發,或者針對與這一專案密切相關的其他專案進行工作時,則對專案本 身的程式碼進行這一層次的理解,會很有幫助。
第四層次:瞭解該專案所有程式碼模組、程式檔案的作用,走通所有主要執行流程。
這個層次的基本定位是“掌握”,能夠比較全面、系統地理解這個專案的設計和實現,並且熟悉專案各個部分的程式碼。如果希望對專案進行深度定製修改,或者對社群有所貢獻,則應當以達到這個層次作為目標。
第五層次:鑽研、領悟該專案的各種設計思想與程式碼實現細節。
這個層次的基本定位是“精通”,精益求精,學無止境。這是大神們追求的境界。如果希望成為專案社群的重要貢獻者乃至核心貢獻者,則應當以這個層次作為努力的目標。
綜上,對於一個開源專案的學習過程可以大致分為五個層次。至於到底要學習到什麼階段,投入多少相關精力,則完全取決於學習的目的。

2.        知識基礎
學習一個開源專案需要的知識基礎主要包括:
1)該專案涉及的技術領域的背景知識。
舉例而言,分析Linux Kenrel,則應該瞭解作業系統原理;學習OpenStack,則應該知道什麼是雲端計算。如果沒有這些背景知識作為基礎,上來就死磕原始碼,只能是事倍功半。
2)        該專案開發使用的語言及其各種開發除錯工具
這個就無需多言了。
3)        英語
很遺憾,目前為止真正流行的開源專案大部分不是起源於國內。因此,除了學習個別極其流行、文件完備的專案之外,大家還是需要自行蒐集閱讀英文資料參考。學好英語很重要。
當然,到底需要準備多少知識基礎,完全取決於學習的目的和層次。如果只是想科普一下,也就不必太過麻煩了。

3.        學習思路
學習一個專案的過程,其實就是由表及裡瞭解分析它的過程。上述提及的五個學習層次便組成了這樣一個逐漸深入的過程。在此基礎之上,學習、分析程式碼的過程,也可以嘗試做到由表及裡、逐漸深入。
在剛開始接觸一個專案的時候,我們看到的其實就是一個黑盒子。根據文件,我們一定會發現盒子上具有若干對外介面。通常而言,這些介面可以被分為三類:
-        配置介面:用於對盒子的工作模式、基本引數、擴充套件外掛等等重要特性進行配置。這些配置往往是在盒子啟動前一次性配好。在盒子的工作過程中,這些配置或者不變,或者只在少數的情況下發生改變。
-        控制介面:用於在盒子的工作過程中,對於一些重要的行為進行操縱。這是盒子的管理員對盒子進行控制命令注入和狀態資訊讀取的通路。
-        資料介面:用於盒子在工作過程中讀取外部資料,並在內部處理完成後向外輸出資料。這是盒子的使用者真正關心的資料通路。
因此,在分析一個開源專案的程式碼時,可以圍繞重要的配置、控制、資料介面展開分析工作,特別應該注意理解一個關鍵的介面背後隱藏的操作流 程。例如,針對資料介面,至少應當走通一條完整的資料輸入輸出流程,也即在程式碼中找到資料從輸入介面進入盒子後,經過各種處理、轉發步驟,最終從輸出介面 被傳輸出去的整個執行過程。一旦走通了這樣一條流程,則可以將與資料處理相關的各個主要模組、主要步驟貫穿起來,並將邏輯模組圖上和文件中的抽象概念對應 到程式碼實現之中,可以有效推進對於專案的深入理解。
在實踐這一思路的過程中,筆者建議可以優先從控制介面和資料介面中各自選擇一二重要者進行背後的執行流程詳細分析,力爭找到其中每一步的 函式呼叫及資料傳遞關係(對於一些系統、應用庫提供的底層函式可以先行跳過以節省時間)。這一工作完成之後,則第1節中第三層次的學習目標即可初步達成。
配置介面在不同的專案中的重要程度不同。對於一些架構極為靈活、配置空間甚大的專案(如OpenStack的Ceilometer),則可以適當多花些時間加以研究,否則簡單瞭解即可。
對於這個學習思路,下文中還將結合例項進行進一步的說明。

4.        若干小建議
以下是筆者的一些零散建議,供大家參考。
1)做好記錄
在剛剛入手開始學習某個專案的原始碼時,其實很有點破譯密碼的感覺。大量的資料結構和函式方法散落在程式碼的各個角落裡,等待著學習者將它 們貫穿到一個個重要的執行流程中。因此,在分析學習的過程中,無論有什麼零散收穫,都值得認真記錄下來。珍珠自然會串成項鍊的。
2)不要過分糾纏於細節
立志搞懂一個專案的每行原始碼是值得尊敬的,但至少在剛剛入手的時候是沒有必要的。如果過於糾纏於程式碼的實現細節,則可能很快就被搞得頭 暈眼花不勝其煩了(看英文資料的時候,每遇到一個不認識的詞都要立刻查詞典麼?)。不妨避免細節上的過度糾纏,還是先儘快走通關鍵的執行流程,將專案的骨 幹框架搭起來,然後再以此為參照,就可以清晰判斷什麼程式碼值得深入分析,什麼地方可以簡單略過了。
3)想像和聯想很重要
如前所述,從零開始搞懂一個專案的程式碼,就像破譯密碼。因此,不妨展開合理的想象和聯想,將各個零散的發現和理解聯絡起來,並加以分析印 證。在這個過程中,對專案所在領域的背景知識、對專案本身的邏輯框架和工作原理等方面的理解,都是想像和聯想的參照與指導。此外,一些關鍵的函式名、變數 名等等都是聯想的hint。本質上,程式語言也是語言,而程式程式碼就是說明文。在分析程式碼時,一定要超越語言和程式碼的細節去理解被說明的事物本身。
4)該搜就搜
分析程式碼的時候,很容易出現的情況就是,一個執行流程走到半截找不到下一步了。。。在這種情況下,當然首先還是推薦採用各種除錯工具的單 步執行功能加以跟蹤。如果暫時不會,或者種種原因只能進行靜態程式碼分析,那麼該搜就搜吧。各種IDE工具的文字搜尋都能用,哪怕是grep也行。至於到底 以什麼為搜尋關鍵詞,就需要琢磨琢磨了。
5)外事不決問google,內事不決問百度
如題,不解釋。

5.        一個例子:OpenStack Cinder分析
此處將以OpenStack Cinder為例,並結合KVM/Qemu和Ceph,說明如何參考上述思路對一個開源專案進行分析。
可能有朋友奇怪為什麼選這麼個東東做例子。這個吧。。。寫文章是忽發起想,舉例子是隨手抓來。木有原因。。。
首先,想對Cinder進行分析,一定要了解若干相關的基礎知識。什麼是雲端計算?什麼是塊儲存?什麼是OpenStack?Cinder在OpenStack裡的作用?等等等等。如果對這些東西沒有概念,則後續學習是很難開展下去的。
在此基礎上,如果有條件,則最好能夠親自部署和實際操作一下Cinder(包括必要的其他OpenStack元件),以便對Cinder 獲得一個直觀的認識和體驗,為後續分析提供一些參考。此處假定Cinder使用的後端是Ceph,而OpenStack上執行的虛擬機器是KVM。
然後,應該從概念上對我們要分析的系統的邏輯框架有個理解。從總體的範疇上講,應該瞭解Horizon和Nova各自的邏輯模組結構,以 及它們和Cinder的協同工作方式、關係。這部分與Cinder的控制介面及執行路徑分析密切相關。此外,還應該瞭解Cinder和KVM/QEMU、 Ceph之間的相互關係。這對於真正理解Cinder很有幫助。從Cinder自身而言,應該瞭解其內部邏輯模組構成、各自的功能、相互間的控制、資料連 接關係等。
在完成上述準備之後,則可以開始對Cinder的程式碼進行分析了。如前所述,應該考慮在控制介面和資料介面中各自選擇一兩個關鍵的、有代表性的加以分析。至於配置介面,假定其實現了某一配置即可,暫時不需要過多花費時間。
Cinder的核心功能其實是OpenStack上的volume管理。至少在Cinder+Ceph方案中,Cinder自身並不在數 據傳輸關鍵路徑上。因此,控制介面的分析就是Cinder原始碼分析的重中之重。就入手階段而言,則有兩個介面及其對應執行流程可以作為Cinder分析 的起點,即volume的create和attach操作。如果能夠徹底打通這兩個操作的執行流程(至少要看到Cinder與Ceph通過librbd交 互的層面),則對於真正理解Cinder的功能與實現大有幫助。
雖然基於KVM的虛擬機器在通過QEMU訪問Cinder建立的、Ceph提供的volume時並不通過Cinder,也即,這一部分的源 程式碼其實已經超出了Cinder原始碼學習的範疇,但是,如果希望真正徹底地理解Cinder,則對於這一部分知識還是應該有所涉獵,至少應該有概念上的 瞭解。
在達到上述階段之後,則可以根據自身的需求決定後續計劃了。

以上就是筆者結合個人經驗對開源專案學習方法給出的若干建議。見解粗淺,歡迎指正,非常感謝~
回覆

相關文章