當很多前輩教育后輩應當多寫注釋的時候,當網絡上充滿了有關程序員從不寫注釋的段子的時候,這是一個非常有爭議的話題。作為一個標題黨,容我先修正一下我的觀點:我認為如果代碼寫得足夠好,那么大多數注釋是多余的,我們應該通過寫出更好的代碼來代替更多注釋。
注釋的確有其用途,但大部分情況下,程序員在濫用注釋。我是反對夾雜在代碼間的注釋的,我認為注釋應當從代碼中獨立出來――通常被稱為文檔。
請看下面一段代碼。
2014.7.2 create by orzfly
2014.7.29 update by jysperm: fixbugs
TODO: 這段代碼中注釋太多了,需要移除一些 -- jysperm
*/
var raw_products = req.query['products'].split(',');
// 商品 ID 的數組
var products = []
// 過濾每個參數
for(var i = 0, i < raw_products.length, i++) {
if (!raw_products[i])
return;
// 前端傳來的數據中居然會有空格
if (!raw_products[i].trim())
return
/* 2014.7.22: 現在可以使用非數字 ID 了
// 略過非數字條目
if (isNan(raw_products[i].trim().toFixed()))
return;
*/
products.push(raw_products[i].trim().toFixed());
}
// 總錢數
var sum = 0;
// 計算每個商品的總錢數
for(var i = 0, i < products.length, i++) {
// 從數據庫中查商品信息
var data = db.product.byID(products[i]);
// TODO: 誰來寫一下沒查到商品的情況
// 把商品的價格加到總錢數上, a += b 是 a = a + b 的縮寫
sum += data.price;
}
你居然花了一半的時間在讀注釋上面,這是多么浪費生命的事情,在代碼中每加一行注釋,都會增加代碼的閱讀成本――即使閱讀者已經了解了注釋所要傳達的精神;同時也會增加維護成本:修改這段代碼的人不得不連同注釋一起修改――而且你不能確定他到底會不會這么做。
所以只有當非常必要的情況下,才應該添加注釋,而且應當言簡意賅。注釋不應當解釋一段代碼在做什么,因為這是每個合格的程序員都應該知道的事情,而是應該解釋這段代碼為什么要這樣做。
由此引出幾種明顯不應該添加的注釋:
本應由版本控制系統記錄的信息、對代碼的評論,以及不是很重要的 TODO.
代碼并不是全部,一個但凡靠譜一點的項目,都應當有自己的版本控制系統,除了記錄代碼差異之外,還應該有工單和 Issue 的功能。
閱讀代碼的人通常不需要了解幾個程序員之間的恩怨,很多時候也不關心這段代碼的歷史,這些信息只會把代碼拖得越來越長。
廢棄的代碼
被棄用的代碼應該被刪掉,這些代碼會非常影響閱讀,而且它們一般又很長。
在絕大多數情況下,被棄用的代碼不會重新派上用場,即使出現了少數情況,你也可以從版本控制系統中找到它們。
對變量和函數名的解釋
這種情況下顯然你需要一個更恰當的名字,如果這個標識符有一個比較小的作用于,你可以使用一個比較長的名字以便容納更多信息。
例如上文中的:
products 應改為 products_id
sum 應改為 total_amount
data 應改為 product_record
對語法的解釋,以及顯而易見的事情
例如上文中的「把商品的價格加到總錢數上, a += b 是 a = a + b 的縮寫」,這顯然是任何一個人都知道的事情。
也許有人愿意通過寫這樣的注釋來梳理思路:
但是當代碼寫完的時候記得刪掉。
對邏輯塊的概括
例如上文中的「過濾每個參數」和「計算每個商品的總錢數」,這情況下通常是你沒有對邏輯進行抽象,具體表現就是像下面這樣:
這導致你需要一些注釋來分割這四個部分。如果這四個部分都是一個函數調用的話,那么函數名本身就是對邏輯的一種解釋,讀者可以快速地找到函數 B, 而不必在前 25 行中搜索做事情 B 的五行代碼。
綜上,我對這段代碼的改善意見如下:
raw_products_id.forEach(function(product_id) {
if (product_id and product_id.trim())
products_id.push(product_id.trim().toFixed());
});
return result;
};
var getPriceOfProduct = function(id) {
var product_record = db.product.byID(products[i]);
if (product_record)
return product_record.price;
else
return 0;
};
var products_id = filterProductID(req.query['products'].split(','));
var tatol_amount = 0;
products_id.forEach(function(product_id) {
tatol_amount += getPriceOfProduct(product_id);
});
雖然我在以一段虛構的,刻意編造的代碼來佐證我的觀點,但我相信在實際的項目中,同樣可以通過改善代碼來減少注釋,而且總體上來講會節約更多的時間和精力。
新聞熱點
疑難解答