如何編寫高質量和可維護的程式碼

2014-12-18    分類:其他、程式設計開發、首頁精華2人評論發表於2014-12-18

本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

我們怎麼做才能既不需要寫很多註釋,又能保證程式碼易於理解呢?

其中一個主要的方法就是讓程式碼自文件化。其優勢在於,既不用寫註釋,又能使得程式碼易於維護。

下面就是三種使得程式碼自文件化的基本方法:

  • 命名:利用名字來解釋變數、函式等的目的。
  • 封裝函式:將一些特定功能的程式碼封裝成一個函式以明確目的。
  • 引入變數:將表示式插入至專用變數。

這可能看上去很簡單,但在實際操作過程中會讓人覺得有點棘手。首先你得明白哪些地方有問題以及哪些地方適用這些方法。

除了上面三個以外,還有一些應用範圍也比較廣的方法:

  • 類和模組介面:將類和模組中的函式暴露出來,讓程式碼更加清晰。
  • 程式碼分組:用組來區分不同的程式碼片段。

接下來我們將具體講一講如何在實際應用中運用上面這5個方法。

1.命名

先看幾個如何運用命名的方法來闡述程式碼使得其自文件化的例子。

重新命名函式

給函式命名通常都不會太難,但是這裡面也有一些需要遵循的簡單規則:

避免使用含糊的字眼,例如“handle”或“manage”——handleLinks、manageObjects。

使用主動動詞——cutGrass、sendFile,以表示函式主動執行。

指定返回值型別——getMagicBullet、READFILE。強型別的語言也可以用型別識別符號來表明函式的返回值型別。

重新命名變數

指定單位——如果裡面有數值引數,那可以加上其單位。例如,用widthPx來取代width以指定寬度的單位是畫素。

不要使用快捷鍵——a和b都不能作為引數名。

封裝函式

關於這一點,我們將舉幾個如何把程式碼封裝成函式的例子。此外,這麼做還有一個好處是,可以避免重複程式碼。

將程式碼封裝成函式

這是最基本的:將程式碼封裝成函式以明確其目的。

猜猜下面這行程式碼是幹什麼的:

var width = (value - 0.5) * 16;

好像不是很清楚,當然有註釋就一清二楚了,但是我們完全可以封裝成函式以實現自文件化……

var width = emToPixels(value);

function emToPixels(ems) {
    return (ems - 0.5) * 16;
}

唯一改變的是計算過程被轉移到了一個函式裡。該函式名明確地表達了它要做什麼,這樣一來就不必寫註釋了。而且,如果有需要後面還可以直接呼叫此函式,一舉兩得,減少了重複勞動。

用函式表示條件表示式

If語句如果包含多個運算物件,不寫註釋的話理解起來就比較難。

if(!el.offsetWidth || !el.offsetHeight) {
}

知道上面這程式碼的目的不?

function isVisible(el) {
    return el.offsetWidth && el.offsetHeight;
}

if(!isVisible(el)) {
}

其實,只要將這些程式碼封裝到一個函式裡,那就很容易理解了。

引入變數

最後再講講如何引入變數。相較於上面兩個方法,這個可能沒那麼有用,但是無論如何,知道比不知道好。

用變數替換表示式

還是上面這個if語句的例子:

if(!el.offsetWidth || !el.offsetHeight) {
}

這次我們不封裝函式,改用引入變數:

var isVisible = el.offsetWidth && el.offsetHeight;
if(!isVisible) {
}

用變數替換程式

我們也可以用來清楚說明覆雜程式:

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;
  • 制定規則:最好遵循相同的命名規則。這樣閱讀的人就能在參考其他程式碼的基礎上正確猜測出各種事物的含義。

結論

要想能使程式碼自文件化提高其可維護性是一個非常漫長的歷程。每個註釋都需要花心力去寫,所以儘量精簡方可省時省力。

然而,自文件化的程式碼永遠取代不了文件和註釋。因為程式碼在表述上總有其限制,所以寫好註釋亦是不可或缺的。此外,API文件於類庫而言非常重要,因為光靠閱讀程式碼是理解不了的,除非這個類庫真的是小得不能再小。

譯文連結:http://www.codeceo.com/article/how-to-coding-best.html
英文原文:How to make your code self-documenting?
翻譯作者:碼農網 – 小峰
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章