我的原始碼閱讀之道

身為開發者,只要體會過閱讀他人原始碼的收穫感,就必然會歌頌閱讀原始碼的重要性,那麼,在倡導閱讀程式碼的重要時,是對誰說的?

當然,這不會是已經有閱讀習慣的開發者,而是那些還沒能跨入閱讀門檻,或突破心理障礙的人們!其實,每個開發者的閱讀習慣與方法不同,多看幾個人的想法總是好的,這次姑且就來看看我的程式碼閱讀之道。

恐懼、麻煩、哪裡優質了?

為什麼不想閱讀原始碼?單是這個問題,就可能有多種答案,你得先搞清楚自己抗拒閱讀原始碼的原因。對單純只是初學程式的新手來說,答案基本上是應該對程式碼本身的恐懼,恐懼的理由也很多,怕看不懂語法、摸不清程式流程、無法理解抽象的目的、系統龐大到不知從何開始,要這類新手直接去找個開放原始碼專案來讀?有時看到這類建議,連我心裡都不免嘀咕著:「別鬧了!」

有時不願閱讀他人程式碼的不見得是新手,而是懶得去理解他人程式,嫌麻煩的開發者,因為那不是他們自己寫的程式,程式思路的出發點、寫作慣例、行為動作、歷史過程等各方面,對他們來說都是陌生的,想要他們閱讀、瞭解他人原始碼,必須得付出時間與心力,而最難且最常發生的抗拒,大概就是調整自己的心智模型,以符合原程式撰寫者(們)的(諸多)心智模型的過程。

會想閱讀某個原始碼的理由其實很多,然而,被閱讀的原始碼對象,不見得每個層面都是好的。網路上開放原始碼的專案很多,然而不見得每個專案都有良好可讀性、設計或架構,有時可學習的也許只是程式碼中隱含的演算法,有時甚至只是閱讀者越級打怪,卻因為沒有人帶領之下,看不出程式中優質之處,這類人不用多久,應該就會對閱讀原始碼失去興致。

目的導向的程式碼閱讀

如果,想體會原始碼閱讀之樂,請先搞清楚你的目的!

想靈活運用程式語言的自身特性而閱讀嗎?還是想瞭解程式的流程或演算法實現?你想知道各個抽象是如何產生與組合?還是想知道程式如何達到易於擴充的彈性?想學習程式如何寫得簡潔易讀?或是如何能構成DSL的風格?你已經習慣某種思維解法,但是想認識另一種模式或典範的實作方式,多一種設計思維?

無論是否為程式初學者,剛接觸一門新語言時,從既有的優質程式碼中,學習如何靈活運用語言特性,是最快也是閱讀程式碼時最直接的獲益。對於這類目的,我不建議直接從閱讀網路上的開放原始碼開始,因為原始碼中得同時瞭解的其他要素太多,就目的而言,不見得會是最快的方式,相對地,我會建議從Effective、Good parts、Best practice甚至是重構之類的書籍開始。

從書籍開始?那還叫做閱讀原始碼嗎?為什麼不是?像Effective這類的書籍,裡頭往往會擷取一些作者們閱讀過的原始碼作為案例,分析、評論他的好壞,加入作者的見解與改進,這就好像是有人帶著你閱讀程式一樣。類似地,如果想從原始碼中學習模式、架構、可讀性等,找個專門探討該主題的書籍作為開始,會遠比毫無方向就直接一頭栽入一大堆原始碼,來得有效率的多。

如果以瞭解開放原始碼中的程式碼流程或演算實作為目的,那麼最好是準備一些基本工具(視不同語言,實際工具會不同),對我來說,第一重要的是可找出caller和callee跳轉檢視工具,在面對龐大原始碼時,這可以初步檢視感興趣的部份、瞭解相同抽象層面間的流程,而不是立即落入逐行的程式碼細節,事實上,許多情況下,我們閱讀原始碼想從中學習的,並不是每一行的細節,而是開發者的整體思路。

當然,還是會有瞭解細節的時候,有時甚至得直接將程式運轉起來,這時你需要藉助Debugger,然後從一個使用者動作開始,逐步追蹤流程,而不是單靠肉眼與人腦運算來理解流程細節。除此之外,程式碼排版、語法關鍵字突顯之類的工具等,對於閱讀原始碼有著絕對的幫助!

動手使用、重構、複刻

開放原始碼專案中的程式碼千頭萬緒,該從哪邊下手?如方才所言「從一個使用者動作開始」,這個使用者動作,並不見得是終端機或者HTT P請求之類的,如果是個程式庫,你要做的,或許不是「閱讀」,而是「動手」,而第一步,是先用它來實際動手寫些程式。

你會需要查看官方文件瞭解使用方式,有時文件中會初步解釋背後原始碼運作原理,接著你可以針對某個感興趣的方法呼叫或物件使用,開始探索原始碼,然後,動手畫出流程、抽象元素或架構之類的圖解,若工具能幫你產生類別圖、相依圖之類的,可以善加利用。

如果程式碼的涵蓋範圍,逐漸超出能理解的範圍,那麼就動手重構吧!如果發覺到,自己正好瞭解了某個程式區塊的概念,並打算往下個程式區塊閱讀時,可以先將上個程式區塊重構出來成為一個小單元(函式、類別等),這樣可以減少自己記憶的細節,後續閱讀其他程式區塊的過程中,若要回顧先前區塊,也比較容易理解或修正。

在初學程式時,新手們總是會被告誡,不要覺得看懂書上範例就足夠了,還要動手實作,看看是否能在不看書的情況下,寫出可運作的範例。實際上,在閱讀原始碼時也是一樣,如果看懂了某個原始碼內容,試著在其他地方用上,若暫時沒有可運用的場合,那麼有個好方式,就是動手複刻該原始碼,複刻一開始可選擇一個較小範圍的對象,或者複刻一個簡易的專案原型。

在動手複刻時,不用複刻全部的功能或細節,只要複刻感興趣的部份就可以了,如果一下子不知道如何複刻,那麼可以從最簡單的需求開始,然後彷照複刻對象的流程,模式或架構等,逐步加上新功能,如果能完成複刻,不只能獲得最大的成就感,往往地,在複刻的過程中,因為會遇上許多的問題,從而能更進一步理解,原本的閱讀對象,為何會是如此撰寫。

讓閱讀原始碼成為習慣

如果你從沒閱讀過程式的原始碼,也許真的會覺得,閱讀原始碼是種什麼大事一樣,好像不從GitHub下載個幾萬行的程式庫讀一讀,就不是在閱讀原始碼似的。

實際上對我來說,閱讀原始碼可以從很多小地方開始下手,當你學習一門新語言時,開始運用一些簡單的標準程式庫時,只要對他們的運作稍微產生那麼一點疑惑,現代程式語言多半附帶有標準程式庫,直接打開它們開始研究,也是一種閱讀程式碼的方式。

也就是說,閱讀原始碼是可以隨時都做的事情,一開始可能要特意練習,依目前自己的程度,加減看看原始碼中能懂的部份,然而,只要時時日以練習,逐漸地就會成為一種習慣,當你有著這樣的閱讀習慣,遇到問題時,尋找相關原始碼就會是再自然不過的動作,若真的要對某個程式庫或框架等做整體性的閱讀,也不致於發生越級打怪的龐大挫折感,也能更有機會進入原開發者的心智模型,吸取其中最寶貴的經驗。

Reference