11.端口和適配器架構(譯)

原文:https://herbertograca.com/2017/09/14/ports-adapters-architecture/

這篇文章是軟件架構編年史()的一部分,這部編年史由一系列關于軟件架構的文章組成。在這一系列文章中,我將寫下我對軟件架構的學習和思考,以及我是如何運用這些知識的。如果你閱讀了這個系列中之前的文章,本篇文章的的內容將更有意義。

2005年,Alistair Cockburn構思了端口和適配器架構 (又稱六邊形架構)并記錄在他的博客中。下面這句話就是他對該架構的目標的定義:

讓用戶、程序、自動化測試和批處理腳本可以平等地驅動應用,讓應用的開發和測試可以獨立于其最終運行的設備和數據庫?!狝listair Cockburn 2005,端口和適配器

有許多文章在談及端口和適配器架構時會花很多篇幅在分層上。然而, 我并沒有在 Alistair Cockburn 的原文中找到關于分層的只言片語。

其思想是將我們的應用看作是一個系統的中心交付物,輸入和輸出都是通過端口出入應用,這些端口將應用和外部工具、技術以及傳達機制隔離開來。應用不應該關心是誰在發送輸入或接收輸出。這就是為了保護產品免受技術和業務需求演進的影響。由于技術/供應商鎖定,這些演進可能導致產品剛開發沒多久就被廢棄。

我將在本文中剖析以下主題:

  • 傳統架構方式的問題
  • 分層架構的演化
    • 什么是端口?
    • 什么是適配器?
    • 適配器的兩種不同類型
  • 端口和適配器架構有哪些優勢?
    • 實現隔離和技術隔離
    • 傳達機制的隔離
    • 測試
  • 總結

傳統架構方式的問題

傳統的架構方式在前端和后端都可能給我們帶來問題。

在前端,業務邏輯最終可能會滲透到 UI(例如,我們把用例的邏輯放到控制器或視圖里,導致這些邏輯不能在其它 UI 界面中重用), 甚至 UI 會反過來滲透到業務邏輯中(例如,我們會為了模板中需要的業務邏輯在實體中創建對應的方法)。

而在后端,我們可能會在自己的業務邏輯里使用外部類的類型提示、繼承或者實例化它們,這會導致對這些外部的庫和技術直接引用,最后任由它們滲透到業務邏輯中。

分層架構的演化

EBI ()和DDD()的福, 2005 年我們已經知道了“系統中真正重要的是位于中間的層次”。業務邏輯(應該)存在于這些層次之中,它們才是我們和競品的真正區別。這才是真正的“應用”。


但是,Alistair Cockburn 意識到 頂部和底部的層次從另一方面來說,就是應用的入口/出口。盡管實際中它們不一樣,卻有著十分相似的目標,在設計上也是對稱的。而且,如果我們想要隔離出應用中間的層次,這些入口和出口能以另一種相似的方式使用。

區別于典型的分層架構圖,我們將它們畫在系統的左右兩側,而不是上下兩邊。

雖然我們識別出了系統中對稱的兩側,但兩側都可能有若干入口/出口。例如, API和UI就是位于應用左側的兩個不同的入口/出口。為了表示應用有若干個入口/出口,我們把應用的形狀改成了多邊形。應用的形狀可以是有多條邊的任意多邊形,但最終六邊形獲得了青睞。這也是“六邊形架構”的由來。

端口和適配器架構使用了實現為端口和適配器的抽象層次,解決了傳統架構方式帶來的問題。

什么是端口?

端口是對其消費者無感知的進入/離開應用的入口和出口。在許多編程語言里,端口就是接口。例如,在搜索引擎里它可能是執行搜索的接口。在應用中,我們把這個接口當成入口/出口使用,而不用去關心它的具體實現,實際上在所有將接口定義為類型提示的地方,這些實現會被注入。

什么是適配器?

適配器是將一個接口轉換(適配)成另一個接口的類。

例如,一個適配器實現了接口 A 并被注入了接口 B。當這個適配器被實例化時,一個實現了接口B的對象將從構造方法注入進來。實現了接口 A 的 對象會被注入到需要接口A的地方,然后接收方法請求,將其轉換并代理給那個實現了接口B的內部對象。

如果我說的不夠明白,別慌,后面我會給出一個更具體的例子。

適配器的兩種不同類型

左側代表 UI 的適配器被稱為主適配器或者主動適配器,因為是它們發起了對應用的一些操作。而右側表示和后端工具鏈接的適配器,被稱為從適配器或者被動適配器,因為它們只會對主適配器的操作作出響應。

端口/適配器的用法也有一點區別:

  • 左側,適配器依賴端口,該端口的具體實現會被注入到適配器,這個實現包含了用例。換句話說,端口和它的具體實現(用例)都在應用內部。
  • 右側,適配器就是端口的具體實現,它自己將被注入到我們的業務邏輯中,盡管業務邏輯只知道接口。換句話說,端口在應用內部,而它的具體實現在應用之外并包裝了某個外部工具。

端口和適配器架構有哪些優勢?

使用這種應用位于系統中心的端口/適配器設計,讓我們可以保持應用和實現細節之間的隔離,這些實現細節包括曇花一現的技術、工具和傳達機制。它還讓可重用的概念更容易更快速地得到驗證并被創建出來。

實現隔離和技術隔離

上下文

我們的應用使用SOLR作為搜索引擎,并使用一個開源庫連接它并執行搜索。

傳統架構方式

傳統架構方式下,我們會直接在我們的代碼中使用庫(SOLR)里的類,作為類型提示,或者實例化和/或作為我們實現的基類。

端口和適配器架構方式

如果采用端口和適配器架構的話,我們會創建一個接口,比如叫做 UserSearchInterface,在代碼中用這個接口作為類型提示。我們還會為 SOLR 創建一個實現該接口的適配器,比如叫做 UserSearchSolrAdapter。這個實現是 SOLR 的包裝,SOLR 會被注入其中并用來實現接口指定的方法。

問題

不久之后,我們想用Elasticsearch換掉SOLR。甚至,對于同樣的搜索行為,我們希望有些時候使用SOLR,有些時候使用Elasticsearch,在運行時決定就好。

如果我們采用傳統架構,我們需要查找所有使用SOLR的代碼并替換成Elasticsearch。然而,這可不是簡單的查找替換:兩個引擎的用法不同,方法、輸入、輸出也不盡相同,替換并不是一件輕松的任務。而在運行時在決定使用那個引擎甚至是不可能的。

然而,假設我們使用了端口和適配器架構,我們只需要創建一個新的適配器,比如就叫UserSearchElasticsearchAdapter,在注入時使用它換掉SOLR的適配器,也許改一下DCI中的配置就可以做到。我們完全可以使用工廠來決定注入那個適配器,實現在運行時注入不同的實現。

傳達機制的隔離

和上面這個例子類似,假設我們的應用需要 Web GUI,CLI 和 Web API。我們想在全部三種 UI 中提供某個功能,比如叫做UserProfileUpdate的功能。

使用端口和適配器架構的話,我們會在一個應用服務的方法中實現這個功能并將其作為一個用例。服務會實現一個接口,該接口說明了方法、輸入以及輸出。

每個版本的 UI 都有各自的控制器(或控制臺命令)來通過這個接口觸發期望的邏輯,應用服務接口的具體實現會被注入到 UI 中。這種情況下,適配器實際上就是控制器(或 CLI 命令)。

之后我們可以修改 UI,因為我們知道這些修改不會影響業務邏輯。

測試

上面兩個例子中,使用端口和適配器架構會讓測試更加容易。第一個例子中,我們用接口(端口)的 Mock 就可以測試應用,而不需要使用 SOLR 或 Elasticsearch 。

第二個例子中,所有的 UI 都可以獨立于應用進行測試。我們的用例也可以獨立于 UI 進行測試,傳給服務一些輸入再斷言結果就好。

總結

在我看來,端口和適配器架構只有一個目標:將業務邏輯和系統使用的傳達機制以及工具隔離。為此,它使用了常見的編程語言結構:接口

UI側(主動適配器),我們創建使用應用接口的適配器,比如控制器。
基礎設施側(被動適配器),我們創建實現應用接口的適配器,比如資源庫。

這就是全部!

然而,我驚訝的發現早在十三年前同樣的思想就已經公開發表了(),盡管它沒有刻意地強調要將工具和傳達機制從應用核心中隔離出來。

系統和角色的任何交互都要通過邊界對象。按照 Jacobson 的描述,角色可以是客戶或者管理員(操作員)這樣的人類用戶,也可以是定時器或者打印機這樣的非人類“用戶”,它們分別對應著端口和適配器架構中的主動適配器被動適配器。

引用來源

1992 – Ivar Jacobson – Object-Oriented Software Engineering: A use case driven approach
200? – Alistair Cockburn – Hexagonal Architecture
2005 – Alistair Cockburn – Ports and Adapters
2012 – Benjamin Eberlei – OOP Business Applications: Entity, Boundary, Interactor
2014 – Fideloper – Hexagonal Architecture
2014 – Philip Brown – What is Hexagonal Architecture?
2014 – Jan Stenberg – Exploring the Hexagonal Architecture
2017 – Grzegorz Ziemoński – Hexagonal Architecture Is Powerful
2017 – Shamik Mitra – Hello, Hexagonal Architecture

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,786評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,656評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,697評論 0 379
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,098評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,855評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,254評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,322評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,473評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,014評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,833評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,016評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,568評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,273評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,680評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,946評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,730評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,006評論 2 374

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,787評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,666評論 25 708
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,792評論 2 59
  • 一個肥胖的渾身臟兮兮的女人,胡亂穿了幾層色彩鮮艷的衣服,黑色的頭發像瘋長的野草似的拱滿了灰塵。 她出門不是來醫院...
    豌豆P閱讀 137評論 0 0
  • 差單反,破鏡頭,但是我愛生活……
    老陶有故事閱讀 288評論 1 3