iT邦幫忙

2026 iThome 鐵人賽

DAY 29
0
Software Development

文科生的軟體工程啟蒙:用一個代購 App,看懂 30 個系統設計觀念系列 第 29 篇

Day 29:系統設計反思(Post-Mortem)——架構權衡(Trade-offs)沒有銀彈,只有適合的取捨

  • 分享至 

  • xImage
  •  

Day 28 談到,AI 擅長生成程式碼細節,但做判斷、做取捨的工作仍然落在人身上。今天是系列倒數第二篇,想換個方式收尾:借用工程團隊在事故之後會做的「事後檢討(Post-Mortem)」,不是檢討誰犯了錯,而是回頭檢視這 30 天裡每一個設計決定背後的取捨。Google 的 SRE 團隊有個原則叫「無究責(Blameless)」:重點是找出系統哪裡有缺口,而不是追究個人,因為「你修不好人,但可以修好系統」。我想用同樣的態度,回頭看這個系列的設計。

一、本質複雜度 vs. 附帶複雜度

電腦科學家 Fred Brooks 在經典論文〈No Silver Bullet〉裡,把軟體的複雜度分成兩種。**附帶複雜度(Accidental Complexity)**是工程師自己製造、也能靠更好的工具或方法解決的困難,例如早期的組合語言,被高階語言取代後大幅減少。**本質複雜度(Essential Complexity)**則是問題本身固有的複雜度:如果使用者真的需要 30 個功能,這些需求不會因為換了新框架就消失。

Brooks 的結論是:沒有任何單一技術,能讓軟體生產力在十年內提升一個數量級,因為大部分困難來自本質複雜度。這個論點放在 Day 28 的脈絡很有意思:AI 確實大幅降低了附帶複雜度(寫程式碼變快了),但「這個系統到底該做什麼、該怎麼取捨」仍然是本質複雜度,AI 並沒有讓它消失。

二、架構的第一定律:一切都是取捨

架構領域的書籍《Fundamentals of Software Architecture》把這件事寫成第一定律:軟體架構裡的一切都是取捨(Everything in software architecture is a trade-off)。沒有哪個設計選擇放諸四海皆好或皆壞,每個選擇都要放回系統的目標與限制裡評估。常見的例子包括:單體架構因為網路呼叫少而效能較好,微服務則比較容易擴展,這是效能與擴展性的取捨;關聯式資料庫結構單純,NoSQL 更有彈性但要接受最終一致性,這是簡單與彈性的取捨;多重驗證讓帳號更安全,卻增加登入的麻煩,這是安全與易用的取捨。

三、用 ADR 記下「為什麼」

既然沒有標準答案,那「當初為什麼這樣選」就比「選了什麼」更值得留下紀錄。業界的做法是架構決策紀錄(Architectural Decision Record,簡稱 ADR):每一則紀錄只記一個重要的架構決策,寫下決策的理由、取捨與後果,累積起來就是專案的「決策日誌」,讓日後接手的人看得懂系統為什麼長這個樣子。

四、回顧這 30 天的取捨

回頭看,這個系列其實反覆出現「沒有最佳解,只有取捨」的時刻:

  • Day 15 的 SRP:職責單一讓每個模組好測試、好替換,但拆得太細,追蹤一個完整流程就要跳過很多檔案,是「單一職責」與「理解成本」的取捨。
  • Day 6 的正規化資料:用 byId 結構避免資料重複,查找也快,但某些畫面需要多一層組裝,是「一致性」與「查詢便利」的取捨。
  • Day 10 的快取:讀取更快,卻有資料與資料庫不同步的風險,是「效能」與「新鮮度」的取捨。
  • Day 27 的分片:撐得住更大的資料量,但跨分片查詢變複雜,是「規模」與「簡單」的取捨。

五、代購 App 案例:一則 ADR

以 Day 7 的 SSOT 為例:訂單總金額要即時計算,還是存成一個固定欄位?即時計算能確保只有一份真相,但每次查詢都要重算;存固定欄位查詢快,卻要面對「商品單價改了,舊訂單要不要跟著變」的問題。把這個決定寫成 ADR,大概長這樣:

# ADR-001:訂單總金額要即時計算還是儲存?

## 背景
訂單列表每頁要顯示 50 筆訂單的總金額;商品單價可能被代購業者調整。

## 決策
訂單建立時,將「下單當下的總金額」存入 orders.total,不再隨商品單價變動。

## 理由與取捨
- 歷史訂單金額應該等於買家當時實際付的錢,所以這個值不屬於「衍生資料」。
- 代價:orders.total 與商品單價可能不一致,需在文件中明確標示它是快照。

## 後果
若未來要做「改價後補差額」功能,需要另外設計調整紀錄,不能直接改 total。

注意:這個決定看起來跟 Day 7 的「衍生資料不要另外儲存」好像矛盾,但關鍵在於「歷史訂單的金額」本來就是當時的事實,而不是從單價推導出來的結果。同一個原則,放在不同的業務前提下,會得到不同的結論,這正是取捨的意思。

六、無究責回顧:這個系列哪裡可以更好

事後檢討的價值,在於誠實面對限制。這個系列裡每個原則的結論,都有它成立的前提:Day 27 的索引、複製、分片、佇列,是業界常見的做法,但真正採用之前,仍需要拿實際的資料量與流量去驗證,不是看到「資料變 100 倍」就一股腦全部導入。反過來說,當我說某個原則「划算」時,也該問自己:它在什麼情境下不划算?例如一支只有三十行的小工具腳本,硬把它拆成表現層、邏輯層、資料層,就是過度設計。能說出一個原則的適用條件,也能說出它的失效條件,才算真正理解它。

七、結論

前面提及No Silver Bullet 說的不是「所有技術都沒用」,而是提醒我們:軟體設計的大部分困難,來自問題本身,而不是工具不夠好。所以這 30 天學到的每個原則,與其說是該怎麼做的標準答案,不如說是在什麼條件下,這個取捨划算,跟經濟學一的核心一樣。所以真正該養成的習慣,是每做一個決定,就把理由與代價寫下來。


上一篇
Day 28:AI 時代的架構師思維——當程式碼能自動生成,人類工程師的核心價值在哪?
系列文
文科生的軟體工程啟蒙:用一個代購 App,看懂 30 個系統設計觀念 共 29 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言