許多註解之所以無用,是因為它們重複了程式碼本身——所有資訊都能從旁邊的程式碼直接推得。

反例 1:每一行程式碼都加翻譯#

ptr_copy = get_copy(obj)                 # Get pointer copy
if is_unlocked(ptr_copy):                # Is obj free?
    return obj                           # return current obj
if is_copy(ptr_copy):                    # Already a copy?
    return obj                           # return obj
thread_id = get_thread_id(ptr_copy)
if thread_id == ctx.thread_id:           # Locked by current ctx
    return ptr_copy                      # Return copy

只有 Locked by current ctx 那一行可能透露程式碼看不出的事,其他都只是把程式碼再寫一遍。

反例 2:什麼都沒講的註解#

// Add a horizontal scroll bar
hScrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
add(hScrollBar, BorderLayout.SOUTH);

// Add a vertical scroll bar
vScrollBar = new JScrollBar(JScrollBar.VERTICAL);
add(vScrollBar, BorderLayout.EAST);

// Initialize the caret-position related values
caretX    = 0;
caretY    = 0;
caretMemX = null;

前兩個註解的程式碼本身已夠清楚;第三個雖有寫註解的空間,但這個註解什麼資訊也沒提供。

自我檢查的方法#

寫完註解後問自己:

「一個從沒看過這段程式碼的人,能光看旁邊程式碼就寫出這條註解嗎?」

如果可以——這條註解沒幫上忙。

反例 3:把名字翻成句子#

/* Obtain a normalized resource name from REQ. */
private static String[] getNormalizedResourceNames(HTTPRequest req) ...

/* Downcast PARAMETER to TYPE. */
private static Object downCastParameter(String parameter, String type) ...

/* The horizontal padding of each line in the text. */
private static final int textHorizontalPadding = 4;

這些註解只是把名稱拆成句子,加幾個介系詞——沒有任何附加資訊。第二個例子的「to」是註解中唯一不在程式碼裡的字。

紅旗:註解重複程式碼(Red Flag: Comment Repeats Code)#

註解中的資訊已經能從旁邊的程式碼看出 → 註解沒幫忙。

一個典型徵兆:註解使用了與被描述對象相同的字眼

真正應該補的資訊#

上面的反例其實漏掉了很多重要的事:

  • 什麼是 normalized resource name?回傳陣列的元素是什麼?
  • downcast 是什麼?
  • padding 的單位是什麼?是某一邊還是兩邊?

改寫範例#

/*
 * The amount of blank space to leave on the left and
 * right sides of each line of text, in pixels.
 */
private static final int textHorizontalPadding = 4;
  • 補上單位(pixels)
  • 說明 padding 用在兩側
  • 用「blank space」解釋什麼是 padding(避免術語陷阱)

寫好註解的第一步#

用與名稱不同的字寫註解。

註解裡的字應該提供「實體意義上的額外資訊」,而不是把名字再說一遍。