1. 程式人生 > >如何閱讀他人的專案原始碼程式

如何閱讀他人的專案原始碼程式


相信很多人和我一樣,面對著別人密密麻麻的程式碼,寧願自己從零開始編寫自己的程式碼,也不願在別人程式碼的基礎上修改: 閱讀別人的程式碼太痛苦了! 在註釋不明確、技術文件缺失,這一行行的程式碼猶如閱讀天書一般,痛苦、煎熬,迷茫。因此,對於閱讀別人的程式碼,我從內心有一種強烈的抵制情緒,甚至有些恐懼。
然而,閱讀他人的專案原始碼是每一個寫程式的人(我只是個在專案需要的時候偶爾寫程式的,不敢自稱程式設計師)必須經歷的事情。也許我們想提升自己的程式設計技能,學習他人優秀的程式設計風格,那閱讀優秀的專案程式碼是畢竟的途徑;也許我們要研究某方面的功能或技術,那如果某個專案原始碼中已經有該技術或者功能的實現,根據原始碼“逆向工程”也是個方法;也許我們需要被迫接手別人未完成的專案,需要在別人已完成部分的基礎上實現功能的修改或則專案的移植
,閱讀他人原始碼則關係到我們吃飯的本領。恩,我就是屬於第三種,為了移植別人專案中的功能而被迫硬著頭皮去閱讀已有的程式碼。為了讓自己堅持下去,我逐漸說服自己要樂於從閱讀他人程式碼中學習,你看,閱讀他人程式碼的好處多多呀/微笑臉。與其在內心中一直抗拒閱讀他人程式碼,不如改變自己的心態,鍛鍊自己閱讀他人程式碼的能力和技巧,用熟練的方法和套路提高閱讀他人原始碼的體驗
我認為生活中遇到的絕大多數事情都可以總結出一種比較高效做事方法,或者叫套路,在閱讀他人專案原始碼這件事情上也不例外。在看了一個月程式碼的基礎上,綜合前輩們的經驗和自己的親身體會,總結出了一套比較高效地閱讀他人專案原始碼的方法,如果你感覺叫套路或者方法有點兒太low,咱可以改頭換面叫藝術。在我們遵循這種方法去閱讀程式碼時,一般都會取得事半功倍的結果,希望自己今後能不斷實踐並優化這套方法,也希望能對正因閱讀他人程式碼而苦惱的你有所幫助。

備份並編譯執行程式碼

拿到專案原始碼之後,首先應該對程式碼進行備份,因為很可能我們在哪兒就不小心改動了程式碼,養成備份的好習慣是很重要的。然後我們可以在IDE中編譯執行,雖然看不到專案的細節,但是通過執行程式,我們會對程式的功能和執行過程有更加直觀的認識。同時,編譯執行的過程會讓你瞭解到它使用的庫、它所依賴的開發框架等等,這是提高我們對某個特定專案理解的好方法。如果我們想編寫與正在探究的特定專案類似的自己的軟體,可能會對我們應該使用的框架或庫有一些想法。

熟悉專案程式語言的語法和慣例用語

我們要對專案程式碼的程式語言有一定的瞭解,想要讀英文小說,起碼應該學習一下英語單詞和語法吧。每種語言都有自己的一套約定、樣式和語法,深入瞭解某個特定語言有助於提高程式碼閱讀技能。同時,我們要熟悉這種語言程式設計的一些慣例,例如基本的命名原則

。我們知道命名一般有駝峰法、匈牙利命名法、帕斯卡命名法,倘若我們熟悉這戲命名原則,則很容易辨別出所閱讀程式碼的命名方式,那麼後面閱讀的時候通過變數和函式的名字我們就可以獲得比較豐富的資訊。因此,在拿到程式碼後,首先要找一下是否有程式命名範例說明,沒有的話自己根據程式碼總結出命名規則,這對後續提高閱讀速度是十分有幫助的。

看專案文件,有機會可向專案開發人員請教

公司的專案程式碼一般都會有相關的設計文件,描述專案的設計過程和基本的內容框架,通過這些文件,我們對專案可以有個整體的認識,比如專案分為幾個模組兒,各有什麼功能?使用了什麼開源庫?在程式碼看到一定程度後,可以帶著問題和自己的理解去想專案的開發人員請教,因為他們對程式碼的熟悉程度比我們強,比自己在那憋著瞎猜程式碼的含義要高效得多?再說,你幫我下,我幫你下,一來一回還能增加感情呢~但是注意一定是帶著問題和自己的理解去溝通交流,否則啥都沒看就去問,很容易招致他人的反感。

自上而下構建專案程式的系統架構

閱讀程式碼很容易陷入一個誤區:剛開始就企圖把所遇到的每一行程式都搞明白其功能和實現。一葉障目,不見泰山。過於糾結具體的實現細節會在最開始就把我們陷於泥潭之中而不能前進,浪費時間並消磨我們閱讀程式碼的耐心和信心。相反,在最開始時我們應該專注於掌握專案程式的系統架構,根據其模組兒劃分和呼叫邏輯在腦海裡構建其骨架,即要知道它先幹嘛、再幹嘛,為了幹這個需要與哪些模組兒進行什麼互動,從巨集觀上對專案有一個全面的認識。為了弄清其架構,我們可以採取top-down的方法,一般可以從其主函數出發,一般是main()函式或者其他函式,然後順著專案程式的主要功能這個線索一路走下去,根據函式的名字以及層次關係確定每一個函式的大致用途即可,將理解作為註解寫在這些函式的邊上,不用關注這些函式的具體實現。在閱讀時,要利用uml建立各類物件之間的關係,並根據自己要展開的層級,隨手在筆記本上繪製出樹狀結構,忽略對系統架構不重要的細節,逐漸建立該專案程式碼的系統架構。注意在該步驟中一定要注意展開的層級,這涉及到這部分工作量的問題,究竟需要展開到那一層,需要根據我們的系統架構定位有關,要看我們所希望的系統架構具體到哪一個層次。

建立系統架構和功能邏輯之間的關聯

在完成系統架構的搭建之後,我們需要根據程式功能,理解系統架構中每一部分的功能,以及其和其他部分的邏輯互動。這一步對於我們進一步理解系統架構的邏輯,以及後面對每個功能模組兒詳細功能的深入探究是很重要的。這個過程與上一個過程有重疊的部分,在對應完每部分的功能之後,我們要對整個系統功能進行模擬邏輯推理,確定我們猜測的各模組兒的功能是合理的。

核心程式碼重點剖析與註釋

完成系統架構搭建之後,需要轉入bottom-up這一部分是我們理解程式某一個程式功能的重要過程,使我們閱讀程式碼的核心之一。此時我們應該要逐行進行閱讀,搞清楚每個語句的功能和實現方法,搞清變數的意義和關聯關係,搞清實現的邏輯和演算法。從我們最感興趣的一個點,開始設定斷點,跟進去看發生了哪些事情,這一塊兒和架構設計哪一塊是match的。然後就是閱讀過程中註釋的書寫了,這是加深程式理解的重要方法。
基本原則是:

  • 猜測的去寫,剛開始閱讀一個程式碼的時候,很難一下子就確定所有的函式的功能,不妨採用採用猜測的方法去寫註解,根據函式的名字、位置寫一個大致的註解,當然一般會有錯誤,但你的註解實際是不斷調整的,直到最後你理解了全部程式碼。
  • 按功能去寫,別把註解寫成語法說明書,千萬別看到fopen就寫開啟檔案,看到fread就寫讀資料,這樣的註解一點用處都沒有,而應該寫在此處開發引數配置檔案(****。dat)讀出系統初始化引數。
  • 在寫註解的使用另外要注意的一個問題是分清楚系統自動生成的程式碼和使用者自己開發的程式碼,一般來說沒有必要寫系統自動生成的程式碼。象delphi的程式碼,我們往往要自己編寫一些自己的程式碼段,還要對一些系統自動生成的程式碼段進行修改,這些程式碼在閱讀過程是要寫註解的,但有一些沒有修改過的自動生成的程式碼就沒有必要寫註解了。
  • 在主要程式碼段要寫較為詳細的註解。有一些函式或類在程式中起關鍵的作用,那麼要寫比較詳細的註解。這樣對你理解程式碼有很大的幫助。5對你理解起來比較困難的地方要寫詳細的註解,在這些地方往往會有一些程式設計的技巧。不理解這些程式設計技巧對你以後的理解或移植會有問題1

調整心態,反覆閱讀

和看晦澀難懂的樹木一樣,程式碼也需要反覆閱讀才能逐漸增加理解。我有個好心態,就是在遇到難懂的書目和程式碼時,我總是告訴自己不要著急,一邊看不懂再來一遍,看個三五遍自然懂了,所謂“書讀百遍,其意自現”嘛。其實遠遠不用5遍,大概三遍左右一般就能弄懂了,5遍的時候已經了熟於心了。專案原始碼的程式碼量多沒啥,但是我們自己心裡不要著急,慢慢來,自己努力的功夫到了,多花點時間在看程式碼思考程式碼上,程式碼總會被你一點點感動的。如果遇到看不懂程式碼的情況,就分析下自己為什麼看不懂?是專案使用了自己不熟悉的設計模式?還是一些業務領域基礎知識自己沒有掌握?或者是自己對專案框架的理解不對導致的,要自己主動的分析。

工欲善其事,必先利其器

用著順手的IDE真的會為我們閱讀程式碼節省很多時間。由於工作環境限制,剛開始時我在VS2003上面閱讀專案程式碼,那體驗額emmmm…無法更改IDE,我就找個輔助工具吧。後來找到了VAssistX,真的方便了很多,閱讀效率和心情都得到了很大提升。據網友們推薦,source insight 看程式碼很不錯,以後我也試試。同時,我們也可以用EA(Enterprise Architecture)逆向工程繪製工程的uml 類圖,幫助我們理解專案中各類之間的呼叫關係。

揣摩作者的程式設計習慣與思想

除了工具及技巧之外,「想要閱讀程式程式碼,得先試著閱讀寫這個程式程式碼的程式人的心。」這句話說來十分抽象,或許也令人難以理解。
當你在閱讀一段程式程式碼時,或許可以試著轉換自己的立場,從旁觀者的角度轉換成為寫作者的心態,揣摩原作者的心理及處境。當你試著設身處地站在他的立場,透過他的思考方式來閱讀、追蹤他所寫下的程式程式碼,將會感覺更加流暢。我在閱讀非自己所寫的程式程式碼時,會觀察原作者寫作的習慣,藉以對應到腦中所記憶的多種寫作模型。在閱讀的過程中,讀完幾行程式程式碼,我會試著猜想原作者在寫下這段程式程式碼時的心境。他寫下這段程式程式碼的用意是什麼?為什麼他會採取這樣的寫法?順著原作者的思考理路閱讀,自己的思考才能更貼近對方寫作當時的想法。當你短暫化身為原作者時,才能更輕易的理解他所寫下的程式程式碼。如果你能知道原作者的背景,程式設計時的偏好,閱讀他的程式程式碼,就更能得心應手了2
最後,推薦大家一本書,《程式碼閱讀與實踐》,可能大家看完會有更多收穫。

祝楓
2018年9月30日於深圳