一、Best Practice
注釋應該聲明代碼的高層次意圖,而非明顯的細節
反例
說明
上文方法用於根據參數產生簽名,注釋中詳細描述了簽名演算法的實現步驟,這其實就是過度描述代碼明顯細節
正例
總結
1. 注釋一定是表達代碼之外的東西,代碼可以包含的內容,注釋中一定不要出現
2. 如果有必要注釋,請注釋意圖(why),而不要去注釋實現(how),大家都會看代碼
在檔案/類層級使用全域注釋來解釋所有部分如何工作
正例
總結
通常每個檔案或類都應該有一個全域注釋來概述該類的作用
公用api需要添加註釋,其它代碼謹慎使用注釋
反例
說明
以上介面提供dubbo rpc服務屬於公用api,以二方包的方式提供給調用方,雖然代碼簡單缺少了介面概要描述及方法注釋等基本資料。
正例
總結
公用api一定要有注釋,類檔案使用類注釋,公用介面方法用方法注釋
在注釋中用精心挑選的輸入輸出例子進行說明
正例
總結
對於公用的方法尤其是通用的工具類方法提供輸入輸出的例子往往比任何語言都有力
注釋一定要描述離它最近的代碼
反例
說明
該方法有一行代碼從map裡刪除了一個資料,注釋放在了put調用之前,而沒有直接放在remove之前
正例
總結
注釋要放在距離其描述代碼最近的位置
注釋一定要與代碼對應
反例
說明
注釋中說明產生隨機字串的長度不能超過16字元,實際代碼已經修改為32個字元,此處注釋會產生誤導讀者的副作用
正例
總結
1. 注釋一定要與代碼對應,通常代碼變化對應的注釋也要隨之改變
2. 若非必要慎用注釋,注釋同代碼一樣需要維護更新
一定要給常量加註釋
反例
正例
總結
給每一個常量加一個有效注釋
巧用標記(TODO,FIXME,HACK)
1. TODO 有未完成的事項
2. FIXME 代碼有已知問題待修複
3. HACK 表示代碼有hack邏輯
樣本
配置標記
可以擴充IDE修改標記的配置,比如加入解決人,關聯缺陷等資訊,以IDEA為例修改入口如下:
總結
1. 巧用TODO、FIXME、HACK等註解標識代碼
2. 及時處理所有標識代碼,忌濫用
適當添加警示注釋
正例
說明
該方法建立了一個大小固定為1且類型為Map的數組鏈表,這個用法比較奇怪,需要注釋說明原因
總結
代碼裡偶爾出現一些非常hack的邏輯且修改會引起較高風險,這個時候需要加註釋重點說明
注釋掉的代碼
反例
說明
常見套路,為了方便需要的時候重新複用廢棄代碼,直接注釋掉。
正例
同上,刪除注釋部分代碼
總結
不要在代碼保留任何注釋掉的代碼,版本管理軟體如Git可以做的事情不要放到代碼裡
循規蹈矩式注釋
反例
說明
分析上述代碼可以發現兩處注釋非常彆扭和多餘:
1. 類注釋使用了預設模版, 填充了無效資訊
2. IDE為Getter及Setter方法產生了大量的無效注釋
正例
總結
1. 不要保留任何循規蹈矩式注釋,比如IDE自動產生的冗餘注釋
2. 不要產生任何該類注釋,可以統一配置IDE達到該效果,推薦使用靈狐外掛程式
日誌式注釋
反例
說明
修改已有代碼很多人會手動添加註釋說明修改日期,修改人及修改說明等資訊,這些資訊大多是冗餘的
正例
代碼同上,刪除該注釋
總結
不要在代碼中加入代碼的著作資訊,版本管理可以完成的事情不要做在代碼裡
“拐杖注釋”
反例
說明
範例程式碼簡單實現了更新指定map k-v等功能,如果目標map不存在則使用指定k-v初始化一個map並返回,方法名為 updateConfigWithSpecifiedKV ,為了說明方法的完整意圖,注釋描述了方法的實現邏輯
正例
總結
拋棄“拐杖注釋”,不要給不好的名字加註釋,一個好的名字比好的注釋更重要
過度html化的注釋
反例
說明
類注釋使用了大量的html標籤用來描述,實際效果並沒有帶來收益反而增加閱讀難度
正例
總結
1. 普通商務記事謹慎使用html標籤,它不會給你帶來明顯收益,只會徒增閱讀難度
2. 如果是公用api且用於產生javadoc可以考慮加入必要的html標籤,比如連結,錨點等
二、程式設計語言注釋實踐
Java
檔案/類注釋規範
目前IDE安裝 靈狐 後會自動設定IDE的file templates為如下格式:
強烈建議使用如上配置,統一、簡潔就是最好。__如果有特殊需要需要定製類注釋可以參考:
方法注釋
IDE提供了統一的方法注釋模版,無需手動設定,好的方法注釋應該包括以下內容:
1. 方法的描述,重點描述該方法用來做什麼,有必要可以加一個輸入輸出的例子
2. 參數描述
3. 傳回值描述
4. 異常描述
舉個例子:
塊注釋與行注釋
1. 單行代碼注釋使用行注釋 //
2. 多行代碼注釋使用塊注釋 /* */
Python
檔案注釋
重點描述檔案的作用及使用方式
類注釋
1. 類應該在其定義下有一個用於描述該類的文檔字串
2. 類公用屬性應該加以描述
函數注釋
1. Args:列出每個參數的名字, 並在名字後使用一個冒號和一個空格, 分隔對該參數的描述.如果描述太長超過了單行80字元,使用2或者4個空格的首行凸排(與檔案其他部分保持一致). 描述應該包括所需的類型和含義. 如果一個函數接受*foo(可變長度參數列表)或者**bar (任意關鍵字參數), 應該詳細列出*foo和**bar.
2. Returns: 描述傳回值的類型和語義. 如果函數返回None, 這一部分可以省略
3. Raises:列出與介面有關的所有異常
多行注釋與行章節附註釋
1. 複雜操作多行注釋描述
2. 比較晦澀的代碼使用行章節附註釋
Golang
行注釋
常用注釋風格
包注釋
/**/ 通常用於包注釋, 作為一個整體提供此包的對應資訊,每個包都應該包含一個doc.go用於描述其資訊。
JavaScript
常用/**/與//,用法基本同Java。
Shell
只支援 # ,每個檔案都包含一個頂層注釋,用於闡述著作權及概要資訊。
其它
待完善
小結
本文先總結了注釋在編程中的最佳實務情境並舉例進行了說明,然後就不同程式設計語言提供了一些注釋模版及規範相關的實踐tips。關於注釋我個人的認知是:注釋即代碼,注釋即文檔,寫好注釋一個工程師必備的素質之一,在整潔代碼前提下,更少的注釋是跟高的追求。關於注釋的實踐暫時寫到這裡,後面會持續完善,也歡迎大家提供好的tips,文中代碼大多出自於日常商務專案,也有部分摘自開源庫,若有不妥之處敬請指正。
本文作者:竹澗
閱讀原文
本文為雲棲社區原創內容,未經允許不得轉載。