2020 年 9 月 5 日

忍者程式碼

學而不思則罔,思而不學則殆。

孔子(論語)

過去的程式設計忍者使用這些技巧來磨練程式維護人員的心智。

程式碼審查大師在測試任務中尋找這些技巧。

新手開發人員有時比程式忍者更擅長使用它們。

仔細閱讀它們,找出你是忍者、新手,還是程式碼審查者?

偵測到反諷

許多人嘗試走忍者路線,但只有少數人成功。

簡潔是智慧的靈魂

讓程式碼盡可能簡短,展現你的聰明才智。

讓微妙的語言功能引導你。

例如,看看這個三元運算子'?'

// taken from a well-known javascript library
i = i ? i < 0 ? Math.max(0, len + i) : i : 0;

很酷,對吧?如果你這樣寫,遇到這行程式碼並試圖了解i是什麼值的開發人員將會度過一段快樂時光。然後來找你,尋求答案。

告訴他們較短的總是較好,引導他們走上忍者的道路。

單字母變數

道隱於無言,唯道善始善終。

老子(道德經)

縮短程式碼的另一種方法是在所有地方使用單字母變數名稱,例如abc

一個短變數會像真正的忍者在森林中一樣消失在程式碼中。沒有人能夠使用編輯器的「搜尋」功能找到它。即使有人做到了,他們也無法「解碼」ab名稱的意義。

…但有一個例外。真正的忍者絕不會在"for"迴圈中使用i作為計數器。任何地方都可以,但這裡不行。四處看看,還有許多更奇特的字母。例如,xy

如果迴圈主體佔用 1-2 頁(如果可以,請延長),則使用奇特的變數作為迴圈計數器特別酷。然後,如果有人深入查看迴圈,他們將無法快速找出名為x的變數是迴圈計數器。

使用縮寫

如果團隊規則禁止使用單字母和模糊名稱,請縮短它們,使用縮寫。

像這樣

  • listlst
  • userAgentua
  • browserbrsr
  • …等

只有真正具有良好直覺的人才能理解這些名稱。試著縮短所有內容。只有有價值的人才能維護你的程式碼開發。

飛得高。抽象化。

大圓無角
大器晚成
大音希聲
大象無形

老子(道德經)

在選擇名稱時,請嘗試使用最抽象的字詞。例如 objdatavalueitemelem 等。

  • 變數的理想名稱是 data只要可以,就使用它。畢竟,每個變數都包含 資料,對吧?

    …但是如果 data 已經被使用了怎麼辦?試試 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 lines of code working with elem

  elem = clone(elem);

  // 20 more lines, now working with the clone of the elem!
}

一位想要在函式後半部使用 elem 的程式設計師會感到驚訝…只有在除錯期間,在檢查程式碼後,他們才會發現他們正在使用複製品!

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

為了好玩而使用底線

在變數名稱之前加上底線 ___。例如 _name__value。如果只有你知道它們的含義,那就太好了。或者,更好的是,僅為了好玩而新增它們,完全沒有特定的含義。或在不同的地方有不同的含義。

一箭雙鵰。首先,程式碼變得更長且更難讀取,其次,其他開發人員可能會花很長時間試圖找出底線的含義。

一位聰明的忍者會在程式碼的某個地方加上底線,而在其他地方避開它們。這使得程式碼更加脆弱,並增加了未來出現錯誤的可能性。

展現你的愛

讓所有人看到你的實體有多麼宏偉!像 superElementmegaFrameniceItem 這樣的名稱肯定會讓讀者茅塞頓開。

的確,一方面,寫了一些東西:super..mega..nice.. 但另一方面 - 這沒有提供任何細節。讀者可能會決定尋找隱藏的含義,並沉思一兩個小時他們有償的工作時間。

覆蓋外部變數

在光線中時,無法在黑暗中看到任何東西。
在黑暗中時,可以在光線中看到所有東西。

關尹子

在函式內外使用相同的變數名稱。很簡單。無需費力想出新名稱。

let user = authenticateUser();

function render() {
  let user = anotherValue();
  ...
  ...many lines...
  ...
  ... // <-- a programmer wants to work with user here and...
  ...
}

跳進 render 的程式設計師可能會沒有注意到有一個本機 user 遮蔽了外部 user

然後他們會嘗試使用 user,假設它是外部變數,是 authenticateUser() 的結果……陷阱出現了!你好,除錯器……

到處都是副作用!

有些函式看起來沒有改變任何東西。例如 isReady()checkPermission()findTags()……假設它們執行計算,尋找並傳回資料,而不會改變它們之外的任何東西。換句話說,沒有「副作用」。

一個非常漂亮的技巧是在它們中新增一個「有用的」動作,除了主要任務之外。

當你的同事看到一個名為 is..check..find... 的函式改變了一些東西時,他們臉上驚訝的表情 - 肯定會擴展你的推理界限。

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

展現你的原創思考!讓 checkPermission 的呼叫傳回的不是 true/false,而是一個包含檢查結果的複雜物件。

那些嘗試寫 if (checkPermission(..)) 的開發人員會疑惑為什麼它不起作用。告訴他們:「閱讀文件!」並提供這篇文章。

強大的函式!

偉大的道到處流動,
向左也向右。

老子(道德經)

不要受限於函式名稱所寫的內容。要更廣泛。

例如,函式 validateEmail(email) 可以(除了檢查電子郵件是否正確)顯示錯誤訊息並要求重新輸入電子郵件。

函式名稱不應明顯顯示其他動作。真正的忍者程式設計師會讓它們在程式碼中也不明顯。

將多個動作合併成一個動作可以保護你的程式碼不被重複使用。

想像一下,另一個開發人員只想檢查電子郵件,而不輸出任何訊息。你的函式 validateEmail(email) 同時執行這兩個動作,不適合他們。因此,他們不會因為詢問任何相關問題而打斷你的冥想。

摘要

以上所有「建議」都來自實際程式碼……有時是由經驗豐富的開發人員撰寫的。也許比你更有經驗 ;)

  • 遵循其中一些建議,你的程式碼將充滿驚喜。
  • 遵循其中許多建議,你的程式碼將真正屬於你,沒有人會想改變它。
  • 遵循所有建議,你的程式碼將成為尋求啟蒙的年輕開發人員的寶貴課程。
教學課程地圖

留言

留言前請先閱讀這段文字…
  • 如果你有改善建議,請 提交 GitHub 問題 或提出 Pull 要求,而不是留言。
  • 如果你無法理解文章中的某個部分,請詳細說明。
  • 要插入少量的程式碼,請使用 <code> 標籤,要插入多行程式碼,請將它們包在 <pre> 標籤中,要插入超過 10 行的程式碼,請使用沙盒(plnkrjsbincodepen…)