這段程式是不是過度設計了?

Easy★★★★Studied

FromRefactoring for Software Design SmellsAgile Principles, Patterns, and Practices

Concepts practiced📏 簡單設計三原則 (DRY / KISS / YAGNI)📏 開放封閉原則 (OCP)

Convention: read the requirements & constraints first, sketch your own design, then expand the reference to compare.

📚 From the Books

這段程式是不是過度設計了?ProblemEasy反模式辨識

一個只支援 HTML 報表的工具,卻預先蓋了 AbstractReport → DefaultReport → AnnotatedReport → HtmlReport 四層階層,其中 annotation 功能根本不在 roadmap 上。程式看起來「很有彈性」,但沒人用得到那些彈性。這是過度設計——怎麼辨識、怎麼收?

🎯 Scenario

// 需求只有一種報表格式,卻預先為『想像中的未來』鋪了一整條 list-like 階層
abstract class AbstractReport
open class DefaultReport : AbstractReport()
open class AnnotatedReport : DefaultReport()   // annotation 不在計畫上,純想像
class HtmlReport : AnnotatedReport()           // 每層只有一個子型別

壞味道:不必要的複雜性(Needless Complexity)——設計中包含目前無用的結構。書中對應兩個具體味道:Unnecessary Abstraction(為便利或「為建而建」引入瑣碎抽象,例如替一個整數旗標硬開一個類別)與 Speculative Hierarchy(為想像中的需求預留型別,違反 YAGNI)。

🧠 Intuition

TIP

先別看下面。對每一層抽象問一句:現在有真實需求要它嗎? 如果理由是「萬一以後要呢」「這樣比較專業」「先留著彈性」——而不是眼前的故事——那它多半是投機性的結構。

⚖️ Reference Design

辨識訊號 — 這些理由都是紅旗
  • 未來防備(future-proofing):「萬一以後需要呢?」——預留的擴充點多半猜錯形狀。
  • 展現專業:加泛化型別來「秀技術」,實際需求不存在。
  • list-like 階層:每層只有一個子型別、沒有分歧——階層在假裝有變化。
  • 為瑣碎資料建類別 / 常數介面enum 已能表達卻硬開一個類別(Unnecessary Abstraction)。
解法:collapse 掉推測性結構,回到最簡方案
// 移除推測性的中介型別(collapse hierarchy),需求出現時再長出來
interface Report { fun render(): String }
class HtmlReport : Report { override fun render() = "<html>…</html>" }
// 真的要支援 PDF/RTF 時,那時的需求會告訴你正確的抽象長相
  • YAGNI:不為想像中的需求預留型別;套 collapse hierarchy 移掉只有單一子型別的中介層。
  • 這與 OCP 的「上當一次」互補:別預測變更方向,等第一個真實變更出現,再引入剛好夠用的抽象。
  • 「抵抗過早抽象」與「善用抽象」同等重要——過度設計是前者失守。

🔑 Takeaways

✍️ My Notes

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

📖 Further Reading