比較短的程式碼比較好嗎?
雖然減少程式碼會提高易讀性,但縮短讀程式碼的時間才是重點。
表層結構
- 清楚的命名方法跟變數名稱
- 方法不需要用
do
- 選擇詞彙的時候不要用模擬兩可的名稱,ex: pop popItem
- 在方法名稱加入更多的資訊
- 方法不需要用
function getPage() {}
// 對方可能不知道 getPage 的實作方式?爬蟲? ajax?
function fetchPage() {}
// 可能比較清楚是用 ajax 的方式並且回傳 json。
- 找尋更明確的詞彙
- send => deliver dispatch announce route
- find => search extract locate recover
- start => launch create begin open
- make => create setup build generate add new compose
清楚明確比可愛更重要
-
就算是 tmp 變數,也可以提供多一點資訊。
- tmpNumber
- tmpFile
- tmpUsrData
-
如果迴圈的 i,j 有意義,那麼就取個適當的名字。 ex: row col index
-
選擇具體的方法名稱。
-
如果變數具有單位,把單位放進去。
- startSec
- delayMs
-
重要屬性的變數命名
- plainData
- entryptedData
-
如果變數的作用範圍比較大的時候,用比較長(or 包含資訊較多)的變數是比較好的選擇,相反的如果只有幾行程式碼就結束,其他人可以馬上看出這個變數在做什麼,那麼就算用
alias
也沒關係。
不被誤解的名稱
- filter 是把東西 filter 掉,還是留下?
- min max 前綴
- 布林值
- computeData => 比較像執行一個耗費較大的 function
排版一致
- 符合排版一致
- 調整程式碼有的相似外觀
- 相關程式碼為一個段落。
- 註解的美學
為什麼排版那麼重要?第一個是其他人(或者是你)以後再看程式碼的時候,至少比較容易(也比較願意)看得懂,再來是你可以花更少的時間去理解你的 code 在幹麻,何樂不為?
代碼品質工具
-
eslint
-
stylelint
用方法消除混亂?
如果你發現你在做某一件事情感覺很混亂的時候,就該使用 method 包裝。
用精美不實的包裝來欺騙消費者是人類的本性(誤)。能不能欺騙別人不是重點,重要的是是否能夠欺騙你自己。連你自己都不尊重的 code 別人也不尊重的。
例如說:
assert(checkTime("12:00")) === "12:00"
assert(checkName("kalan", 20)) === { name: "kalan", age: 20 }
assert(checkPaid(20000, true)) === 20000
仔細觀察一下上面的 code ,不難發現它們都是在做一些同樣的事情,而且還有一些重複出現的字串。而且太長了,我們需要一點時間才能知道這幾行 code 在幹嘛。
這個時候就需要重構啦,我們可以用 method 把它包裝起來。
function checkValue(type, value) {
if (type === "time") {
assert(checkTime(value));
}
if (type === "name") {
assert(checkName(value) === value;
}
if (type === "paid") {
assert(checkPaid(value)) === value;
}
}
// checkValue(type, value);
// [string] [depend]
checkValue("name", kalan);
checkValue("time", 12:00);
checkValue("paid", 20000);
這樣一來 code 比較簡潔,易讀性也提升了! 再次強調,並不是比較精簡的程式碼就是好 code ,容易讓人理解的 code 才是好 code。 除了這些之外,還有一些好處:
- 清楚呈現測試的部分。
- 更容易加入其他測試!
照順序及段落區分:
落落長的程式碼不僅是別人,連自己都不會想看。在變數宣告、陳述式表達的時候,可以依照所做的行為不同拆分。這個寫文章也需要段落是同樣的道理。
function getUserInfo(userName, age) {}
getUserInfo("kalan", 20)
// getUserInfo(userName, age)
// [string] [number]
getUserInfo("kalan", 20)
如果有相同的函式呼叫的話,可以讓參數對齊方便閱讀。
command = {
{ "timeout" , null, cmd_spec_timeout},
{ "timestamping" , bull, cmd_adj_boolean},
f
}
在寫註解的時候,其實不需要太拘泥,把自己當時想到的想法,以及這個 function 應該做的事情寫下來就好了,有時候過了一段時間你會忘記這個 function 在幹麻。
--
#2. 註解篇:
註解是為了讓其他人了解程式設計者的想法而存在的。同時也讓自己了解自己當初的想法。
- 如何撰寫好的註解,以及哪些東西
不需要註解
。 - 不該註解的部分
- 為讀者設身處地著想
不要讓註解搶走了程式該有的位置
避免寫作抗拒。這通常需要一段時間才能體會到。但當專案架構還沒有變得複雜之前就盡快寫註解絕對是件好事。不然你只能寫下違背良心的
// TODO: refactor
然後就再也沒有下文了。
結語
- 選用特定寫法的原因
- 程式碼中的缺陷。
- 使用者會對哪個部分感到疑惑
維持註解簡潔
- 用更精確的方式來描述自己的程式碼,並且不要用代名詞來描述參數。
- 如果參數的行為較複雜,可以直接給範例讓使用者一目了然。
#3. 流程控制:
最常見的就是 if/else
的判斷。書中提供一個準則,就是肯定的條件句先擺前面、先處理簡單的狀況。
如果你的 function / method 是有返回值的,就盡快讓他 return 吧!
- 善用迪摩根定律:這個定律應該理工科都有印象吧!他可以把一些比較複雜的邏輯判斷簡化。
與複雜的邏輯搏鬥:
書中提到一個蠻有趣的方式,我想把它記錄下來。 在實作 range 的時候,我們可能有一個方法 overlapWith ,來判斷兩個 range 之間是否有重疊。比起使用直接比對這兩個 range 是否有重疊,不如比對這兩個 range 是否不重疊更簡單。因為只要比對兩種狀況 => other 的 end 在 range 之前。 other 的 start 在 end 之後。
將龐大的表示式用變數裝起來。
$(".thumb_up").removeClass("highlighted")
$(".thumb_up").removeClass("highlighted")
$(".thumb_up").removeClass("highlighted")
// refactor
const $thumbUp = $(".thumb_up")
const highLight = "highlighted"
$(".thumb_up").removeClass("highlighted")
$(".thumb_up").removeClass("highlighted")
$(".thumb_up").removeClass("highlighted")
//
4. 變數:
變數存在越久,就越難 debug
- 減少不必要的變數宣告。
什麼是不必要的變數?
- 無法讓意思變得更言簡意賅
- 本身的邏輯不複雜,不需要再用變數取代
- 只使用一次
- 使用一次性寫入的變數
在 functional programming 當中,我們希望 function 是 pure 且 immutable 的,對於變數來說也是,盡量讓你的變數為 const 或 immutable 的。這樣子不僅你對 function 可以一目了然,也比較容易掌握出錯的點在哪裡。
將想法轉為程式碼:
先用口語敘述行為,再把程式的行為轉換為程式碼。這樣子可以幫助程式設計師寫出更自然的程式碼。
避免撰寫不必要的程式碼
- 了解需求
- 重新思考需求
- 定期閱讀 API 以維持對標準函式庫的熟悉度