Enemy of Clean Code

Clean Code
#心得 #Performance

在現實開發中,有許多因素和習慣會成為 Clean Code 的「敵人」。這些「敵人」通常會導致程式碼難以理解、難以維護、出錯率高,最終影響團隊的開發效率和軟體的品質。

一﹑管理(Management)

「管理」會被視為「敵人」的其中原因是,各企業、團隊的文化習慣不同,包括交付壓力、不良指標、缺乏所有權。

交付壓力(pressure to ship)

在軟體開發中有所謂的開發時程,但開發時程並不能保證按計畫時間完成,如果開發不如預期,deadline 可能就會成為一個沉重的壓力。

也正因為這些壓力,開發者不得不犧牲程式碼品質,因為從實務的角度來看,交付程式碼往往都會是先考慮「完成度」再考慮「品質」。

像是,在解決一些複雜的問題時,理想情況下應該花時間進行思考尋找最佳解,但考慮到開發時程的種種限制,你可能會先寫出一個勉強能動的解決方案,並暫時擱置優化,就是大家常說的「先求有,再求好」。

這種做法短期內能滿足交付需求,但隨著各種 task 堆疊,優化的工作會一再被推遲。當下一個 Sprint 又開始,這些尚未解決的問題就增加了系統的不穩定性,最後可能變成技術債。

解決這種混亂的辦法,就在於如何在「交付時間」和「技術債」之間做出妥協(compromise)。但妥協並不是說就完全放掉品質,而是在兩者之間取得平衡,想清楚 Priority,哪部分是可以妥協,哪部分需要堅持, 讓他們理解以長期來看這些堅持是必要的,有時候也要學會為五斗米折腰。

不良指標(bad metrics)

在軟體開發中也有一些常見的指標,像是:

  • 有多少 Bugs?
  • 該程式的效能如何?
  • 有多少測試覆蓋率(test coverage)?

這些都能夠幫助我們把控程式碼品質,但對於開發者來說,最讓人討厭的是用來衡量開發者的「產出」(output)和「生產力」(productivity)的指標,像是:

  • 有多少行 code、commits 或 MR/PR?
  • 完成了多少 feature?
  • 做了多少 story points?

對於非技術管理者來說,他們可能認為「寫了多少數量的程式碼」是一個直觀且可量化的指標,能快速反映開發者的努力程度或生產力。

但這已經完全偏離軟體開發的本質,軟體開發應該要是追求「高效能」、「穩定」,且「易於維護」的程式碼才是價值所在。

clean code 中有引用到一句話來解釋,出自英國經濟學家查爾斯·古德哈特(Charles Goodhart)提出的古德哈特定律(Goodhart′s law):

「When a measure becomes a target, it ceases to be a good measure.」

意思是,當一項指標成為目標時,它就不再是一項好的指標。

如果有興趣也可以讀看看這篇 文章,淺談 單一指標對決策的影響-古德哈特定律。

缺乏所有權(lack of ownership)

所有權是判斷這 codebase 健康的關鍵,這裡的所有權是指對程式碼的「關注度」或者說是「責任感」,隨著不斷的更新與迭代,系統的穩定性、可靠性和可維護性也當然會隨著時間流逝而慢慢降低。

若缺乏持續關注,最糟情況,標準可能會下降到「只要程式碼能正常運作就好」,當這種狀況開始發生,可能導致技術債的累積,增加未來還債的成本。

而維持關注其中需要的因素,就是一定要有「自豪感」(pride),如果一個開發者對程式碼無法產生自豪感,表示你對自己的工作沒有信心,也對你寫出來的程式碼品質不保證,那將會影響整個系統的健康。

程式碼的所有權不是一個人的責任,而是整個團隊的共同責任。

當每個開發者都對程式碼充滿自豪感,並願意承擔維護與改進的責任,系統的穩定性、效能和可維護性才能有效的持續提升。

二﹑自我(Self)

在軟體開發領域,任何開發者一定都多少有「自我」的意識,這是在創造的過程中對成就感和自我價值的追求,也確實是許多開發者的動力來源。

但如果不加以控制,容易導致寫程式只為給人留下深刻印象,並提升我們的優越感,而不是考慮維護性與可用性。

賣弄語法(Overly Clever Syntax)

過度追求展示語法使用的技巧,為了顯示自己對高階語法的熟悉度,使用過於複雜的語句與嵌套式結構,雖然看到當下可能為之一亮,但卻增加了團隊的維護成本。

像是,每當發現到語言的新特性時,就會想馬上在專案中直接使用,但卻忽略了這段程式碼對於未來維護或擴充上真的有幫助嗎?

  1. 舉例:

    const complexFunc = arr => arr.map(x => x * x).filter(x => x % 2 === 0).reduce((a, b) => a + b, 0);
    
  2. clean code 書中範例:

    function showNotification(message) {
      hasUserEnabledNotifications() && (
        new Notification(message).show() &&
        logNotificationShown(message)
      );
    }
    

    更好的做法應該是用更常規且清楚的方法表示:

    function showNotification(message) {
      if (hasUserEnabledNotifications()) {
        new Notification(message).show();
        logNotificationShown(message);
      }
    }
    
  3. 分享 Reddit 上的最佳示範

通常這種以自我為中心的做法,將程式碼限制在少數與自己具有相同認知的開發者,忽視了團隊協作的本質,當未來需要由其他開發者接手維護和擴充時,他們需要花費更大量的時間解偶,甚至還可能引入其他新的問題。

固執的意見(Unyielding Views)

在程式設計或選擇使用不同技術時,因個人偏好而拒絕接受他人的建議或考慮更好的替代方案。這種固執通常源於對自身能力的過度自信,或對新技術、新方法的抗拒。

常見例子:

  1. 堅持使用過時技術

    • 認為新技術風險高,成本大,不願投入時間學習。
    • 例如:在現代 Web 開發中,依然固守 jQuery,而拒絕考慮 React、Vue 等更適合的框架。
  2. 抗拒程式碼重構

    • 認為現有的程式碼「能跑就好」,不需要任何優化。
    • 拒絕採納團隊建議,認為自己的程式碼「完美無缺」。
  3. 忽視團隊共識

    • 拒絕遵守團隊的程式碼風格或技術規範,堅持自己的寫法。
    • 例如:團隊決定使用 ESLint 規範程式碼風格,他卻認為這種工具「沒必要」。
  4. 不願學習新工具

    • 認為熟悉的工具已經足夠,拒絕嘗試 CI/CD、容器化部署等現代開發流程。

冒名頂替症(Impostor Syndrome)

冒名頂替症(Impostor Syndrome)是一種普遍的心理現象,讓人覺得自己不配擁有現在的成就或地位,覺得身邊的同事都更有能力,而自己只是在「偽裝」成為專業人士,認為自己只是運氣好,碰巧近來這團隊。

這種感覺其實是行業特性使然,科技領域的廣度和深度無法讓任何人掌握所有技能,所以當面對未知的挑戰時,難免會產生焦慮與自我懷疑。

而這種心理狀態可能會帶來幾種影響:

  1. 缺乏決斷力:對自己的判斷不信任,容易選擇保守路線,錯失最佳解決方案。
  2. 缺乏冒險精神:害怕失敗而不敢做出大膽的決定,例如嘗試新技術或對程式碼進行重構。
  3. 溝通不足:由於對自身能力的不信任,不敢表達自己的觀點,可能降低與同事或涉眾討論的積極性,進而影響項目進展。

我們需要明白的是,沒有人是全能的,尤其在這麼大的領域中,雖然團隊成員的能力、經驗、特質不同,但也因為這種多樣性才能在解決複雜問題時能夠有不同視角的看法。

「自我懷疑並不意味著無能,而是成長中的自然階段。」

三﹑貨物崇拜(Cargo Cult)

貨物崇拜(Cargo Cult)的概念源自人類學,指某些土著部落在接觸到文明時,透過模仿他們所觀察到的行為試圖吸引更多物資。

這些部落可能會建立類似飛機跑道或模仿軍事儀式,期望能像西方人一樣獲得飛機送來的貨物,儘管他們並不是真的了解這些行為背後的邏輯和運作原理。

這個詞最早被用在描述太平洋島嶼上的現象,在第二次世界大戰期間,當時盟軍在這些島嶼上建造機場並向當地人提供物資,但戰後盟軍撤出,物資也停止運送,但當地人認為只要模仿西方人的行為,像是建立機場跑道或模擬通訊,就能召回飛機帶來物資。

貨物崇拜程式碼

在程式設計中,貨物崇拜程式碼是比喻一種表面上模仿但缺乏深度理解的行為,這個術語也在 computer science 中被廣傳,批評一些科學領域中只複製表面,而不是用真正科學的方法來實踐。

通常貨物崇拜程式碼看起來都正確,且也可以執行,但實際上可能存在很多問題,像是難以維護、不符合需求、有潛在風險。

我自己歸納這幾點,也是我個人會做的事:

  1. 盲目的使用一些設計模式:

    通常使用設計模式必須有他能派上用場的情境,如果強行將某些設計直接套到現有架構,可能造成 Over Design 或 Poor Design。

  2. 過度抽象化

    可能過去看過什麼特別的架構或寫法,將原本簡單的邏輯過度抽象,導致程式碼變得複雜且難以理解。

很多時候都是覺得這東西很炫泡,就想去使用他,這個當然可以構成理由,但好的設計或架構都是需要時間來印證的,應保持謹慎與務實,確保其真正為專案帶來價值才是正確。

貨物崇拜工具和函式庫

貨物崇拜也可以是工具或函式庫,每個開發者一定都有自己喜歡的一套開發環境,會依賴好用的工具或函式庫,但如果你並不了解他們而盲目的使用就需要注意了。

  1. 過度依賴主流工具或框架:

    像剛剛前面講到的,其實很多時候大家並不完全知道這個到底好用在哪,解決了什麼問題,大多都是基於受歡迎而去使用他,不是基於專案需求去使用。

  2. 過度堆疊 tech stack:

    有時候在做 side project 時,會希望自己能從中學到什麼什麼,所以在專案中導入了一堆技術,但實際上用到的只有三兩個,而這些都是隱藏的維護成本,還有可能導致工具和工具之間產生衝突等等,這點也經常在開源社群被提到。

參考來源

  • Clean Code 學派的風格實踐