標籤:編碼規範
原文:How to make your code self-documenting?
譯文:怎麼讓代碼自我文檔化?
譯者:dwqs
在代碼中找到一個放錯地方並且沒有用的注釋是不是很有趣呢?
怎麼樣才能做到寫很少的注釋但仍能讓代碼易於理解呢?
一個主要的方式就是讓代碼自我文檔化。當代碼自我文檔化的時候,就不需要注釋去它的作用或者目的,並且也能使代碼變得非常容易維護。
在這篇文章中,我將提供一些讓你的代碼自我文檔化的方式。下面就是三種使得代碼自文檔化的基本方法:
- 命名:利用名字來解釋變數、函數等的目的。
- 封裝函數:將一些特定功能的代碼封裝成一個函數以明確目的。
- 引入變數:將運算式插入至專用變數。
這可能看上去很簡單,但在實際操作過程中會讓人覺得有點棘手。首先你得明白哪些地方有問題以及哪些地方適用這些方法。
此外,除了上述三種,還有一些應用比較廣泛的方式:
- 類和模組介面:將類和模組中的函數暴露出來,讓代碼更加清晰。
- 代碼分組:用組來區分不同的程式碼片段。
接下來我們將通過執行個體,具體講一講如何在實際應用中運用上述5個方法。
一、命名
首先,看幾個如何利用命名時代碼變得清晰和自我文檔化的例子。
1、重新命名函數
給函數命名不是很難,你可以遵守以下規則:
- 避免使用含糊的字眼,例如“handle”或“manage”——handleLinks、manageObjects。
- 使用主動動詞——cutGrass、sendFile,以表示函數主動執行。
- 指定返回值類型——getMagicBullet、READFILE。強型別的語言也可以用類型標識符來表明函數的返回值類型。
2、重新命名變數
- 指定單位——如果裡面有數值參數,那可以加上其單位。例如,用widthPx來取代width以指定寬度的單位是像素。
- 不要使用快速鍵——a和b都不能作為參數名。
二、函數封裝
接下來,看幾個如何將代碼封裝成函數的例子。封裝函數的一個好處就是避免代碼重複,或者說改進代碼結構。
1、將代碼封裝成函數
這是最基本的:將代碼封裝成函數以明確其目的。猜猜下面這行代碼是幹什麼的:
var width = (value - 0.5) * 16;
好像不是很清楚,當然有注釋就一清二楚了,但是我們完全可以封裝成函數以實現自文檔化……
var width = emToPixels(value); function emToPixels(ems) { return (ems - 0.5) * 16;}
唯一改變的是計算過程被轉移到了一個函數裡。該函數名明確地表達了它要做什麼,這樣一來就不必寫注釋了。而且,如果有需要後面還可以直接調用此函數,一舉兩得,減少了重複勞動。
2、用函數代替條件運算式
If語句如果包含多個運算對象,不寫注釋的話理解起來就比較難。
if(!el.offsetWidth || !el.offsetHeight) {}
知道上面這代碼的目的不?
function isVisible(el) { return el.offsetWidth && el.offsetHeight;} if(!isVisible(el)) {}
三、引入變數
最後再講講如何引入變數。相較於上面兩個方法,這個可能沒那麼有用,但是無論如何,知道比不知道好。
1、用變數代替運算式
看看上面的例子
if(!el.offsetWidth || !el.offsetHeight) {}
這下不封裝成函數,用引入變數代替
var isVisible = el.offsetWidth && el.offsetHeight;if(!isVisible) {}
2、用變數代替方程式
我們也可以用來清楚說明複雜程式:
return a * b + (c / d);
用變數來代替
var divisor = c / d;var multiplier = a * b;return multiplier + divisor;
四、類和模組介面
類和模組的介面——也是面向公用的方法和屬性——有點像說明如何使用的文檔。
看下面的例子:
class Box { public function setState(state) { this.state = state; } public function getState() { return this.state; }}
這個類也可以包含其他代碼。我特意舉這個例子是想說明公用介面如何自文檔化。
你能說出這個類是如何被調用的嗎?很顯然,這並不明顯。
這兩個函數都應該換個合理的名字以表述它們的目的。但即便做到這一點,我們還是不怎麼清楚如何使用。然後就需要閱讀更多的代碼或者翻閱文檔。
但是如果我們這樣改一下呢……
class Box { public function open() { this.state = open; } public function close() { this.state = closed; } public function isOpen() { return this.state == open; }}
是不是清晰多了?注意:我們只是改動了公用介面,其內部表達與原先的this.state狀態相同。
五、代碼分組
用組來區分不同的程式碼片段也是自文檔化的一種形式。例如,像這篇文章中說的那樣,我們應該儘可能將變數定義在靠近使用它的地方,並且儘可能將變數分門別類。這也可以用來指定不同程式碼群組之間的關係,這樣更加方便其他人知道他們還需要瞭解哪些程式碼群組。
看下面的例子:
var foo = 1; blah()xyz(); bar(foo);baz(1337);quux(foo);
與下面的比較:
var foo = 1;bar(foo);quux(foo); blah()xyz(); baz(1337);
將foo的所有使用組合放在一起,一眼望去就能知道各種關係。但是有時候我們不得不在中間調用一些其他函數。所以如果可以那就盡量使用代碼分組,如果不可以,那就不要強求。
六、其它建議
imTricky && doMagic();
if(imTricky) { doMagic();}
顯然後者比較好。文法技巧並沒有帶來什麼好處。
- 命名常量:如果代碼裡面有一些特殊值,那最好給它們命名。var PURPOSE_OF_LIFE = 42;
- 制定規則:最好遵循相同的命名規則。這樣閱讀的人就能在參考其他代碼的基礎上正確猜測出各種事物的含義。
原文首發:http://www.ido321.com/1360.html
如何高效編寫可維護代碼?