六邊形架構設計
分層架構是運用最為廣泛的架構模式,把一個軟體系統進行分層,是我們目前做工程專案的一個共識,我們最初學習的分層架構就是經典的三層架構了。它自頂向下分成三層:
- 使用者介面層(User Interface Layer)
- 業務邏輯層(Business Logic Layer)
- 資料訪問層(Data Access Layer)
在傳統的單體應用中,因為業務不算複雜,這種分層並沒有什麼問題,把資料的渲染交給使用者介面層,把核心業務邏輯放到業務邏輯層,然後將資料庫的訪問交給資料訪問層。
但是隨著業務越來越複雜,問題也隨之而來:
- 需要依賴的基礎設施也不僅僅只有資料庫這樣單一了
- 很多引數的校驗,我們開始糾結是放到使用者介面層還是業務層。
- 快取是放到哪裡去控制
......
程式碼開始變得複雜,很快只有上帝能看懂了,然後寫程式碼往往就是牽一髮而動全身。
我們都知道在設計模式中有一個很重要的原則就是 依賴倒置 ,他包含了三層含義:
- 高層模組不應該依賴低層模組,兩者都應該依賴其抽象
- 抽象不應該依賴細節
- 細節應該依賴抽象
所以設計模式中產生了一個模式—— 介面卡模式 :
將一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠在一起工作。
在中介軟體軟體爆發的今天,同一種功能的中介軟體可能會有非常多的選擇。比如:
- MQ: RabbitMQ, Kafka, ActiveMQ, RocketMQ......
- SQL: MySQL, PostgreSQL......
- NoSQL: Redis,MongoDB, ElasticSearch......
- Job: Elastic-Job, XXL-JOB.....
......
除此之外還有各種供應商的需要有備用通道:簡訊,郵件,推送,業務供應商......
如果我們在業務邏輯中去關注這些東西,毫無疑問,我們的業務邏輯就會很繁瑣:
if ( config == 'A' ) { // statement 1 } else if ( config == 'B' ) { // statement 2 } else if ( config == 'C' ) { // statement 3 } else if ( config == 'D' ) { // statement 4 } else { // default statement }
特別是業務中去選擇供應商的時候,我們通常是要有好幾個備用通道的,但是我們的業務邏輯本身只是關心:這件事做了沒,而不是到底用哪種方式去做。
所以六邊形架構被提出了。六邊形架構提倡用一種新的視角來看待整個系統,該架構中存在兩個區域,分別是“外部區域”和“內部區域”。在外部區域中,不同的客戶均可以提交輸入;而內部的系統則用於獲取持久化資料,並對程式輸出進行儲存(比如資料庫),或者在中途將輸出轉發到另外的地方(比如訊息)。
我們在設計系統的時候,往往過於關注資料庫,Http介面等基礎設施的設計,而忽略了我們需要關注的業務。在複雜系統中,最容易變化的也是業務形態,產品經常會要求改來改去,因為業務本身就在不斷地演進,如果我們一開始就基於資料庫作所有的設計,那麼勢必一旦遇上業務的修改,庫表肯定也需要對應先進行變化。假如我們融入六邊形架構,將資料庫和暴露的Controller都視為是基礎設施,先去關注業務的模型和程式碼,Class的修改比要資料庫改起來要簡單的多。另外一方面,也大大提高了程式的可測試性:在沒有準備一堆基礎設施(資料庫,介面,非同步通知等等)情況下,可以先測試邏輯的完整性。
另外,有時候隨著業務增長有的基礎設施是會需要進行替換的,採用六邊形架構之後,這種更換的成本就會降低。另外如果出現需要使用Web Service的客戶,我們也不必糾結於之前的HTTP介面,直接開出一套新的協議程式碼供客戶使用,而不會糾結領域部分程式碼有邏輯上的缺失。
採用六邊形架構之後,我們的領域模型也會更加獨立,更精簡,在適應新的需求時修改也會更容易。