軟體設計很難。第一個冒出來的點子,幾乎不可能是最佳設計。
對每個重要設計決策,考慮多個選項——這就是「設計兩次」。
範例:GUI 編輯器的文字類別#
設計類別介面時,別停在第一個點子,至少考慮幾個替代方案:
| 選項 | 介面風格 |
|---|---|
| 行導向 | 整行的插入、修改、刪除 |
| 字元導向 | 個別字元的插入、刪除 |
| 字串導向(範圍) | 任意範圍的字元(可跨行) |
不需要把每個方案的所有細節釘死——只需草擬幾個最重要的方法。
替代方案要「差異夠大」#
盡量挑差異很大的方案,學到的東西最多。
即使你確信只有一條合理路線,也至少考慮第二個設計——再爛都好。
思考爛設計的弱點、再對比好設計的優點,本身就極具教育意義。
列出每個方案的優劣#
設計介面最重要的考量:對上層程式碼是否易用。
例如文字類別案例:
- 行導向 → 上層需要為跨行 / 部分行操作做拆行 / 合行
- 字元導向 → 多字元操作得用迴圈
其他可考慮的因素:
- 哪個方案的介面更簡單?
- 哪個方案更通用?
- 哪個方案能讓實作更高效?
- 文字案例中,字元導向可能顯著較慢(每個字元都要呼叫一次文字模組)
可能的最佳解:把多個方案的優點合起來#
比較完替代方案後,最佳設計可能是:
- 其中之一
- 或一個結合多個方案優點的新設計
如果所有方案都不夠好——
- 再生出新方案
- 拿原方案的問題當線索:例如行 / 字元兩個方案都讓上層得做額外文字操作 → 紅旗,提示介面應該與上層的真實操作對齊 → 這個推理過程會把你導向「範圍導向」API
多層次的應用#
「設計兩次」可以套用到系統的許多層級:
- 模組介面(如上)
- 模組實作:對文字類別可考慮「行的 linked list」、「固定大小字元 block」、「gap buffer」等
- 介面與實作的目標不同:實作最看重簡潔與效能
- 高層次:UI 功能、系統主要模組的拆解
每個層級都同樣的判斷:能比較幾個方案,就比較容易看出最佳路徑。
時間成本#
「設計兩次」並不需要很多額外時間。
- 小模組(class):考慮替代方案大概一兩個小時
- 相較於後續實作的好幾天 / 好幾週,這只是一小部分
- 初步設計實驗多半能換到顯著更好的設計,回收成本綽綽有餘
更大的模組?實作時間更長,好設計帶來的好處也更高。
為什麼聰明人特別難接受#
作者觀察:「設計兩次」對非常聰明的人特別難接受。
成長過程中,他們發現「第一個直覺」就足以拿好成績;不需要第二、第三個方案。但問題是:
- 隨著職涯推進,他們進入更困難的問題場域
- 終究有一天,第一個點子不再夠好
- 大型軟體系統就是這類問題:沒有人能一次就做對
但作者經常看到聰明人堅持實作第一個點子,從而讓他們的真實潛力被低估(也讓人很難與他們合作)。
也許他們潛意識相信「聰明人應該一次就做對;嘗試多種設計就代表不聰明」——這是錯的。
不是你不夠聰明,而是問題真的很難。
這是好事:思考困難的問題比解 trivial 問題有趣得多。
額外好處:磨練設計技藝#
「設計兩次」不只改善這次的設計,還會持續改善你的設計能力。
比較多種方案的過程會教你:什麼讓設計變好、什麼讓設計變糟。久而久之,你會更快剔除壞設計、鎖定真正好的設計。