- 原文地址:How to read code without ripping your hair out
- 原文作者:Sun-Li Beatteay
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:Mcskiller
- 校對者:xionglong58, Endone
- 多寫程式碼
- 多讀程式碼
- 每天都完成以上內容
這是我在兩年前轉向程式設計時給我自己的要求。幸運的是,現在有很多線上編寫程式碼的課程和教程可以教你寫程式碼,然而他們卻基本上都沒有去教你如何閱讀程式碼。
這是一個重要的區分點。隨著進入科技領域的程式設計訓練營畢業生數量的 飛速增長。強調閱讀原始碼變得更加重要。Brandon Bloom 寫道:
如果它在 你 的機器上執行,它就是 你 的軟體。你 應該對此負責,所以 你 必須對它瞭如指掌。
雖然每個程式設計師都應該閱讀原始碼,但 事實 並非如此。許多程式設計師不願意閱讀原始碼是因為它閱讀起來很難,容易打擊他們的信心,並且讓他們感到自己很蠢。我知道,因為這就是我的感受。
其實只是方法不對
在我閱讀其他人的程式碼時,我想出了一個只需要三步的閱讀方法。可能有些人已經在遵循這些步驟,但我相信大部分人是沒有的。
我的步驟如下。
1. 選一個你感興趣的點
回想我第一次閱讀原始碼的時候,那簡直是一場災難。
我當時正在學習 Sinatra,然後我想更好的瞭解底層執行機制。然而,我並不知道應該從哪裡開始讀,於是我找到了它在 Github 上的 repo 然後隨便開啟了一個檔案。不開玩笑,我確實是這樣做的。
我想我可以花一個下午來研究它,然後在吃晚飯的時候就可以完全掌握。畢竟,閱讀我自己的程式碼很容易,閱讀別人有什麼不同?
我們都知道接下來會發生什麼。可以這麼說,我當時的感受像一頭撞在了一堵文字牆上一樣。
我一次想學的東西太多了。許多初學者在第一次閱讀原始碼的時候也會犯同樣的錯誤。
心智模型是一點一點建立起來的,閱讀程式碼也應該如此。
不要去試圖以堅持努力來消化 1000 行程式碼,專注於一個主題。如果能夠細化到單個方法更好。
有一個細化的焦點能夠讓你分清什麼是相關的,什麼是不相關的。沒有必要去理會那些不相關的東西。
然而,選擇一個特定的主題並不能解決你的所有問題。知道它在程式碼庫中的位置仍然是個難題。
這就是第二步的問題了。
2. 找到一個切入點
現在你有了一個想要學習的目標,接下來應該怎麼做?
幸運的是,程式語言附帶了檢查工具。
物件的類,類的祖先,堆疊跟蹤,還是某種方法的所有者,這是大多數語言都有的特性。無論你是想知道哪一個,一旦你開始分析程式碼庫,你會遇到一系列問題。
與其用文字來解釋這個概念,不如用程式碼展示來得更快。
開始分析
假設我想學習更多 ActiveRecord 的相關知識。然後我已經把重點縮小到了 belongs_to
方法上,現在我想了解它如何影響 ActiveRecord 模型。
ActiveRecord 是 Rails 的一部分,它是用 Ruby 構建的。Ruby 提供了大量開發工具。
我的第一種方法是使用除錯工具,比如用 pry
gem 來剖析我的 ActiveRecord 模型。對於之前的假設,這就是我選擇除錯的模型的程式碼。
class Comment < ActiveRecord::Base
belongs_to :creator, foreign_key: 'user_id', class_name: 'User'
belongs_to :post
binding.pry
validates :body, presence: true
end
複製程式碼
注意 binding.pry
語句。當 Rails 遇到這行程式碼時,pry
將會在執行中期暫停應用程式並開啟命令列提示符。
下面是我研究 belongs_to
關聯的時候在控制檯使用的示例交換。
-
我的所有的輸入內容都是在
pry >
之後。 -
=>
顯示控制檯的輸出。
pry> class = belongs_to(:post).class
=> ActiveRecord::Reflection::AssociationReflection
pry> class.ancestors
=> [ActiveRecord::Reflection::AssociationReflection,
ActiveRecord::Reflection::MacroReflection,
...omitted for brevity ]
pry> defined? belongs_to
=> "method"
pry> method(:belongs_to).owner
=> ActiveRecord::Associations::ClassMethods
複製程式碼
如果你不太能理解 Ruby,並且這個交換讓你感到困惑,可以看看我的提示。
-
當
belongs_to :post
執行時,它返回一個AssociationReflection
類的例項。 -
MacroReflection
是AssociationReflection
的父類。 -
belongs_to
是一個類方法,它是在ActiveRecord::Associations
內部的ClassMethods
模組上定義的。
現在我有了一些線索,但是我應該遵循哪一條呢?因為我對 belongs_to
方法本身更感興趣,而不是它的返回值,所以我決定去檢視 ClassMethods
模組。
3. 跟隨線索
現在你已經有了想要跟隨的目標,剩下的就是跟隨它,直到找到你的答案。這似乎是一個簡單的步驟,但這正是大多數初學者犯錯的地方。
其中一個原因是,倉庫是沒有目錄的。我們任由維護人員以可讀的方式組織他們的檔案。
對於有很多維護者的大型專案,這通常不是問題。
但對於一個小專案,你可能會發現自己要費力地逐個處理檔案,逐個破譯名稱變數,然後就會多次遇到“這是從哪裡來的”的情況。
GitHub 搜尋
有一個工具可以幫助我們更容易完成這個任務,就是 GitHub 搜尋(我們假設你正在閱讀的專案是在 Github 上的)。Github 搜尋非常方便,因為他能夠顯示所有匹配搜尋查詢的檔案。它還能顯示符合查詢的內容在檔案中的位置。
為了得到最好的結果,你需要讓你的搜尋儘可能具體。這需要你對你想找的內容有一個概念。盲目的搜尋 Github 是沒有用的。
回到步驟 2 中的示例,我試圖在 ActiveRecord::Associations
中找到 ClassMethods
模組。用外行人的話來說,我正在尋找位於 ActiveRecord
模組內部的模組 Associations
中的 ClassMethods
模組。此外,我也在尋找 belongs_to
方法。
這是我的搜尋查詢。
結果準確地顯示了我正在尋找的東西。
可能需要更多研究
Github 搜尋將會顯著的縮小你的搜尋範圍。因此,你可以更容易的找到一個深入程式碼庫的切入點。
不幸的是,找到類或者方法不一定能給出問題的答案。你可能發現你從一個模組跳到另一個模組,直到你瞭解全域性。
在我的例子中,belongs_to
類把我導向了 BelongsTo
中的 build
方法。這讓我找到了 Association
的父類。
最後,我發現 belongs_to
讓 Rails 向我的模型新增了幾個例項方法,包括 getter 和 setter。它使用一種叫做超程式設計的高階程式設計技術來實現這一點。
Rails 還建立了一個 Reflection
類例項用於儲存 association 中的資訊。
來自 Rails API 文件:
Reflection 啟用了檢查 ActiveRecord 類和物件的關係和聚合的功能。例如,這種功能可以在 form builder 中使用,該 builder 接受一個 Active Record 物件然後根據其型別為所有屬性建立輸入欄位,並顯示它與其他物件的關聯。
挺簡潔的。
總結
雖然我不能保證解析別人的程式碼會很有意思,但這是值得的。它會給你的技術棧新增一項關鍵的技能,讓你更加自由。你將不會再依賴於完整的文件和示例,雖然文件很棒,但它並不是萬能的。正如 Jeff Atwood 說的:
你可能可以找到最好的,最權威和最新的文件,但是無論文件說什麼,原始碼才是最真實的。
所以快去練習這項技能吧!
我相信你現在肯定有一些你一直都想了解的東西。不要糾結於程式碼庫的大小。開啟你最喜歡的框架的倉庫然後開始學習。如果你按照我在文章中的步驟來,你很快就能成為一名原始碼專家。
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。