學而無思,則勞而無功;沒有學習的思想是危險的。
過去的程式設計師忍者使用這些技巧來磨練程式碼維護者的思維。
程式碼審查專家在測試任務中尋找它們。
新手開發人員有時甚至比程式設計師忍者更好地使用它們。
仔細閱讀它們並找出您是誰 - 忍者、新手,還是代碼審查者?
發現諷刺
許多人嘗試追隨忍者之路。很少人成功。
使代碼盡可能短。展示你有多聰明。
讓微妙的語言特徵引導您。
例如,看一下這個三元運算子'?'
:
// 取自著名的 javascript 函式庫 我=我?我<0? Math.max(0, len + i) : i : 0;
很酷,對吧?如果你這樣寫,那麼遇到這一行並試圖理解i
的值是什麼的開發人員將會度過一段愉快的時光。然後來找你,尋求答案。
告訴他們越短越好。引導他們走上忍者之路。
道藏於無言之中。只有道是善始善終的。
另一種縮短程式碼的方法是在各處使用單字母變數名。如a
、 b
或c
。
一個短變數會像森林中真正的忍者一樣消失在程式碼中。沒有人能夠使用編輯器的“搜尋”找到它。即使有人這樣做,他們也無法「破解」名字a
或b
意思。
……但有一個例外。真正的忍者永遠不會在"for"
循環中使用i
作為計數器。任何地方,但不是這裡。環顧四周,還有很多奇特的字母。例如, x
或y
。
如果循環體需要 1-2 頁(如果可以的話,讓它更長一些),那麼用一個奇怪的變數作為循環計數器就特別酷。然後,如果有人深入查看循環內部,他們將無法快速找出名為x
變數是循環計數器。
如果團隊規則禁止使用單字母和模糊的名稱 - 縮短它們,使用縮寫。
像這樣:
list
→ lst
。
userAgent
→ ua
。
browser
→ brsr
。
…ETC
只有真正具有良好直覺的人才能理解這些名字。嘗試縮短一切。只有有價值的人才能維護你的程式碼的發展。
大廣場沒有角落
這艘偉大的船隻最後完成,
偉大的音符是純淨的聲音,
偉大的形象沒有形式。
在選擇名稱時嘗試使用最抽象的單字。如obj
、 data
、 value
、 item
、 elem
等。
變數的理想名稱是data
。可以在任何地方使用它。事實上,每個變數都保存數據,對吧?
…但是如果data
已經被取得怎麼辦?試試value
,它也是通用的。畢竟,變數最終會獲得一個值。
依變數的型別命名: str
、 num
...
嘗試一下。年輕的入門者可能會想——這樣的名字對忍者真的有用嗎?確實,他們是!
當然,變數名仍然有意義。它說明了變數內部的內容:字串、數字或其他內容。但是當外人試圖理解程式碼時,他們會驚訝地發現實際上根本沒有任何資訊!最終將無法改變你深思熟慮的程式碼。
透過調試很容易找出值類型。但這個變數的意義是什麼?它儲存哪個字串/數字?
如果沒有良好的冥想,就沒有辦法弄清楚!
……但是如果不再有這樣的名字怎麼辦?只要增加一個數字: data1, item2, elem5
…
只有真正細心的程式設計師才應該能夠理解您的程式碼。但如何檢查?
方法之一 - 使用相似的變數名稱,例如date
和data
。
盡可能混合它們。
快速閱讀這樣的程式碼變得不可能。當出現拼字錯誤時……嗯……我們被困了很長時間,喝茶的時間。
可以說的道,並不是永恆的道。能被命名的名字,並不是永恆的名字。
對相同的事物使用相似的名稱會讓生活變得更加有趣,並向公眾展示您的創造力。
例如,考慮函數前綴。如果函數在螢幕上顯示一則訊息 - 以display…
啟動它,例如displayMessage
。然後,如果另一個函數在螢幕上顯示其他內容,例如使用者名,請以show…
開頭(例如showName
)。
暗示這些功能之間存在細微差別,但實際上並沒有差別。
與團隊的其他忍者達成協議:如果 John 在他的程式碼中開始使用display...
來「顯示」函數,那麼 Peter 可以使用render..
,而 Ann – paint...
。請注意程式碼變得多麼有趣和多樣化。
……現在是帽子戲法!
對於兩個有重要區別的函數 – 使用相同的前綴!
例如,函數printPage(page)
將使用印表機。函數printText(text)
會將文字顯示在螢幕上。讓不熟悉的讀者仔細思考一下類似名稱的函數printMessage
:「它把訊息放在哪裡?到印表機還是在螢幕上?為了讓它真正發光, printMessage(message)
應該會在新視窗中輸出它!
一旦整體被分割,各個部分
需要名字。
名字已經夠多了。
一個人必須知道何時停止。
僅在絕對必要時新增變數。
相反,請重複使用現有名稱。只需將新值寫入其中即可。
在函數中嘗試僅使用作為參數傳遞的變數。
這將使得很難確定變數now中的具體內容。還有它是從哪裡來的。目的是培養閱讀程式碼的人的直覺和記憶力。直覺較弱的人必須逐行分析程式碼並追蹤每個程式碼分支的變更。
該方法的一個高級變體是在循環或函數中間秘密地(!)用類似的值替換該值。
例如:
函數 ninjaFunction(elem) { // 使用 elem 的 20 行程式碼 元素=克隆(元素); // 還有 20 行,現在使用 elem 的克隆! }
想要在函數後半部分使用elem
程式設計師同事會感到驚訝......只有在調試期間,在檢查程式碼後,他們才會發現他們正在使用克隆!
經常在程式碼中看到。即使對經驗豐富的忍者也能致命。
在變數名前加上底線_
和__
。就像_name
或__value
一樣。如果您知道它們的含義,那就太好了。或者,更好的是,添加它們只是為了好玩,根本沒有特殊意義。或說在不同的地方有不同的意義。
一槍打死兩隻兔子。首先,程式碼變得更長且可讀性較差,其次,開發人員可能會花很長時間試圖弄清楚下劃線的含義。
聰明的忍者會在代碼的一個位置添加下劃線,並在其他位置避開它們。這使得程式碼更加脆弱,並增加了未來出錯的可能性。
讓大家看看你們的實體有多宏偉!像superElement
、 megaFrame
和niceItem
這樣的名稱肯定會給讀者帶來啟發。
事實上,從一方面來看,有些東西是這樣寫的: super..
、 mega..
、 nice..
但從另一方面來看——這並沒有帶來任何細節。讀者可能會決定尋找隱藏的意義,並花一兩個小時的帶薪工作時間進行冥想。
在光亮的時候,在黑暗中什麼也看不見。
在黑暗中,能看見光明中的一切。
函數內部和外部的變數使用相同的名稱。就這麼簡單。沒有努力發明新名字。
讓用戶=驗證用戶(); 函數渲染(){ 讓用戶 = anotherValue(); …… ....很多行... …… ... // <-- 程式設計師希望在這裡與使用者一起工作並且... …… }
跳到render
內部的程式設計師可能不會注意到有一個本地user
遮蔽了外部渲染。
然後他們會嘗試與user
一起工作,假設它是外部變量,即authenticateUser()
的結果…陷阱就出現了!你好,調試器...
有些功能看起來並沒有改變任何東西。像isReady()
、 checkPermission()
、 findTags()
...它們被假定執行計算、查找並返回數據,而不改變它們之外的任何內容。換句話說,沒有「副作用」。
一個非常漂亮的技巧是除了主要任務之外還為它們添加一個「有用」的動作。
當你的同事看到一個名為is..
的函數、 check..
或find...
改變某些東西時,他們臉上會露出茫然驚訝的表情——這肯定會拓寬你的理性界限。
另一種令人驚訝的方式是返回非標準結果。
展現你的原創思維!讓checkPermission
的呼叫傳回的不是true/false
,而是包含檢查結果的複雜物件。
那些嘗試編寫if (checkPermission(..))
的開發人員會想知道為什麼它不起作用。告訴他們:「閱讀文檔!」。並給出這篇文章。
偉大的道流遍四方,
向左和向右。
不要透過名稱中所寫的內容來限制功能。更廣泛。
例如,函數validateEmail(email)
可以(除了檢查電子郵件的正確性之外)顯示錯誤訊息並要求重新輸入電子郵件。
附加操作不應從函數名稱中顯而易見。真正的忍者編碼員也會使它們從代碼中變得不明顯。
將多個操作合併為一個操作可以防止您的程式碼被重複使用。
想像一下,另一個開發人員只想檢查電子郵件,而不輸出任何訊息。您的函數validateEmail(email)
兩者兼而有之,不適合他們。所以他們不會透過詢問任何事情來打斷你的冥想。
上面的所有“建議”都來自真實的程式碼……有時是由經驗豐富的開發人員編寫的。也許比你更有經驗;)
遵循其中一些,你的程式碼將變得充滿驚喜。
遵循其中的許多方法,您的程式碼將真正成為您的程式碼,沒有人願意更改它。
遵循所有這些,您的程式碼將成為尋求啟蒙的年輕開發人員的寶貴課程。