Clean Code
忙了半年左右,我回來了(?),來寫點早該看完的《Clean Code》小心得。
整本書講 clean code 的原則,最後以一個大例子運用原則跟示範 refactor。寫那些原則像在抄書,只針對比較有感的原則跟 code smell 寫點心得。
最少驚奇(嚇)原則
讓看你的 code 的人(很可能就是你自己)對那段 code 的預期符合實際結果,儘量符合 common sense 以減少驚奇、驚嚇與驚恐。code 愈能符合預期,愈能減少進去實作看細節的時間。反之,如果常常不符預期,不用多久大家就會戒慎恐懼的每次都進去看實作,不然天知道它會發生什麼事,對吧?
不過我承認,似乎不是所有人的 commen sense 都一樣。
base class 不應該知道實作細節
跟實作細節有關的常數、變數或 function 只該出現在 derived class、不該出現在 base class。
base class 不該對實作有任何假設。
Static vs Non-static function
本書建議少用 static function,在模糊不確定時讓 function 是 non-static,使用 static function 要確定不會有任何可能想讓該 function 是多型。
我好像曾經在哪裡看過建議使用 static function 而非 non-static function,但忘記是哪了,也可能我記反了。總之有段時間只要遇到沒使用 member 的 function 一律宣告成 static,因為既然實作沒用到 member 就限制住它。
好吧這是前陣子的爭論點之一。我發現在 interface 上將 function 們宣告成 static 會限制 class 的實作方式、class 無法使用 member,而 interface 不該知道或者限制 class 的實作(類似上一點的概念)。以多型基本上是操作 object 來說,讓 interface 的多數 function 是 static 挺奇怪的,static 表示不需要 object 就可以使用,那好像沒有定成 interface 意義?
所以後來改觀了,現在傾向用 non-static function 而非 static,static function 只在有語意跟功能上較適合 static 才用。
不要在實作時假設其他 class 的東西
這不是書裡的原則,是我的感想。這藏在很多地方,像是 base clas 不該知道實作細節、不要在 class A 假設知道 class B 的任何事、要使用多型就不要假設某個變數是某個 class 的 object 等等。
發現實作上很容易忽略,可能因為如果不是使用別人的介面,程式設計師知道相關 class 們的各種細節,以至於容易把屬於 A 的東西放進 B 而渾然不覺。我避免這種「假設」的方法是想像自己是 class A 然後問:「我該知道這個資訊嗎?」
用多型取代 if/else 或 switch/case
不是絕對,但如果 code 裡到處有跟 type 相關的 switch/case 或 if/else,用多型比較好。讓生出多型 object 的地方是唯一有 switch 的地方,其他部份的 switch 就能用多型 object 處理。
Structure over Convention(結構勝於常規)
「具有強制決策設計特性的結構」勝於「慣例」。
有大家遵守的慣例當然很好,但用強制性的程式結構更好。例如用有 abstract function 的 base class 比用 switch/case 好,因為 switch/case 的撰寫不是強制性的,很可能會漏改,而 abstract function 的實作是強制的,只要繼承該 base class 就必須實作,不然會 compile 不過或跑起來 error。
強制性的程式結構可以降低漏改或改錯的可能性,改錯馬上就知道了。套句以前聽過的話:「就是要讓寫錯的編不過,他編不過就知道錯了」
再說了,我很懶得記慣例(喂)
時序耦合
時序耦合是指某些 function 必須以某個次序 call,例如有三個 function A()、B()、C() 需要依序 call。如果 function 沒有顯著的顯示出時序耦合,可能被以錯誤的順序 call。書裡是建立流水線來凸顯時序性,也就是讓 B()
的 input 是 A()
的 output、C()
的 input 是 B()
的 output。
另外我認為 public function 似乎儘量不要有密切的時序耦合比較好,例如上述三個 function 是 public 要依序而且馬上 call 才能完成一件事,這種情況用另一個 public function 把 call A()
、B()
、C()
包起來比較好。