前兩天我們處理的是資料本身的正確性——操作順序不能亂、送進來的內容不能假。從今天開始進入系列的第三階段,視角要往上拉一層:不再看「這筆資料對不對」,而是看「程式碼的結構健不健康」。
在軟體開發的過程中,程式碼能「跑起來」往往只是基本要求。隨著專案規模持續擴大、需求不斷變更,程式碼很容易累積出一些潛在的問題,這些隱含的警訊在業界被稱為「程式碼壞味道(Code Smell)」。壞味道雖然不代表程式完全故障或無法運行,但它預示著系統的維護成本正在攀升,未來更容易引發臭蟲(Bug)。其中,最經典且最具破壞力的壞味道之一,便是「高耦合(High Coupling)」所導致的「義大利麵程式碼(Spaghetti Code)」。
定義:程式碼壞味道是指原始碼中任何可能暗示深層設計問題的特徵。如同冰箱裡傳出的異味是在提醒食物可能壞了,程式碼的壞味道則在警告開發者:此處的結構需要進行重構(Refactoring)。
目的:透過及早識別這些結構上的瑕疵,防止系統隨著時間推移而陷入無法維護的泥沼,確保程式碼的可讀性與擴充性。
常見的壞味道特徵:
定義:高耦合是指系統中的模組、類別或函式彼此過度依賴,導致「動一髮而牽全身」;而義大利麵程式碼則是這種混亂依賴所形成的產物,如同糾結不清的麵條般難以追蹤控制流程。
形成的主要原因:
影響:當程式碼陷入這種狀態,開發者將花費大量時間在理解混亂的邏輯而非實現新功能,大幅降低團隊的生產力。
以開發代購 App 為例,若缺乏良好的架構約束:
問題情境:開發初期為了趕進度,工程師將「商品抓取」、「訂單計算」、「Line 訊息通知」以及「資料庫連線」全部寫在同一個函式裡:
// 義大利麵程式碼:一個函式做了四件不相干的事,還互相纏繞
async function processOrder(order) {
const item = await fetchProduct(order.itemId); // 商品抓取
const total = item.price * order.qty + order.shippingFee; // 訂單計算
await db.query(`UPDATE orders SET total = ${total} WHERE id = ${order.id}`); // 資料庫連線
await lineNotify(order.buyerId, `您的訂單總額為 ${total} 元`); // Line 通知
// 哪天要改運費算法,得在這個函式裡動刀,一不小心就connect到通知的訊息格式
}
壞味道的展現:當代購業者想要修改「運費計算規則」時,竟然不小心影響到了「Line 訊息通知」的發送邏輯,甚至造成資料庫連線中斷。這是因為各個功能模組之間產生了極高的耦合,彼此緊密糾纏,導致修改一處就會在全系統引發非預期的連鎖反應。
改善方向:透過重構來降低耦合度,明確劃分各模組的單一職責,例如將通知邏輯獨立為 Notification 模組、運費計算獨立為 PricingService,讓程式碼重新恢復清晰易讀的結構——這正是接下來 Day 15 要正式介紹的單一職責原則。
壞味道與義大利麵程式碼是軟體開發中常見的技術債。如果放任不管,隨著功能擴充,系統將變得極其脆弱且難以維護。透過持續的程式碼檢視、建立清晰的模組邊界以及落實重構,開發團隊才能有效化解高耦合帶來的危機,確保軟體專案的健康與長遠的可維護性。回頭看 Day 9 提過的 Global Store 才發現,同一個技術決定可以是解方也可以是壞味道的源頭,差別只在有沒有紀律地管理——這種「工具本身中立,用法決定好壞」的體悟,比記住幾個壞味道的名稱更有收穫。