[note] Clean Code
Naming
好的命名能夠讓開發者不用去看內部的實作,就能理解它的意思。
getUser()
可能太過籠統,視情況需要的話可以使用getUserByEmail()
Functions
抽成 function?
可以思考下面這兩種寫法:
在一般的情況或還無法確定未來的情境會不會變的更複雜前,會傾向使用左邊的寫法,邏輯一目了然;相較之下,右邊的情境會讓開發者需要跳到另一個函式中 才能確認該判斷式實作的內容,增加了開發者的認知負擔。
但右邊的寫法並非沒有任何好處,當這個判斷邏輯:
- 會在多個地方被使用時,抽成 function 可以避免開發者拼錯字。雖然可以透過將該單字抽成 CONSTANT 來避免拼錯字的問題,但開發者還是會需要在使用的地方 import 這個 constant,多一行 import 也有點煩,所以抽成 function 可以避免這個問題(如果有使用 TypeScript 也可以直接避免拼錯字的問題)。
- 當這個判斷的邏輯變得複雜時。如果判斷邏輯不像是
status === 'fulfill'
這麼單純的話,抽成 function 會是合理且必要的選擇 - 可以針對這個邏輯進行 unit test
Control Structures & Errors
Avoid Deep Nesting: Use Guards & Fail Fast
原本的寫法:
function withoutGuard() {
if (isValid) {
// do a looooot of stuff
}
}
改成 early return:
function withGuard() {
if (!isValid) {
return;
}
// do the same stuff here
}
另外,使用 Strategic Pattern、或把 function 保存在物件(Map)中,也是很好用來處理 nested if 的情況:
const orderStatusProcessor = {
success: () => {/*... */},
failed: () => {/*... */},
pending: () => {/*... */},
};
function processOrder(order) {
// 執行 orderStatusProcessor
orderStatusProcessor[order.status]();
}
Error Handling
如果它是個錯誤,就把它以錯誤拋出,而不是直接 return 它。
沒有使用 error:
if (!isValid) {
return { code: 111, message: 'it is invalid' };
}
使用 error 處理:
if (!isValid) {
const error = new Error('it is invalid');
error.code = 111;
throw error;
}
如果所有 error 的格式都是一樣的,則可以在某一個地方統一使用 try...catch
來處理這些錯誤。
Using Factory Functions & Polymorphism
Factory Function 的概念比較像是會回傳一個「東西」的函式,有點類似 class。
Reference
- Clean Code @ Udemy