第4章:註解

「不要替糟糕的程式碼寫註解 ─ 重寫它」

「為什麼我如此鄙視註解?因為它們說謊。」

請記得,這的確是軟體界的常態,程式碼、註解、文件,這三項獨立的個體,三者內容背離的速度,總是隨時間加劇,除非可以有強而有力的規範、政策與資源支撐團隊成員維護它們的關連性。

然而,維護完整正確註解的成本如此龐大,如何撰寫最精簡的註解,以有效控制成本,並保持程式碼的可維護性,就是本章要討論的課題。

鮮少註解的整潔程式碼,遠勝於滿是註解的雜亂程式碼

有時,程式成品讓人困惑,並不是因為它缺少註解,而是它的語法、邏輯不夠精練/準確。
與其花時間在寫註解來解釋混亂的程式碼,不如花時間去整理它!

寫作文需要練習與反覆修改,如同不夠通順的文句應被修訂:「應該,好的文字要讓人看得情楚明白也沒有很多贅字才對(口語與別字)」。寫程式也是要再三斟酌,可以執行與通過測試只是基本要求,提升產出品質才是挑戰。

用程式碼表逹本意是書中對程式碼品質的理想,但在我們的專案環境中可能需要有所妥協、不能照單全收,我在章末心得再談一下這點。


應避免的項目 (糟糕的註解)

跳過原文的編排順序,這裡先來看看應避免的註解型式。

那些版本管理工具為你做的事

★ 日誌型註解

很久很久以前的專案,因為原始碼管理工具並未像今日如此完備,在專案開發規範中是要求撰寫這類檔案開頭註解的。如果今天你還在專案規範中看到這件事,請記得調整它。

★ 出處、署名

程式會交接,人員會離職,但這些註記作者是何人的註解,不會有人維護。
想知道這些資訊,去查詢版控工具中的記錄會更準確。

★ 被註解的程式碼

這些版控工具都記錄的東西,真的沒有必要留下,只會造成後續維護者的困惑。

  • 有些程式碼,可能是開發者為了不同執行環境留下的選項。我們應該思考的是,怎麼把它們拉到外部設定?舉例而言,我看過類似下面的 CODE。
    // final String password = "abcd!@#123";
    final String password = this.xxxConfig.getAsdtPassword();
    
    顯然原作者後來有試著把密碼內容透過另一個 config 元件取得。那麼第一行程式就應該是移除,而非只是註解,至少也該考慮以下註解方式,起碼在行尾的註解影響較少。
    final String password = this.xxxConfig.getAsdtPassword(); // @ 開發環境:"abcd!@#123"
    
  • 另一個相關情境是 CodeReview 的溝通階段,我認為 reviewer 有時可以先把原作內容註解掉,改以建議的實作代替。但原作者若同意此修改,應身負把註解程式碼移除的責任。

JavaDOC 與 開發規範之惡

★ 多餘的註解:沒有比程式碼本身透露更多資訊。

如果程式足夠簡明,沒有理由多寫一段註解提高不一致的風險。

尤其像 JavaBean 中典型的 Getter and Setter,完全沒有必要加上註解。本章許多小節都重複強調此點。

★ 規定型註解

如果在所屬專案開發規範中,有一則類似的條款:「所有的函式都必須要有完整JAVADOC格式註解」,工程師只會用像是 JAutoDoc 之類的工具程式,產出無用的多餘註解,以規避自動化檢核。

以下是我們專案目前的制式規範,有包含部分除外條款,可以參考看看:

  • 所有Class應使用JavaDoc的標準註解格式說明用途資訊。
  • 原則上所有Method應使用javaDoc的標準註解格式說明用途、參數、回傳值等資訊。
    • 但JavaBean之標準Getter/Setter若無進行特別處理,可省略。
    • 若為 private method,可省略標準參數、回傳值說明格式,簡單描述即可。
    • 變數或函式名稱足以說明用途者,可省略。
  • 一般 Method 內部流程,視邏輯複雜度應加上單行註解 // 逐步標明各區塊作用。
  • 所有 public 或可透過Getter/Setter存取之成員變數應加上註解或@Text。

★ 干擾型註解 (之一)

/** Default Construtor. */

此小節的例一貼近 '多餘的註解' 。

★ 可怕的干擾

由 規定型註解 衍生的 誤導型註解:複製貼上的大問題。

★ HTML型式

可以找找相關的討論資訊:Using Markdown Syntax in Javadoc

★ 函式標頭

替只做一件事的小型函式選一個好名稱,多半比將註解寫在函式標頭優雅。 通常是因為 開發規範 規定,所以才會有這類註解。

記得在規範中加上除外條款:變數或函式名稱足以說明用途者,可省略。

★ 非公共函式庫的 JAVA-DOC

沒有要


糟糕的註解會提高程式的維護成本

★ 喃喃自語:(不夠充分的註解 以及 留了註解就不做事)。

書中範例的問題是:它在例外區塊只寫下「發生了什麼」,但沒有說明「已經做了什麼」或「應該還要做什麼」?

★ 誤導型註解

範例 4-1 的註解,錯誤的解譯了原始程式碼表達的邏輯,如果這是一個被封裝提供呼叫的函式庫,使用者必須得要 TRACE 原始碼,才能知道為什麼執行結果與 API 說明不同。

所以,在這個開放原始碼盛行的世界,在使用從未用過的套件/API之前,除了看看說明文件,最好也看看它的原始碼。在其它關於測試/TDD的文章中,也有對此點的討論及解決之道。

★ 干擾型註解 (之二)

看例 4-4/4-5 時,請思考一下例外處理的相關討論

  • JDK 8 的語法也適合處理此情境:以我們的共用套件為例
UdeRuntimeUtils.quietRun(this::addExceptionAndCloseResponse);

★ 非區域性的資訊

註解該說什麼?寫下的內容與該段程式關連性多高? 註解只應該描述附近的程式碼,不要在區域性註解寫下那些不被這段程式控制的事情。

不合乎慣例的註解

這是我自己加的,註解的格式也很重要,尤其是 IDE 會幫你自動變色的時候。 在函式段落中,使用 JAVA DOC 格式 /** */ 註解, 會令人在快速瀏灠程式碼時,發生困惑。


其它 - 把事情說清楚

★ 可使用函式或變數時,就別使用註解

適當的做 Extract local variable 重構,可以使你的程式簡明,而不需要多餘的註解。

★ 右大括號(區域結尾)後方註解

只要程式碼夠簡短,就沒有必要。

應該說,IDE 夠強力,就沒有必要。 有些工具軟體的 script 編寫介面,就像最陽春的 NOTEPAD, 這時不得不以註解方式,標注一些可以幫助未來翻修程式所需的資訊。

★ 位置標誌物

  // Actions 1 ///////////////////////////////////
  // Actions 2 ///////////////////////////////////
  // =========================== Final Action ===============

與下一章「編排」的概念相關。如果有這類註解,專案應該統一型式。

★ 過多的資訊

有些資訊可以附上外部連結、規格代碼、甚至查詢關鍵字就好。

★ 不顯著的關聯

有時要把演算法說明白,是很困難、複雜的。

舉例來說,看看 leetcode 上第4題,標註為HARD的問題解答頁面。 https://leetcode.com/problems/median-of-two-sorted-arrays/solution/ 你會發現,相關證明的篇幅遠遠超過短短二三十行的程式碼。

這種程式的註解該怎麼寫?其實是個考驗。


要用註解表達什麼?(有益或必要的註解)

摘錄項目說明:

  • 法律方面的標註:如著作權/授權聲明,可以使用參照連結以縮短篇幅。
  • 開放 API 的Javadoc:如果開發的程式是給多人使用的共用函式庫,良好的 JAVA-DOC 是標準的說明文件格式,理應提供。但也要仔細撰寫,不要反而造成誤導。
  • 資訊型註解:像是特殊語法(如正則表示式)的意涵,有時可以在程式重構後略去。
    // format matched kk:mm:ss EEE, MMM dd, yyyy
    Pattern tiMatcher = Pattern.compile("\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*")
    
  • 對意圖的解釋:像是對演算法的摘要說明。
  • 放大重要性:突顯一些處理邏輯的必要性,如書中的TRIM()。
  • 闡明:對於短句或參數的翻譯,不得已而為之。

    通常以行尾註解,加強註解與程式本身位置的關連性。
    並請恪外留意正確性。

  • 對後果的告誡:警告會出現某種特殊後果的註解

    • 為什麼使用特定實作:如需要保證 Thread safe
    • 為什麼 IGNORE 某項機制:如測試耗用過多資源。

      以書本上單元測試的這個例子,我會考慮把這類測試放到其它獨立測試用專案。
      另外舉例像是使用 @SuppressWarnings 停用編輯器檢查時,應加上相關的豁免說明。

  • TODO:沒有定期審視此類註解的話,它會變成千年垃圾,請小心。

    團隊應規劃相關 TODO TAG 使用規範,例如留下 TODO 就一定要開 issue 單之類的。


心得與調適

  • 註解應該解釋「程式碼為什麼要這麼寫」,而不是「程式碼究竟寫些什麼」。

  • 雖然程式碼品質的理想是「程式碼即註解」,但是我們這類的專案,在合約規範中通常都會包含交付文件,
    尤其是 PDS (程式設計規格),而且是中文的交付文件!
    所以還要會適度的將程式語意譯為中文,寫在註解段落中,以便整理文件時,有所參考。

PDS 文件轉換規劃

為了彌補撰寫文件在人力成本上的耗損,以及希望可以提高這份文件的參考價值,我們專案之前有一個 PDS文件轉換規劃,簡單的說,就是自訂簡單的格式規範,以增強 JAVADOC 在函式內容描述上的不足,並以自行開發的doclet產出交付word文件底稿。
有點像 Doxygen,但是我想把事情變得再簡單一點。

// !  
// !!

results matching ""

    No results matching ""