iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
自我挑戰組

一杯咖啡的設計課:30 天 Design Pattern 的自我修煉系列 第 8

Day 8|先別急著 SOLID,用 KISS、YAGNI、DRY 幫架構踩煞車

  • 分享至 

  • xImage
  •  

今天柴咖啡店休,我們也休息一下,來聊一下觀念~~

哇,那既然 SOLID 五個原則講完了,例子我也看得懂,那以後我每次開發都強制使用,將五個原則貫徹始終,甚至把 SOLID 刺在手臂上,是不是可以從 junior 直接跳級成 CTO 了

https://ithelp.ithome.com.tw/upload/images/20260905/20183470dyWKZGyPgp.jpg
https://ithelp.ithome.com.tw/upload/images/20260905/20183470WIFhu7PzN5.jpg
想起我起初遇到一個很優秀的前輩跟我說的名言:「 軟體開發的根本是需求溝通 」

需求會變,就會需要成本,需要成本我們就要好好設計

我們來回顧一下 SOLID 的本質是什麼

「當需求變動時,怎麼設計程式碼,才能讓『變動的成本』不會隨著系統長大而指數爆炸?」

SOLID 的出發點是對的。但問題往往不是原則本身,而是套用的時機

為什麼會有 SOLID

系統還小的時候,什麼都塞在一起也跑得動。小黃(還記得嗎?最初寫系統的朋友)
https://ithelp.ithome.com.tw/upload/images/20260905/20183470atQtN5orfq.jpg

一開始幫朋友寫的點餐系統,一個 class 搞定,沒人有疑問,但也可能是沒人看得懂程式碼

但系統長大之後,事情開始變得麻煩,阿柴接手後才發現改一個折扣邏輯,結果訂單顯示壞了;

加一個新的付款方式,卻動到不相關的庫存計算;

每次改東西都要祈禱不要壞其他地方

SOLID 就是從這些痛苦裡歸納出來的原則,前人在被系統折磨過(?)之後,整理出來的一套「怎麼讓改動的代價不那麼大」的經驗法則

什麼時候該用,什麼時候不該用

什麼時候該用?

  • 單一職責原則(SRP):這是唯一在開發當下就應盡量遵守的原則。讓一個函數或類別只專注做一件事,幾乎沒有任何抽象成本,且能立刻提升可讀性與測試性

  • 核心業務邊界明確時:如果你在開發初期就已經 100% 確定某些部分未來必然會替換(例如資料庫存取層、第三方金流 API、寄信服務),直接使用依賴反轉(DIP)引入介面也是合理的

什麼時候該等出現「痛」時再重構引入?

  • 開放封閉原則(OCP):出現第 3 次變動(符合 Rule of Three:事不過三),代表業務邏輯有擴充需求,此時才透過多型或策略模式重構

  • 介面隔離原則(ISP):先寫出簡單好用的類別;當發現某些客戶端被迫實作一堆用不到的空方法時,再來拆分介面

  • 里氏替換原則(LSP):當子類別開始出現「覆寫父類別方法卻丟出 NotImplementedException」等破壞契約的行為時,代表繼承關係設計錯誤,應重構改用組合(Composition)

阿柴是在需求開始變複雜、改東西開始會出錯的時候,才學會一條一條把這些原則用進去

既然定義好 SOLID 的使用時機,那我們延伸探討三個觀念,KISS、YAGNI、DRY

KISS、YAGNI、DRY 是什麼

這三個老大哥都比 SOLID 資歷更老,也更直觀:

KISS(Keep It Simple, Stupid)

源自美國海軍 1960 年代的工程設計原則,後來被軟體業借用:能簡單解決的問題,就不要故意做複雜

不必要的複雜度本身就是 bug 溫床,多一層抽象,就可能多一個出錯、也多一個要維護的地方

kaisheng 大大解釋得很清楚也很棒

任何傻子都能寫出電腦看得懂的程式,而優秀的程式設計師則會寫出讓人類看得懂的程式

KISS 主要圍繞在可讀性的部分,畢竟人一天的認知是有限的,如果用很複雜的方式去解決簡單的問題,不僅看的人很辛苦,維護的人也很辛苦

相反,如果在開發過程實踐 KISS 原則,可讀性提高,保持簡單和直觀,避免過度設計與抽象化,也會讓維護的成本降低

那什麼時候該提醒自己需要 KISS?

當發現自己在寫一段「目前沒有任何需求」的彈性寫法,或單純想讓程式碼看起來更專業而硬加一層設計時,就是該喊卡的時候

YAGNI(You Aren't Gonna Need It)

出自 Extreme Programming(極限編程),由 Ron Jeffries 提出:不要為了「將來可能用得到」而現在就先做

我的理解是,開發應專注於當下該解決的需求,而不是針對尚未發生的事情,去多設計彈性或者不必要的功能

畢竟假設多包的那層彈性,十次有九次,等真的需求來的時候,會發現當初猜錯方向,起初的自我感動設計彈性反而會變成先拆掉的包袱

任何變動都會有成本,而如何讓越低的成本敲動最大的效益,我想是一個優秀的工程師的必備條件

DRY(Don't Repeat Yourself)

最後一個,出自《The Pragmatic Programmer》,Andy Hunt 與 Dave Thomas 提出,原文是:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

起初看到這段時,我在想,代表出現兩次以上的程式碼,通通都要濃縮嗎? 這裡我們先來看看以下的例子

class Coupon { public decimal Rate = 0.1m; }
class Tax    { public decimal Rate = 0.1m; }

兩個 Rate 都是 0.1,那依照 DRY 的方式,將欄位抽成共用的基底類別:

class Percentage { public decimal Rate = 0.1m; }
class Coupon : Percentage { }
class Tax    : Percentage { }

好像合理,但我們區分這兩個知識體來說, Coupon.Rate 是「折扣打幾折」,Tax.Rate 是「稅率抽幾趴」,兩件事本來就無關,只是剛好都設計成 0.1,並不屬於同一份知識

所以 DRY 講的是在開發上不應該知識、意圖上的重複,強調的是「knowledge」而不是「code」

怎麼把這幾個觀念收斂呢

KISS、YAGNI、DRY 加上 SOLID,各自講起來都成理,但實際改程式碼的時候,總不可能五六條原則同時在腦中打架,想完腦袋也下課了

所以我把這幾個原則,初步想了一套篩選機制

  1. 先問 YAGNI:這個需求是不是真的存在,還是自己腦補?
  2. 再問 KISS:這個寫法會不會把簡單問題搞複雜?
  3. 再問 DRY:這是同一份知識重複,還是只是長得像?
  4. 三問沒問題,我們才輪到 SOLID 決定「拆到哪一層」比較合適

先確認需求是否存在,再確認是否複雜化,再確認知識是否重複,最後再依邏輯套用 SOLID 去處理

但人跟專案都是複雜的,這系列主要還是培養自己的判斷力,而不是學會一個功夫就要打遍天下無敵手

明天柴咖啡店營業,我們也要正式進入創建型 Pattern 的第一站:Factory Method

如果看不懂我寫的,可以看看延伸的資料,希望可以幫助到你

wiki - KISS

wiki - YAGNI

wiki - DRY

Martin Fowler - Yagni

軟體設計原則 KISS (Keep it simple, stupid)


上一篇
Day 7|D (依賴反轉原則) 柴咖啡如何優雅解開資料庫與 LINE 的枷鎖?
下一篇
Day 9|Factory Method(工廠方法) 將物件的誕生交給子類別
系列文
一杯咖啡的設計課:30 天 Design Pattern 的自我修煉26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言