昨天我們看到高耦合怎麼把程式碼纏成一團麻——商品抓取、訂單計算、通知、資料庫連線全擠在同一個函式裡,改一處就牽動全部。今天要談的分層架構,就是預防這件事發生的具體做法:把不同職責放進不同的層,讓耦合沒有機會在同一個地方發生。
分層架構是軟體設計中最常見的架構模式之一。它將應用程式組織成不同的邏輯層,每個層級負責特定的任務,並僅與相鄰的層級進行互動。透過落實「關注點分離」(Separation of Concerns)原則,此模式確保了軟體中不同面向(如使用者互動、商業規則與資料儲存)保持獨立,進而提升系統的可理解性、可維護性與可擴展性。
表現層 / 介面層(Presentation Layer)
邏輯層 / 服務層(Business Logic Layer)
資料存取層 / 永續層(Data Access Layer)
把訂單建立這件事,拆進三層看:
// controllers/orderController.js —— 表現層:只負責收請求、回結果
app.post('/orders', async (req, res) => {
const order = await OrderService.createOrder(req.body);
res.json(order);
});
// services/orderService.js —— 邏輯層:商業規則都在這裡
async function createOrder(input) {
if (input.quantity <= 0) throw new Error('數量不合法'); // 驗證
const total = input.price * input.quantity + input.shippingFee; // 計算
return OrderRepository.save({ ...input, total });
}
// repositories/orderRepository.js —— 資料存取層:只跟資料庫講話
async function save(order) {
return db.query('INSERT INTO orders (buyer_id, total) VALUES (?, ?)', [order.buyerId, order.total]);
}
表現層:供海外代購業者與買家使用的手機 App 或網頁介面。當買家在介面上提交新的代購商品需求時,此層負責收集輸入資料並發送請求至邏輯層——它不知道、也不需要知道總金額是怎麼算出來的。
邏輯層:負責處理代購業務流程。收到訂單請求時,驗證訂單資料、計算商品總金額(含國際運費與代購服務費),並處理匯率換算——它不直接碰資料庫,也不管畫面長什麼樣。
資料存取層:透過 ORM 與資料庫進行互動的儲存庫元件。接收來自邏輯層的指令後,安全地執行資料庫查詢,將新訂單寫入資料庫並更新庫存記錄,不直接暴露 SQL 查詢給前端。
哪天要把「運費計算規則」改掉,只需要動 orderService.js 這一個檔案——跟昨天那個一改運費就意外弄壞 Line 通知的義大利麵範例相比,這裡的三個檔案彼此不知道對方內部長什麼樣,改一層不會波及另外兩層。
分層架構透過嚴格分離表現層、邏輯層與資料存取層,為軟體開發提供了一個清晰且具組織性的藍圖。這種設計不僅防止了元件間的緊密耦合,還能讓開發團隊在不影響整個系統的情況下,輕鬆進行特定層級的擴展、維護或技術遷移。拿昨天那個義大利麵範例重新看一次,才發現分層架構要解決的其實不是「程式碼要不要拆檔案」,而是「改一個地方會不會波及另一個地方」——三個檔案分開放,跟三個檔案彼此不知道對方內部長什麼樣,是兩件不同層次的事,後者才是分層真正要保護的東西。