Javascript 忍者代碼

2023-02-17 10:38 更新
學而不思則罔,思而不學則殆??鬃印墩撜Z》

過去的程序員忍者使用這些技巧,來使代碼維護者的頭腦更加敏銳。

代碼審查大師在測試任務中尋找它們。

一些新入門的開發(fā)者有時候甚至比忍者程序員能夠更好地使用它們。

仔細閱讀本文,找出你是誰 —— 一個忍者、一個新手、或者一個代碼審查者?

檢測到諷刺意味
許多人試圖追隨忍者的腳步。只有極少數(shù)成功了。

簡潔是智慧的靈魂

把代碼盡可能寫得短。展示出你是多么的聰明啊。

在編程中,多使用一些巧妙的編程語言特性。

例如,看一下這個三元運算符 ?'?'?:

// 從一個著名的 JavaScript 庫中截取的代碼
i = i ? i < 0 ? Math.max(0, len + i) : i : 0;

很酷,對嗎?如果你這樣寫了,那些看到這一行代碼并嘗試去理解 ?i? 的值是什么的開發(fā)者們,就會有一個“快活的”的時光了。然后會來找你尋求答案。

告訴他短一點總是更好的。引導他進入忍者之路。

一個字母的變量

道隱無名。夫唯道善貸且成。老子(道德經(jīng))

另一個縮減代碼量的方法是,到處使用單字母的變量名。例如 ?a?、??或 ?c?。

短變量就像森林中真正的忍者一樣,一下就找不到了。沒有人能夠通過編輯器的“搜索”功能找到它。即使有人做到了,他也不能“破譯”出變量名 ?a? 或 ?b? 到底是什么意思。

……但是有一個例外情況。一個真正的忍者絕不會在 ?"for"? 循環(huán)中使用 ??作為計數(shù)器。在任何地方都可以,但是這里不會用。你隨便一找,就能找到很多不尋常的字母。例如 ??或 ?y?。

使用一個不尋常的變量多酷啊,尤其是在長達 1-2 頁(如果可以的話,你可以寫得更長)的循環(huán)體中使用的時候。如果某人要研究循環(huán)內(nèi)部實現(xiàn)的時候,他就很難很快地找出變量 ??其實是循環(huán)計數(shù)器啦。

使用縮寫

如果團隊規(guī)則中禁止使用一個字母和模糊的命名 — 那就縮短命名,使用縮寫吧。

像這樣:

  • ?list ?→ ?lst?
  • ?userAgent ?→ ?ua?
  • ?browser ?→ ?brsr?
  • ……等

只有具有真正良好直覺的人,才能夠理解這樣的命名。盡可能縮短一切。只有真正有價值的人,才能夠維護這種代碼的開發(fā)。

Soar high,抽象化。

大方無隅,大器晚成,大音希聲,大象無形。老子(道德經(jīng))

當選擇一個名字時,盡可能嘗試使用最抽象的詞語。例如 ?obj?、?data?、?value?、?item ?和 ?elem ?等。

  • 一個變量的理想名稱是 ?data?。 在任何能用的地方都使用它。的確,每個變量都持有 數(shù)據(jù)(data),對吧?……但是 ?data ?已經(jīng)用過了怎么辦?可以嘗試一下 ?value?,它也很普遍。畢竟,一個變量總會有一個 值(value),對吧?
  • 根據(jù)變量的類型為變量命名:?str?、?num?……嘗試一下吧。新手可能會詫異 — 這些名字對于忍者來說真的有用嗎?事實上,有用的!一方面,變量名仍然有著一些含義。它說明了變量內(nèi)是什么:一個字符串、一個數(shù)字或是其他的東西。但是當一個局外人試圖理解代碼時,他會驚訝地發(fā)現(xiàn)實際上沒有任何有效信息!最終就無法修改你精心思考過的代碼。我們可以通過代碼調(diào)試,很容易地看出值的類型。但是變量名的含義呢?它存了哪一個字符串或數(shù)字?如果思考的深度不夠,是沒有辦法搞明白的。
  • ……但是如果找不到更多這樣的名字呢? 可以加一個數(shù)字:?data1?, ?item2?, ?elem5?……

注意測試

只有一個真正細心的程序員才能理解你的代碼。但是怎么檢驗呢?

方式之一 —— 使用相似的變量名,像 ?date ?和 ?data?。

盡你所能地將它們混合在一起。

想快速閱讀這種代碼是不可能的。并且如果有一個錯別字時……額……我們卡在這兒好長時間了,到飯點了 (⊙v⊙)。

智能同義詞

道,可道,非常道。名,可名,非常名。老子《道德經(jīng)》

對 同一個 東西使用 類似 的命名,可以使生活更有趣,并且能夠展現(xiàn)你的創(chuàng)造力。

例如,函數(shù)前綴。如果一個函數(shù)的功能是在屏幕上展示一個消息 — 名稱可以以 ?display…? 開頭,例如 ?displayMessage?。如果另一個函數(shù)展示別的東西,比如一個用戶名,名稱可以以 ?show…? 開始(例如 ?showName?)。

暗示這些函數(shù)之間有微妙的差異,實際上并沒有。

與團隊中的其他忍者們達成一個協(xié)議:如果張三在他的代碼中以 ?display...? 來開始一個“顯示”函數(shù),那么李四可以用 ?render..?,王二可以使用 ?paint...?。你可以發(fā)現(xiàn)代碼變得多么地有趣多樣呀。

……現(xiàn)在是帽子戲法!

對于有非常重要的差異的兩個函數(shù) — 使用相同的前綴。

例如,?printPage(page)? 函數(shù)會使用一個打印機(printer)。?printText(text)? 函數(shù)會將文字顯示到屏幕上。讓一個不熟悉的讀者來思考一下:“名字為 ?printMessage(message)? 的函數(shù)會將消息放到哪里呢?打印機還是屏幕上?”。為了讓代碼真正耀眼,?printMessage(message)? 應該將消息輸出到新窗口中!

重用名字

始制有名,名亦既有,夫亦將知止,知止可以不殆。老子(道德經(jīng))

僅在絕對必要時才添加新變量。

否則,重用已經(jīng)存在的名字。直接把新值寫進變量即可。

在一個函數(shù)中,嘗試僅使用作為參數(shù)傳遞的變量。

這樣就很難確定這個變量的值現(xiàn)在是什么了。也不知道它是從哪里來的。目的是提高閱讀代碼的人的直覺和記憶力。一個直覺較弱的人必須逐行分析代碼,跟蹤每個代碼分支中的更改。

這個方法的一個進階方案是,在循環(huán)或函數(shù)中偷偷地替換掉它的值。

例如:

function ninjaFunction(elem) {
  // 基于變量 elem 進行工作的 20 行代碼

  elem = clone(elem);

  // 又 20 行代碼,現(xiàn)在使用的是 clone 后的 elem 變量。
}

想要在后半部分中使用 ?elem ?的程序員會感到很詫異……只有在調(diào)試期間,檢查代碼之后,他才會發(fā)現(xiàn)他正在使用克隆過的變量!

經(jīng)??吹竭@樣的代碼,即使對經(jīng)驗豐富的忍者來說也是致命的。

下劃線的樂趣

在變量名前加上下劃線 ?_? 和 ?__?。例如 ?_name? 和 ?__value?。如果只有你知道它們的含義,那就非常棒了?;蛘?,加這些下劃線只是為了好玩兒,沒有任何含義,那就更棒了!

加下劃線可謂是一箭雙雕。首先,代碼變得更長,可讀性更低;并且,你的開發(fā)者小伙伴可能會花費很長時間,來弄清楚下劃線是什么意思。

聰明的忍者會在代碼的一個地方使用下劃線,然后在其他地方刻意避免使用它們。這會使代碼變得更加脆弱,并提高了代碼未來出現(xiàn)錯誤的可能性。

展示你的愛

向大家展現(xiàn)一下你那豐富的情感!像 ?superElement?、?megaFrame ?和 ?niceItem ?這樣的名字一定會啟發(fā)讀者。

事實上,從一方面來說,看似寫了一些東西:?super..?、?mega..?、?nice..?。但從另一方面來說 — 并沒有提供任何細節(jié)。閱讀代碼的人可能需要耗費一到兩個小時的帶薪工作時間,冥思苦想來尋找一個隱藏的含義。

重疊外部變量

處明者不見暗中一物,處暗者能見明中區(qū)事。關(guān)尹子

對函數(shù)內(nèi)部和外部的變量,使用相同的名稱。很簡單,不用費勁想新的名稱。

let user = authenticateUser();

function render() {
  let user = anotherValue();
  ...
  ...許多行代碼...
  ...
  ... // <-- 某個程序員想要在這里使用 user 變量……
  ...
}

在研究 ?render? 內(nèi)部代碼的程序員可能不會注意到,有一個內(nèi)部變量 ?user ?屏蔽了外部的 ?user ?變量。

然后他會假設(shè) ?user ?仍然是外部的變量然后使用它,?authenticateUser() ?的結(jié)果……陷阱出來啦!你好呀,調(diào)試器……

無處不在的副作用!

有些函數(shù)看起來它們不會改變?nèi)魏螙|西。例如 ?isReady()?,?checkPermission()?,?findTags()……?它們被假定用于執(zhí)行計算、查找和返回數(shù)據(jù),而不會更改任何它們自身之外的數(shù)據(jù)。這被稱為“無副作用”。

一個非常驚喜的技巧就是,除了主要任務之外,給它們添加一個“有用的”行為。

當你的同事看到被命名為? is..?、?check..? 或 ?find...? 的函數(shù)改變了某些東西的時候,他臉上肯定是一臉懵逼的表情 — 這會擴大你的理性界限。

另一個驚喜的方式是,返回非標準的結(jié)果。

展示你原來的想法!讓調(diào)用 ?checkPermission ?時的返回值不是 ?true/false?,而是一個包含檢查結(jié)果的復雜對象。

那些嘗試寫 ?if (checkPermission(..))? 的開發(fā)者,會很疑惑為什么它不能工作。告訴他們:“去讀文檔吧”。然后給出這篇文章。

強大的函數(shù)!

大道泛兮,其左可右。老子(道德經(jīng))

不要讓函數(shù)受限于名字中寫的內(nèi)容。拓寬一些。

例如,函數(shù) ?validateEmail(email)? 可以(除了檢查郵件的正確性之外)顯示一個錯誤消息并要求重新輸入郵件。

額外的行為在函數(shù)名稱中不應該很明顯。一個真正的忍者會使它們在代碼中也不明顯。

將多個行為合并到一起,可以保護你的代碼不被重用。

想象一下,另一個開發(fā)者只想檢查郵箱而不想輸出任何信息。你的函數(shù) ?validateEmail(email)? 對他而言就不合適啦。所以他不會找你問關(guān)于這些函數(shù)的任何事而打斷你的思考。

總結(jié)

上面的所有“建議”都是從真實的代碼中提煉而來的……有時候,這些代碼是由有經(jīng)驗的開發(fā)者寫的。也許比你更有經(jīng)驗 ;)

  • 遵從其中的一丟丟,你的代碼就會變得充滿驚喜。
  • 遵從其中的一大部分,你的代碼將真正成為你的代碼,沒有人會想改變它。
  • 遵從所有,你的代碼將成為尋求啟發(fā)的年輕開發(fā)者的寶貴案例。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號