回顧mvc、介紹MVC在現代後端開發中的常見困境及說明六角形架構如何解決這些問題
回顧經典 MVC
在經典的 MVC 模式中,三個元件的職責是:
-
Model (模型)
代表資料和業務邏輯。負責與資料庫互動,並提供資料給 View。
-
View (視圖)
使用者介面。在傳統 Web 應用中,它負責將 Model 的資料渲染成 HTML。
-
Controller (控制器)
接收使用者的 HTTP 請求,呼叫 Model 來更新狀態,並選擇一個 View 來產生回應。
MVC 在現代後端開發中的常見困境
隨著業務變複雜,許多遵循 MVC 模式的專案會不自覺地陷入以下困境:
-
臃腫的控制器 (Fat Controllers)
大量的業務邏輯,因為無處安放,最終都被塞進了 Controller 的方法中。Controller 不僅要處理 HTTP 請求和回應,還要負責資料驗證、流程編排、呼叫多個 Model。這使得 Controller 變得極其臃腫,難以測試和維護。當 Controller 變得過於龐大時,任何小的需求變動都可能牽一髮動全身,導致維護成本大幅提升。
-
貧血的模型 (Anemic Models):
與此同時,Model 逐漸退化成一個只有 Getters/Setters 的「資料袋」,所有的業務邏輯都被抽離到 Controller 或某些
Service層中,完全違背了物件導向中「資料與操作相結合」的初衷。這種設計讓 Model 失去了主動性,導致業務規則分散在各處,降低了程式碼的可讀性與一致性。 -
以資料庫為中心:
在許多 MVC 框架中(特別是 ActiveRecord 風格的),Model 與資料庫的表結構是緊緊綁定的。這導致整個應用的設計都圍繞著資料庫 schema 展開,業務邏輯隱性地依賴於資料庫的實作細節。這使得「脫離資料庫來測試業務邏輯」變得異常困難。當我們想要替換資料庫或進行單元測試時,往往會發現業務邏輯與資料存取層糾纏不清。
六角形架構如何解決這些問題
我們的專案所採用的六角形架構,正是為了解決上述問題而設計的。
-
針對臃腫的控制器
我們的
Controller極其輕薄。它的唯一職責是「翻譯」HTTP 請求,然後委派給Usecase。所有的業務流程都在Usecase中,職責清晰。這樣的設計讓Controller易於維護與測試,並且能專注於協調請求與回應。 -
針對貧血的模型
我們的
Domain層是「充血」的。User物件不僅有資料,更有保護其內部一致性的驗證邏輯和業務方法。它是應用程式中真正「聰明」的部分。這種設計讓業務規則集中於Domain物件,提升了程式碼的可讀性、可維護性與一致性。 -
針對以資料庫為中心
這是兩者最本質的區別。在我們的架構中,業務領域(Domain)才是宇宙的中心,而不是資料庫。資料庫只是一個可以被隨時替換的「基礎設施」,是一個被動實現了
Repository介面的「Adapter」。依賴倒轉原則確保了我們的核心業務邏輯對 GORM、對 MySQL 一無所知。這讓我們能夠輕鬆地替換資料存取技術,或在測試時使用記憶體資料庫模擬,極大提升了系統的彈性與可測試性。
思考的轉變:從「分層」到「內外之分」
從 MVC 到六角形架構,最核心的是思維模式的轉變:
-
MVC 的心智模型是「水平分層」
- UI 層 -> 業務層 -> 資料層。
- 資料流從上到下,像一個三層蛋糕。
- 這種分層方式雖然直觀,但容易讓業務邏輯與技術細節混雜,導致層與層之間的界線模糊。
-
六角形架構的心智模型是「內外之分」
- 核心是「內部」(Domain, Usecase),其他一切(HTTP, Database, Redis, …)都是「外部」。
- 依賴的箭頭永遠從「外部」指向「內部」。
- 這種設計強調「業務邏輯」與「技術細節」的徹底分離,讓核心邏輯不受外部變動影響。