編寫可維護的代碼
三年前,我在雅虎發表了第一次演講!標題為可維護的 JavaScript(幻燈片)。談話的重點是鼓勵人們在他們的 JavaScript 編碼中使用更嚴格的方法。很多以編寫 JavaScript 為生的人都是從業餘愛好者和黑客開始的,包括我自己。當然,所有最好的前端工程師都是自學成才的,因為這些東西在大學裡都沒有教過。我藉此機會簡單地指出,傳統軟件工程程序中教授的相同編碼實踐也可以應用於 JavaScript。當然,我還提供了一些我自己通過多年 Web 開發收集的個人發現。
什麼是可維護代碼?
在演示文稿中,我說過可維護代碼具有以下品質:
- 可以理解
- 直觀
- 適應性強
- 可擴展
- 可調試
我現在還想添加“可測試”作為可維護代碼的第六種質量。當我最近想到這一點時,我意識到所有這六個品質都歸結為一個概念:不要混淆。
令人困惑的代碼並不體現這些品質,並使每個人的工作變得更加困難。多年來,我們在識別不良代碼方面變得更好。糟糕的代碼會導致運行時問題,無論是實際拋出的錯誤、性能瓶頸還是可訪問性問題。錯誤代碼通常由需要對代碼進行現場更改以進行補救的錯誤來識別。混亂的代碼更陰險。
沒有上下文很難發現令人困惑的代碼。在真空中檢查時,任何單行或一系列代碼行都會令人困惑。上下文決定了該代碼是否令人困惑。這必然意味著發現令人困惑的代碼的唯一方法是徹底審查。
任何和我一起工作的人都知道我對代碼審查的熱情,因為我相信它們不僅是發現更深奧的問題的最佳方式,而且也是在團隊中交流最佳實踐的一種方式。代碼審查永遠不會在任何人的“待辦事項”列表的頂部,但它們至關重要。當令人困惑的代碼在白天出現時,識別和修復會容易得多。更重要的是,當一群人看到令人困惑的代碼時,他們都會同意它令人困惑,並想出一個通用的方法來解決它。
混淆 JavaScript
令人困惑的代碼有多種形式,但具有壓倒一切的品質:很難判斷它是故意的還是錯誤的。 JavaScript 是存在混淆代碼的三種(JavaScript、CSS 和 HTML)中最簡單的一種。一個經典的例子:
switch(type){
case "string":
handleString(value);
case "number":
handleNumber(value);
default:
handleValue(value)
}
這段代碼看起來很無害。體面的工程師會看著這段代碼說:“嘿,每個 case 語句都缺少一個中斷。”如果您在同一個文件中修復代碼,您甚至可能傾向於提供幫助,只需添加一個 break
在每個案例之後。但是你確定這裡有錯誤嗎?你怎麼知道開發者沒有故意省略break
在每種情況下?真的沒有辦法說,所以你可以創造 修復此代碼的錯誤,但就您所知,此代碼可能已經導致您可以修復的錯誤。這是令人困惑的代碼。
你如何把它變成好的代碼?通過提供上下文。在這種情況下,周圍的代碼沒有提供足夠的上下文,所以添加註釋是最好的方法。例如:
switch(type){
case "string":
handleString(value);
/*falls through*/
case "number":
handleNumber(value);
/*falls through*/
default:
handleValue(value)
}
這段代碼不那麼令人困惑。您知道每個案例的目的都是為了下一個案例,因此您不會在遇到此代碼時意外修復它。此外,如果您的團隊同意這是在這些情況下使用的模式,那麼您知道每個 case 語句必須由 break
終止 , return
, throw
, 或 /*falls through*/
評論。如果一個 case
聲明不以其中一個結尾,那麼它很可能是一個錯誤,應該作為缺陷提交。
JSLint
如果您不知何故沒有聽說過,JSLint 是由 Douglas Crockford 創建的用於驗證 JavaScript 代碼的工具。它被描述為一種幫助識別不良代碼的工具,它確實如此,但它也識別出令人困惑的代碼。事實上,它識別的混淆代碼類型比識別錯誤代碼的類型多。究竟什麼是令人困惑的代碼是主觀的,Crockford 和我在 JSLint 指出的事情上並沒有 100% 達成一致,但這仍然是可用於幫助識別除了壞代碼之外可能令人困惑的代碼的最佳工具。主頁>
混淆CSS
不要被愚弄,令人困惑的代碼也可能存在於 Web 應用程序的其他層中。 CSS 有一些有趣的語法問題,可能會導致混淆。例如,padding 屬性的值可以有一個、兩個、三個或四個部分:
/*same padding all around*/
padding: 10px;
/*padding for top/bottom, different padding for left/right*/
padding: 10px 20px;
/*padding for top, different padding for left/right, different padding for bottom*/
padding: 10px 20px 15px;
/*different padding for top, right, bottom, and left*/
padding: 10px 20px 15px 25px;
有人會說所有這些都很好,不會令人困惑。就個人而言,我發現第三個選項非常令人困惑,因為不清楚您是否打算使用不同的底部填充。您可能打算使用兩個或四個部分。這種形式也是所有選項中最不直觀的。有幾種簡單的方法可以消除歧義。首先是同意始終使用一個、兩個或四個部分來表示 padding
等屬性 .這有一個令人愉快的副作用,如果你只需要一個維度就可以讓你停下來思考一下。這是它的外觀:
/*Don't use*/
padding: 10px 20px 15px;
/*Better*/
padding: 10px 20px 15px 20px;
即使您最終對左右部分使用相同的值,我認為更容易判斷結果是預期的。另一種選擇是始終為一次性維度使用特定的填充屬性,例如:
/*Don't use*/
padding: 10px 20px 15px;
/*Better*/
padding: 10px 20px;
padding-bottom: 15px;
這個例子和前面的例子都具有明確做出這個決定的優勢:你意思是 只改變一個維度的填充,因此,它必須是正確的。
小心混淆代碼
令人困惑的代碼是源代碼中第二糟糕的(僅次於糟糕的代碼)類型的代碼,因為它會引入細微的錯誤,而這些錯誤可能會在很長一段時間內被忽視。我喜歡說代碼就像兔子:當你不看的時候它會成倍增加。如果您的系統中有一個令人困惑的代碼實例,那麼很快就會有兩個。這是因為軟件項目的自然流程。有人正在尋找如何做新事物的示例,他們遇到了令人困惑的代碼。令人困惑的代碼被複製,現在源中有兩個實例。下次有人去尋找示例時,他們找到令人困惑的代碼的可能性是示例的兩倍(當然,找到相同方法的兩個示例可以驗證尋求者頭腦中的方法)。
好的、可維護的代碼也是如此。源代碼中好的代碼示例越多,其他人就越有可能複制它。這就是你想要的。