忍者程式碼(Ninja Code)

https://javascript.info/ninja-code

Len Chen
8 min readSep 14, 2019
https://www.flickr.com/photos/dlato/5530553658

過去的程式忍者使用這些技巧來讓程式碼維護者的心思更加敏銳。

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

初學的開發者有時候將它們用的比程式忍者更好。

細心閱讀然後找出你的角色是 — 程式忍者、初學者、或者程式碼審查者?

很多人試著跟隨忍者的腳步,但很少有人成功。

要言不煩(Brevity is the soul of wit)

讓程式碼盡可能簡短,以顯示出你多麼聰明。

讓微妙的語言特性指引你。

舉例,看一下這個三元運算子 ?

// 從知名 javascript 函式庫取得的程式碼
i = i ? i < 0 ? Math.max(0, len + i) : i : 0;

酷,對吧?若你也像這樣寫,那些看到這一行程式碼並試圖理解 i 值的開發者們,將會有個美好的時光,接著就會來找你尋求答案。

告訴他們更短總是更好,引領他們進入忍者之路。

單一字母變數

道隱無名。夫唯道,善貸且成。
— 老子(道德經)

另一個寫程式更快的方式是到處使用單一字母的變數名稱,像是 abc

短變數會像個真正的忍者處於森林中一樣,消失於程式碼之中,沒有人能夠使用編輯器的 “搜尋” 找到它們。即使有人辦得到,他們也無法 “破譯” ab 名稱的意義。

…但有個例外,一個真正的忍者永遠不會在 for 迴圈內使用 i 作為計數器。任何地方都行,就是這裡不可以。觀察四周看看,還有其他像是 xy 這種異樣的字母呢。

若迴圈本體有 1–2 頁這麼長(若可以就讓它盡量長),那麼以異樣的變數作為迴圈計數器會是特別的酷。然後若有人深入迴圈內部,他們將無法快速知道以 x 為名的變數就是迴圈計數器。

使用縮寫

若團隊規則禁止使用單一字母或模糊的名稱 — 盡量縮短它們,使用縮寫吧。

像這樣:

  • list -> lst
  • userAgent -> ua
  • browser -> brsr
  • …等等

只有真正擁有良好直覺的人才有辦法理解這些名稱。盡量縮短一切事物,只有天選之人才夠格接手你的程式開發。

突破天際的抽象化

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

在選擇一個名稱時,試著使用最為抽象的詞,像是 objdatavalueitemelem 等等。

  • 變數的理想名稱是 data在任何能用地方都用,每個變數都確實都有 data 不是嗎?

…但如果 `data` 已經被用過了怎麼辦?試著使用 value,它也很普遍,畢竟一個變數最終總會得到一個 value

  • 使用變數類型命名:strnum

嘗試看看,新手可能會懷疑 — 這種名稱真的對成為忍者有用嗎?是的,就是會!

確實,該變數名稱依然含有意義。它說明了變數內部有些什麼:一串字串、一個數值或其它東西。但當外部使用者試著理解程式碼時,他們會驚訝地發現事實上根本不具有任何資訊!且最終將無法改變你精思熟慮過的程式碼。

值的類型很容易就可以經由除錯得知,但此變數的意義呢?它儲存著哪種 字串/數值?

不經過良好的冥想是無法理解的!

…但如果這種名稱不夠用怎麼辦?加個數字就好了:data1, item2, elem5

注意力測試

只有真正細心的程式設計師才夠格理解你的程式碼,要如何確認?

其中一個方法 — 使用相似的名稱,像是:datedata

盡可能的混合在一起。

快速閱讀這種程式碼是不可能的,而且當還有錯字時… 嗯… 我們卡在這很久了,來喝個茶吧。

聰明的同義詞

最困難的事是在黑暗的房間內尋找一隻黑貓,尤其當那裡根本沒有貓時。
— 孔子(譯者註:這則引用應是個烏龍,孔子沒有說過這句話,可上網查詢相關來源)

同件 事情使用 相似 的名稱使得生活更為有趣,並向大眾顯示出你的創意。

例如,函式前置。若某個函式在螢幕上顯示一段訊息 — 使用 display... 開頭,像是 displayMessage。然後若另一個函式在螢幕上顯示別的東西,像是使用者名稱,就用 show... 開頭(像是 showName)。

暗示這些函式之間有些微妙的不同,而其實並沒有。

與團隊中的忍者夥伴達成一個協議:若 John 在程式碼中用 display... 作為 “顯示” 函式的起始,那 Peter 可以用 render..,而 Ann 就用 paint...,注意看看程式碼會變得多麼有趣且多樣化啊。

…接著是帽子戲法!

對於兩個有著重要差異的函式 — 使用同樣的前置!

舉個例,函式 printPage(page) 將會用到印表機,而函式 printText(text) 將會把文字放到螢幕上。讓某個不熟悉的讀者思考一下這個相似的函式名稱 printMessage:”它會把訊息丟到哪去?印表機還是螢幕上?” 為了讓它更為耀眼,printMessage(message) 應該要輸出訊息到新的視窗中!

重複使用名稱

始制有名,
名亦既有,
夫亦將知止。
知止所以不殆。
— 老子(道德經)

只在絕對需要時才加入新的變數。

否則,重複使用已存在的名稱。就只要對它們寫入新的值。

在函式中試著只使用作為參數傳遞的變數。

這樣做變數 現在 的值到底是什麼會變得很難確定,也會不知道它從哪來的。這麼做的目的是為了開發閱讀程式碼的人的直覺和記性。直覺不佳的人必須一行一行分析程式碼,並追蹤每段程式碼分枝的變化。

這種方法的進階變化是偷偷地(!)在像是迴圈或函式之中換掉它的值。

舉個例:

function ninjaFunction(elem) {
// 20 行程式碼用來處理 elem
elem = clone(elem); // 另外的 20 行,用來處理複製後的 elem!
}

想要在函式第二部分使用 elem 的程式夥伴會非常驚訝… 只有在除錯檢查完程式碼後,他們才會發現原來他們是在使用複製體!

這經常在程式碼中看到,即使是對於經驗豐富的忍者來說也是非常致命。

底線的樂趣

在變數名稱前使用底線 ___,像是 _name__value。若只有你知道它們的意義就太讚了,或者更棒的是,加上去只是為了樂趣,根本沒有特別的意義存在,或是在不同的地方就有不一樣的意義。

你一槍殺死了兩隻兔子耶。首先,程式碼變得更長且更不易讀了,再來,開發夥伴會花很長的時間試圖理解底線的意義。

一個聰明的忍者會把底線放在某處,然後刻意避免在其他地方使用。這會讓程式碼更為脆弱且增加未來出錯的機會。

展現你的熱情

讓大家看看你是多麼的氣壯山河!像是 superElementmegaFrameniceItem 這種名稱,一定可以達到啟發讀者的功效。

從某方面來看,這樣確實有寫下些什麼:super..mega..nice..,但從另一方面來看 — 毫無細節可言。讀者也許得在上班時間花一兩個小時冥想,來尋找背後隱藏的意義。

重疊外部變數

夫處明者,不見暗中一物,
而處暗者,能見明中區事。
— 關尹子

將函式的內部與外部變數都使用一樣的名稱。很簡單,也不用花時間創造新名稱。

let user = authenticateUser();function render() {
let user = anotherValue();
...
...many lines...
...many lines...
...
...
... // <-- 某個程式設計師想在這裡使用 user,然後...
...
}

一個跳進 render 內的程式設計師,可能會沒注意到有個區域的 user 隱蔽了外部的變數。

然後他們會試圖將 user 視為外部變數 authenticateUser() 的結果來使用… 翻開覆蓋的陷阱卡!哈囉,除錯器…

副作用(Side-effects)無所不在!

有些函式看起來不改變任何東西,像是 isReady()checkPermission()findTags()… 他們被設想為執行計算、找出並回傳資料,而不改變內部的任何東西,換句話說就是沒有 “副作用(side-effects)”。

有個真正漂亮的技巧,就是在他們的主要任務之外,再加個 “有用的” 動作。

當你的同事看到一個名為 is..check..find.. 的函式改變了某些東西時,他的臉上一定會充滿迷惑 — 絕對能拓展你理性的界線。

另一個給人驚喜的方式是回傳非標準的結果。

展現你原始的想法!讓 checkPermission 呼叫不回傳 true/false,而是回傳某個包含檢查結果的複雜物件。

那些試圖寫下 if(checkPermission(..)) 的開發者,會懷疑為什麼這麼寫不起作用。告訴他們:”看文件!”,然後把這篇文章丟給他們。

強大的函式!

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

別讓名稱限制了函式,變得更廣泛吧。

舉個例,函式 validateEmail(email) 可以(除了檢查 email 是否正確之外)顯示錯誤訊息並要求重新輸入 email。

額外的動作不該明顯出現在函式名稱中,真正的忍者程式人員會使它們在程式碼中也不這麼顯眼。

把多個動作合併成一個以避免你的程式碼被重複使用。

想像一下,別的開發者只想要檢查 email 而不要輸出任何訊息時,你的函式 validateEmail(email) 做這麼多事就不適合他們啦。所以他們才不會在你冥想的時候來問你問題。

總結

上述的 “這些建議” 都由實際的程式碼得來… 有時甚至是由有經驗的開發者寫下的,甚至是比你更有經驗的人 ;)

  • 遵循部分,你的程式碼會變得充滿驚奇。
  • 遵循多數,你的程式碼會真正成為你的程式碼,沒有人會想改變它。
  • 遵循全部,你的程式碼將成為年輕開發者尋求啟發的寶貴案例。

--

--