iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
Software Development

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

Day 13:什麼是壞味道(Code Smell)?——高耦合與義大利麵程式碼的形成原因

  • 分享至 

  • xImage
  •  

前兩天我們處理的是資料本身的正確性——操作順序不能亂、送進來的內容不能假。從今天開始進入系列的第三階段,視角要往上拉一層:不再看「這筆資料對不對」,而是看「程式碼的結構健不健康」。

在軟體開發的過程中,程式碼能「跑起來」往往只是基本要求。隨著專案規模持續擴大、需求不斷變更,程式碼很容易累積出一些潛在的問題,這些隱含的警訊在業界被稱為「程式碼壞味道(Code Smell)」。壞味道雖然不代表程式完全故障或無法運行,但它預示著系統的維護成本正在攀升,未來更容易引發臭蟲(Bug)。其中,最經典且最具破壞力的壞味道之一,便是「高耦合(High Coupling)」所導致的「義大利麵程式碼(Spaghetti Code)」。

一、什麼是程式碼壞味道(Code Smell)?

定義:程式碼壞味道是指原始碼中任何可能暗示深層設計問題的特徵。如同冰箱裡傳出的異味是在提醒食物可能壞了,程式碼的壞味道則在警告開發者:此處的結構需要進行重構(Refactoring)。

目的:透過及早識別這些結構上的瑕疵,防止系統隨著時間推移而陷入無法維護的泥沼,確保程式碼的可讀性與擴充性。

常見的壞味道特徵:

  1. 長方法(Long Method):函式過長,包含過多不相干的邏輯。
  2. 巨大類別(God Class):一個類別包辦了所有業務邏輯,違反單一職責原則。
  3. 程式碼重複(Duplicated Code):相同或相似的邏輯散落各處,修改時容易遺漏。

二、高耦合與義大利麵程式碼的形成

定義:高耦合是指系統中的模組、類別或函式彼此過度依賴,導致「動一髮而牽全身」;而義大利麵程式碼則是這種混亂依賴所形成的產物,如同糾結不清的麵條般難以追蹤控制流程。

形成的主要原因:

  1. 缺乏模組化設計:在時間壓力下不斷堆疊快速修補(Quick Fixes),未妥善劃分元件邊界。
  2. 過度依賴全域狀態:資料與函式任意存取,導致元件之間的相依關係變得錯綜複雜——這正是 Day 9 提過的 Global Store 沒被紀律地管理時會出現的反效果:同一個工具,用得有紀律是解方,用得沒紀律就成了高耦合的溫床。
  3. 雙向依賴(Bidirectional Dependency):模組 A 呼叫模組 B,同時模組 B 又回頭呼叫模組 A,形成強烈的耦合束縛。

影響:當程式碼陷入這種狀態,開發者將花費大量時間在理解混亂的邏輯而非實現新功能,大幅降低團隊的生產力。

三、實務案例:代購 App

以開發代購 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 才發現,同一個技術決定可以是解方也可以是壞味道的源頭,差別只在有沒有紀律地管理——這種「工具本身中立,用法決定好壞」的體悟,比記住幾個壞味道的名稱更有收穫。


上一篇
Day 12:資料驗證與防禦性設計——前端資料過濾、型別邊界(Type Boundaries)與防呆
系列文
文科生的軟體工程啟蒙:用一個代購 App,看懂 30 個系統設計觀念 共 13 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言