程式碼潔癖系列(四):可忽略的注釋

  • 2020 年 3 月 11 日
  • 筆記

剛開始學編程的時候,老師就告訴我們,注釋很重要,但是一直到現在,也沒有人真正告訴過我要怎麼寫注釋。還有很多人甚至乾脆不寫注釋。所以今天想聊一下到底如何寫注釋。

提到注釋就讓我想起一個段子:兩個程式設計師去飯店吃飯,點菜的時候程式設計師甲說:我要吃宮保雞丁,程式設計師乙就幫他記。

宮保雞丁

然後程式設計師甲又說:我不想吃宮保雞丁了,換成地三鮮吧。程式設計師乙就說好的,然後又幫他記上了。

//宮保雞丁  地三鮮

這個段子也從側面反映了程式設計師們習慣性忽略注釋的事實。段子講完了,下面插播一些正文。

注釋不能拯救糟糕的程式碼

首先,我想說的可能和大多數人的觀點相左:盡量少用注釋!沒錯,盡量少用。因為注釋是會騙人的,而且時間越長的注釋越容易騙人,因為大部分人在修改程式碼的時候都不會去修改注釋。少寫注釋,盡量用程式碼去描述你要做什麼。當你要寫注釋的時候,就要思考一下,別人為什麼不能通過程式碼理解你想表達什麼。這時你需要嘗試修改程式碼,來達到上述目的。

// Check to see if the employee is eligible for full benefits  if (employee.flags & HOURLY_FLAG) &&      (employee.age > 65)

看一下這段程式碼,如果只看程式碼,可以理解它要表達什麼嗎?

if (employee.isEligibleForFUllBenefits())

花上點時間,把程式碼改成這樣,是不是不用注釋也可以讀懂了?

我們這裡說盡量少使用注釋,並不是完全不用注釋,在某些情況下,我們需要注釋。那麼什麼樣的注釋才算是好的注釋呢?

法律資訊

有時,公司程式碼規範會要求註明版權和著作權。那麼我們就應該將這些資訊放到源文件的開頭位置。

提供資訊的注釋

// Returns an instance of the Responder being tested.  protected abstract Responder responderInstance()

這樣的注釋就是不錯的注釋,給讀者提供了返回值的資訊,不過,如果我們把函數命名為responderBeingTested,那麼這個注釋也就顯得多餘了。

闡釋

可以用注釋把某些難以理解的參數或返回值翻譯成可讀的形式。當前,前提是如果這些程式碼你無法修改,比如參數或返回值是標準庫的一部分。這時闡釋就顯得很有用。舉過來一個栗子。

assertTrue(a.compareTo(a) == 0);  // a == a  assertTrue(a.compareTo(b) != 0);  // a != b  assertTrue(a.compareTo(b) == -1); // a < b

不過這樣的闡釋也有缺點,那就是它有可能是不正確的,我們需要小心確認其正確性。如果缺失正確性,那麼這樣的闡釋只會起到負面作用。

TODO注釋

TODO注釋是比較常用的注釋,可以在程式碼里添加工作列表,例如,對一個空實現函數添加TODO注釋,就可以解釋這裡為什麼是空實現,以及以後要實現什麼。

公共API的Javadoc

這個也許最令人欣賞的注釋習慣了。不過目前我們通常用swagger來代替注釋。對swagger感興趣的童鞋可以戳閱讀原文。

所謂見賢思齊焉,見不賢而內自省也。看完了好的注釋,就要想想怎麼才能寫出好的注釋;接下來再來看看壞的注釋,看的同時需要多反省自己,盡量避免寫出壞的注釋。

自說自話

寫的東西只有自己能看懂,別人都不明白要表達什麼。如果讀程式碼時連注釋都看不明白,還有人想看下去嗎。

日誌式注釋

幾乎把程式碼的每次修改記錄都寫到注釋里,也許在那個沒有程式碼版本控制工具的遠古時代,這麼做還有一定的意義。但是現在我們擁有很多健壯的程式碼版本控制工具,這樣的注釋也就變得毫無意義。

在程式碼里加上自己的簽名也是一樣的道理,我們都可以通過程式碼版本控制工具查看具體的創建者和修改者,而不是只記住創建者。

注釋掉程式碼也是一樣,我們用版本控制工具可以輕鬆找回以前的程式碼,不需要的程式碼可以直接刪掉,而不是留一個注釋掉的程式碼放在那裡。

廢話注釋

/** The day of the month. */  private int dayOfMonth;

我不想多廢話了……

結語

也許文中的觀點和大多數人的思維相左,可能我的有些觀點是錯的,歡迎大家和我討論注釋究竟是否必要。最後如果覺得文章不錯的話就幫忙點個贊或者轉發一下吧。

—END—