簡單設計三原則 (DRY / KISS / YAGNI)

★★★★Studied

FromAgile Principles, Patterns, and Practices

📚 From the Books

簡單設計三原則 (DRY / KISS / YAGNI)ConceptPrinciples

XP 的「簡單設計」把好設計壓成三句箴言:KISS(考慮可能有效的最簡方案)、YAGNI(你不會需要它——別為想像中的未來預先加基礎設施)、DRY(一次且僅一次——發現重複就消除,這會自然驅動出好抽象)。它們是 SOLID 之外的「日常剎車」:讓設計只服務當前迭代,不預先擔憂未來。

🧠 When to Use

TIP

訊號:你正在寫「以後可能會用到」的擴充點;同一段邏輯在三個地方各抄一份;或為了「更有彈性」把簡單需求包成三層抽象。這三條原則就是叫停的手煞車。

⚖️ Structure & Variants

KISS — 考慮可能有效的最簡方案
// ❌ 需求只是「打九折」,卻先開一套可插拔的規則引擎
class DiscountEngine(private val rules: List<DiscountRule>) { /* ... 一堆抽象 ... */ }

// ✅ 最簡方案:一個函式就夠,等真的有第二種折扣再長出抽象
fun memberPrice(base: Int): Int = (base * 0.9).toInt()
  • 「Consider the simplest thing that could possibly work」——先寫能動的最簡碼,需要彈性時再靠重構引入抽象。
YAGNI — 你不會需要它
// ❌ 現在只支援信用卡,卻預先塞了 PayPal / 加密貨幣 / 分期 的空殼
interface PaymentGateway { /* ... */ }
class CreditCard : PaymentGateway
class PayPalStub : PaymentGateway      // 沒人用,先擺著
class CryptoStub : PaymentGateway      // 想像中的未來

// ✅ 只做當前迭代要的;真的要加通道時,那時的需求會告訴你正確的介面長相
class Checkout(private val card: CreditCard) { /* ... */ }
  • 抵抗「提前加入基礎設施」的誘惑。預先加的擴充點多半猜錯形狀,反而成為之後改動的阻力——這與 OCP 的「上當一次(fool me once)」是同一件事的兩面。
DRY — 一次且僅一次(Once and Only Once)
// ❌ 同一條稅率規則抄在三個地方,改一處就漏兩處
fun invoiceTotal(x: Int) = x + x * 5 / 100
fun quoteTotal(x: Int)   = x + x * 5 / 100
fun receiptTotal(x: Int) = x + x * 5 / 100

// ✅ 知識只存在一處,重複被消除
const val TAX_RATE = 0.05
fun withTax(x: Int): Int = x + (x * TAX_RATE).toInt()
  • DRY 針對的是知識的重複(同一條規則、同一個決策),不是「長得像的程式碼」。消除重複會自然把共同知識逼成一個好抽象。

⚠️ Misuse & Anti-patterns

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading

🔗 Dive Deeper