在軟體設計領域裡,我們經常聽到一句話:「高內聚、低耦合」是良好架構的黃金法則。這句話的核心意涵就是:如果一個系統的模組設計具有高度內聚性,並且模組間耦合度低,那麼這個系統會比較容易維護、比較容易擴展,長期下來也會展現更高的結構穩定性。
而在微服務架構中,這個原則更是放大來看。因為微服務的本質就是「以獨立服務」來分解系統,每個服務各自承擔一塊業務責任。如果我們在設計過程中沒有處理好「耦合」的議題,那麼微服務只會淪為「分散式的單體」,反而增加系統的複雜度,帶來更高的維運成本。
「耦合」(Coupling)指的是兩個元件或模組之間相互依賴的程度。耦合度越高,代表它們的行為、資料、甚至生命週期被綁得越緊,任何一方的變動都可能影響到另一方。
「解耦」(Decoupling)則是設計上的一種追求,目的在於減少這種相互依賴,讓系統能有更好的彈性。
在實務中,耦合不是非黑即白,而是存在光譜。我們追求的不是「零耦合」(那在現實世界幾乎不可能),而是「鬆散耦合」(Loose Coupling),讓服務之間能透過明確、穩定的介面互動,而不去干擾彼此的內部實作。
微服務架構強調:一個應用程式應該依據業務能力(Business Capability)拆解為不同的獨立服務,每個服務獨立部署,並能透過 API 或事件進行協同合作。也就是說,單一服務無法完成所有業務需求,必須與其他服務互動,才能完成完整的工作流程。
例如:在一個電商平台中,「訂單服務」需要與「庫存服務」協作來保留庫存,也要與「支付服務」協作來完成收款。這些互動就牽涉到「耦合」的議題。
在 《Building Microservices》 中,Sam Newman 將服務之間的耦合分成四種主要型態,從鬆散到緊密排列如下:
不同服務之間需要彼此協作來完成業務需求,但互動聚焦於「介面」(Interface),而不是「內部實作」。
訂單服務下單時,需要呼叫庫存服務來「保留庫存」。這時候訂單服務只需要透過 API 向庫存服務發送「保留請求」,並不需要知道庫存服務內部如何管理商品數量。
當一個服務需要將外部請求的資料直接轉交或轉換,傳遞到其他服務。
訂單服務在處理訂單時,除了需要庫存資訊外,還要帶上「發貨資料」傳遞到物流服務。此時訂單服務扮演「直通」的角色,成為中介管道。
兩個或多個服務直接共用同一份資料來源,例如同一個資料庫。
訂單服務與庫存服務共用一個資料庫表單,彼此直接讀取同一份庫存資料。
服務直接存取或修改其他服務內部的資料表或資料結構。
庫存服務直接寫入訂單服務的資料庫,以便更新訂單狀態。換言之,服務之間「跨越了邊界」,直接操作他人內部資料。
而上述四種耦合,如果一定要出現,建議順序如下:
回到設計原則,如果我們能讓每個服務的內部職責「內聚」(高內聚),並且在服務之間保持最小化的依賴(低耦合),那麼整體系統將會具有以下特性:
為了完成高內聚、低耦合的設計,「封裝」以及「明確的介面」是重要的關鍵,這就不免需要回顧「資訊隱藏」與「服務拆分」的議題。
在微服務架構中,耦合是無法避免的,但我們可以透過設計讓耦合「健康」存在。
最終,我們才能建立一個 高內聚、低耦合 的微服務架構,真正達到敏捷、可擴展、可持續演進的目標。