- 原文地址:How to read code without ripping your hair out
- 原文做者:Sun-Li Beatteay
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:Mcskiller
- 校對者:xionglong58, Endone
這是我在兩年前轉向編程時給我本身的要求。幸運的是,如今有不少在線編寫代碼的課程和教程能夠教你寫代碼,然而他們卻基本上都沒有去教你如何閱讀代碼。html
這是一個重要的區分點。隨着進入科技領域的編程訓練營畢業生數量的 飛速增加。強調閱讀源碼變得更加劇要。Brandon Bloom 寫道:前端
若是它在 你 的機器上運行,它就是 你 的軟件。你 應該對此負責,因此 你 必須對它瞭如指掌。android
雖然每一個程序員都應該閱讀源碼,但 事實 並不是如此。許多程序員不肯意閱讀源碼是由於它閱讀起來很難,容易打擊他們的信心,而且讓他們感到本身很蠢。我知道,由於這就是個人感覺。ios
其實只是方法不對git
在我閱讀其餘人的代碼時,我想出了一個只須要三步的閱讀方法。可能有些人已經在遵循這些步驟,但我相信大部分人是沒有的。程序員
個人步驟以下。github
回想我第一次閱讀源碼的時候,那簡直是一場災難。web
我當時正在學習 Sinatra,而後我想更好的瞭解底層運行機制。然而,我並不知道應該從哪裏開始讀,因而我找到了它在 Github 上的 repo 而後隨便打開了一個文件。不開玩笑,我確實是這樣作的。編程
我想我能夠花一個下午來研究它,而後在吃晚飯的時候就能夠徹底掌握。畢竟,閱讀我本身的代碼很容易,閱讀別人有什麼不一樣?後端
咱們都知道接下來會發生什麼。能夠這麼說,我當時的感覺像一頭撞在了一堵文字牆上同樣。
我一次想學的東西太多了。許多初學者在第一次閱讀源碼的時候也會犯一樣的錯誤。
心智模型是一點一點創建起來的,閱讀代碼也應該如此。
不要去試圖以堅持努力來消化 1000 行代碼,專一於一個主題。若是可以細化到單個方法更好。
有一個細化的焦點可以讓你分清什麼是相關的,什麼是不相關的。沒有必要去理會那些不相關的東西。
然而,選擇一個特定的主題並不能解決你的全部問題。知道它在代碼庫中的位置仍然是個難題。
這就是第二步的問題了。
如今你有了一個想要學習的目標,接下來應該怎麼作?
幸運的是,編程語言附帶了檢查工具。
對象的類,類的祖先,堆棧跟蹤,仍是某種方法的全部者,這是大多數語言都有的特性。不管你是想知道哪個,一旦你開始分析代碼庫,你會遇到一系列問題。
與其用文字來解釋這個概念,不如用代碼展現來得更快。
假設我想學習更多 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
模塊。
如今你已經有了想要跟隨的目標,剩下的就是跟隨它,直到找到你的答案。這彷佛是一個簡單的步驟,但這正是大多數初學者犯錯的地方。
其中一個緣由是,倉庫是沒有目錄的。咱們任由維護人員以可讀的方式組織他們的文件。
對於有不少維護者的大型項目,這一般不是問題。
但對於一個小項目,你可能會發現本身要費力地逐個處理文件,逐個破譯名稱變量,而後就會屢次遇到「這是從哪裏來的」的狀況。
有一個工具能夠幫助咱們更容易完成這個任務,就是 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、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。