在撰寫程式碼的同時,還要費心力去撰寫註解嗎?如果是撰寫程式的開發者,多半情況下,不愛或懶得寫註解,然而,若是接手維護其他開發者的程式,而程式碼中沒有(適當的)註解,那麼一定是罵聲連連。

撰寫程式的開發者,多半情況下不愛寫註解,基本的心態大概就是「我已經用程式碼寫下想做的事了,為什麼要寫註解?」就價值上來看,註解對開發者來說,通常不列為工作成果的一部份,畢竟專案都快生不出來了,「哪還有時間寫註解?」

其他不寫註解理由,還有:「爛程式碼才需要註解」甚至是「註解會洩漏商業機密」,或許,將來還會加上個理由:「註解會讓函式本體超過600個字元而影響效能」(https://goo.gl/pXUZNX)…XD

支持註解的一派,理由好像就比較單純了,因為「對日後程式碼的維護有幫助」,因而許多管理者或教師甚至會從維護的角度,要求開發者一定要寫註解,雖然讓註解成為正式工作內容的一部份,不過,在沒有規範或不適當規範下,註解反而會成為維護的負擔,像是為了註解而註解,產生許多無意義的註解,或是為了增加程式碼可讀性,而產生拼命掩蓋程式碼缺失的註解,久而久之,註解越來越沒有意義,甚至過時或淪於喃喃自語,而成為開發者發洩不滿的遊樂場。

兩派說法似乎都有其道理,實際上,正如程式碼撰寫上有所謂最佳實踐,註解撰寫上也應有其實踐經驗,然而,討論註解實踐之道的書籍或文件,這幾年雖然多了起來,不過仍屬少數,對註解較完整討論的書籍有《Clean Code》(在第四章),以及《The Art of Readable Code》(在第五與第六章),有篇〈The Most Important Code Isn't Code〉(http://goo.gl/QmtbBr)也值得參考。

〈The Most Important Code Isn't Code〉中談到的,其實是文件的重要性,不過,其中用了不少註解做範例,也清楚地列出文件的幾個目標與做法,像是讓未來的自己或其他開發者,在維護程式碼時更易進入狀況,驗證自己對程式碼有足夠的瞭解、令程式碼變得可測試、文件要能比較版本差異性、成為行銷賣點,以及作者本人也還在實證的最後一點――有助於床上功夫。

註解與程式碼的可讀性

「程式碼就是最好的註解」是近來很常提倡的一個說法,然而,大多數的程式碼沒有偉大到不需要註解(https://goo.gl/tsrypE),這說法並非不寫註解的萬用擋箭牌,而是用來檢視被註解的是否為「可讀性良好的程式碼」,重點在於想辦法重構程式碼,讓它變得更可讀,而不是用註解來掩飾程式碼本身的不可讀。若程式碼本身難以閱讀,又以「程式碼就是最好的註解」當藉口,那就真的只能寫個「慘」字了!

程式碼中變數、函式、類別、模組等的命名是個例子,如果發現自己正試圖用註解來拯救糟糕的名稱,比較好的方式或許是直接重新命名,或者是重構當時的程式碼區塊。

當試圖為一段程式碼區塊寫註解時,也許可以想一下,這個區塊是否能提取為一個獨立的函式,並給予適當命名來提高程式碼可讀性,當每個函式的實作本體夠小夠短,使用註解來掩護程式碼本身不可讀的可能性,才能越低。

那麼,如果命名夠清楚,而且每個函式的實作本體夠小夠短,足以自我解釋意圖之時,是否需要註解呢?因為每個程式語言或程式庫語法不同,程式碼的表達力確實會受到限制,因而有時雖然每個實作夠短,但如果註解可以加速閱讀程式碼,那麼註解就有存在的必要,或許像Java這類囉嗦的語言就是一個例子,然而公認表達能力好的Python,在《The Art of Readable Code》中,也有個不錯的例子:

# 移除第二個'*'後的所有東西

 

name = '*'.join(line.split('*')[:2])

 

無論如何,看這樣的註解,還是比直接看程式碼來得快了,對將來的自己,或者是接手的其他開發者來說,這類註解都有助於更快地瞭解程式本身,增加可維護性。

簡單來說,對於程式碼的實作來說,優先提高程式碼的可讀性,避免用註解為程式碼換句話說,或掩蓋可讀性的不足,然後,如《Clean Code》中談到的:「在最好的情況下,註解也只不過是必要之惡。」這必要之惡,就真的是在補程式碼本身的不足了。

需要學習的文件註解

除了在必要之時,補充程式碼的可讀性之外,註解的另一個形式是作為文件來使用,畢竟有一群人並非對程式內容如何實作有興趣,而是對怎麼使用程式有興趣,像是模組、套件的作用、類別的目的、頂層常數的意義、函式接受的引數與執行結果等。

對如何使用程式有興趣的,也有可能是開發者本身或其他開發者,因此,不少開發者往往也會將這類資訊,直接撰寫在原始碼之中,成為鄰近模組、套件、類別、常數、函式等位置的註解,然而,有的使用者需要的真的是一份文件,而不是程式碼,開發者不想做重複的事(把註解中的資訊重新撰寫為另一個文件),就有了專門從原始碼註解中產生文件的工具,各語言生態系中幾乎都有這類工具,像是JavaScript的JSDOC、Java的JavaDoc、Python的DocStrings,Go的godoc等。

這就成了註解存在的另一個重大理由,作為文件而存在,即使開發者的程式碼實作在可讀性上真的高到不需要註解,還是得有一份為使用者(也可能是開發者本身)考量,作為文件而存在的註解,這類註解的撰寫通常就需要學習,也需要有一定的慣例或形式了,像是Python在PEP 0257中,為DocStrings的撰寫做了規範,定義了模組、套件、類別、常數、函式等註解應當如何清楚地撰寫。各語言領域都應當從找出相關的實踐,來瞭解如何撰寫這類註解。

〈The Most Important Code Isn't Code〉中提到,為撰寫文件時,往往會令程式碼更具可測試性,一個有趣的事實是,在Python中使用註解撰寫文件時,註解中撰寫的程式碼範例,在遵守規範下,確實可使用doctest模組來直接運行測試。

對於作為文件的註解,有個重要的實踐是,在沒有工具的輔助,若直接閱讀原始檔中的註解,也應該是清楚易讀的,因此,註解中HTML標記之類會干擾閱讀的因素,應當避免,比較好的註解是應該是類似Markdown的寫法,然後由適當工具自動產生HTML,或其他格式的文件。

從多個視角看程式碼

談到註解的支持與否,多半與可維護性有關,只不過,可維護性這個目標太過籠統,因此就使得註解變得可有可無、沒有準則,甚至產生誤導之作用;然而,就跟寫技術文件、重構或測試案例一樣,無論是從程式碼的可讀性、文件需求、可測試性等方面,來看待註解撰寫時的作用與形式,通常也就是從其他視角看程式碼的時機。

因此,就像是重構或測試等受到重視,而成為程式訓練或開發流程的一部分,註解撰寫也應受到訓練或開發流程的重視,而成為其中一部分,以便有更具體的規範與目標,而不是放任開發者自由心證;或者也與重構或測試一樣,就像〈The Most Important Code Isn't Code〉最後提到的,這可以讓你對自己的程式碼更有自信!

作者簡介


Advertisement

更多 iThome相關內容