Part 1: API設計和策略前端
軟件系統的複雜性是一個很痛苦的問題,並且沒法避免。Fred Brooks將複雜性描述爲,軟件系統解決業務問題所固有的本質複雜性,以及實施該解決方案所帶來的偶發複雜性。web
隨着與採用「API優先」工程實踐和微服務架構的組織進行更密切的合做,我發現這種描述愈來愈有用。首先,經過這種方式分離複雜性,它容許架構師和工程師專一於最小化系統的偶發複雜性。
與微服務相關的技術創新有很大幫助:容器,自動化工具和API管理平臺。但我真正喜歡這種複雜性劃分的緣由是,它幫助咱們認清一個事實:任何技術都不能下降系統的本質複雜性。編程
「開發軟件產品的許多經典問題源於這種本質的複雜性,其非線性隨着規模的增長而增長。」 – 出自Fred Brooks著《No Silver Bullet—Essence & Accident in Software Engineering》canvas
可是,咱們能作的至少是理解和記錄一個系統的本質複雜性。對於大多數技術人員來講,有效完成這一任務很重要,由於系統的本質複雜性不包括解決方案中使用的底層技術。api
系統本質複雜性定義的本質要素是系統執行的任務和功能,以及執行所需的對象和交互。爲了優化這種定義的認知負荷,將此定義表達爲視覺模型也是很天然的。即便在可視化的狀況下,軟件架構師仍然努力保持模型中的元素不受技術限制,而且保持一致。緩存
Eric Evans的領域驅動設計(Domain-Driven Design ,DDD)方法論突出的緣由是,它提供了一種可視化定義軟件系統本質複雜性的方法。特別是,顯示域,子域,有界上下文及其相互關係的上下文映射,與我見過的以有效方式說明本質複雜性的任何方法都很是接近。 UML意在提供一種用於定義與技術無關的應用程序描述的手段,但它的許多模型天然偏向於面向對象的根源。事實上,若是你深刻DDD工具箱,我認爲你會遇到一樣的偏見。安全
我在定義一個互連微服務系統時,使用了DDD上下文映射的派生。將在將來的文章中詳細介紹這種方法。網絡
爲何理解和記錄軟件系統的本質複雜性很重要,這與微服務有什麼關係?隨着微服務系統的發展和演變,其許多好處來自於服務自己的凝聚力。PhilCalçado在他的博客文章「微服務與分佈式對象的第必定律(Microservices & the First Law of Distributed Objects)」中強調了這一需求。凝聚力是肯定服務邊界的產物,這是模擬系統本質複雜性的必要步驟。架構
有趣的是,與Brooks所描述的複雜性彷佛是矛盾的,微服務系統的技術無關上下文映射在某種程度上與它的實現的拓撲結構是同構的,遠遠超過一整套單體應用的拓撲。這多是一個巧合,也代表咱們正在採用這種微服務架構方法。分佈式
Part 2:設計微服務系統
最近我一直在與許多大型組織合做,幫助他們理解並實現Web API和微服務體系結構的價值。在這項工做中,我看到這些組織一直在努力於,如何定義企業裏微服務之間的最佳邊界。這是一個已知的問題,但沒有解決。雖然關於凝聚式服務(cohesive services)的價值和有界上下文已經寫了不少,但如何實際識別這些內容彷佛沒有指導意義。
這個問題的一個緣由是,試圖肯定服務邊界的人是技術人員,他們天生就在尋找技術解決方案,可是定義凝聚力和能力一致性的服務邊界(cohesive, capability-aligned service boundaries)卻須要領域專家。從根本上說,這應該是一種建模練習,它獨立於任何技術的覆蓋。然而,即便那些有意識地採用了技術無關建模方法的組織,也一直在努力定義服務邊界。
發生這種狀況的部分緣由是,最流行的軟件建模方法每每存在實施誤差。例如,領域驅動設計(DDD)傾向於面向對象的編程,而UML偏向數據建模的角度。除此以外,業界尚未就如何直觀地描繪微服務系統模型達成共識,諸如應該描述哪些組件,應該如何表示關係,應該使用什麼術語,更不用說這其中的任何工具。
不過,全部的但願都不會丟失。 DDD的一些概念,最明顯的是「有界上下文」( bounded contexts)的概念,已經得到了普及,並啓動了關於服務邊界定義的行業對話。重要的是,DDD方法論中更高層次的抽象,包括域,子域,有界上下文,聚合(aggregates),上下文映射,都是技術不可知和模型爲中心的。
理解系統的方法是關注組件之間的關係,若是想要一個微服務系統的基本表示,不須要比上下文映射更深刻。所以,也許咱們可使用DDD上下文映射做爲可視化微服務系統的起點。
即便在上下文映射層面,大型組織的完整服務系統也是不可理解的。所以,爲了使上下文映射有用,爲上下文映射自己設置上下文很是重要。這種上下文能夠是特定總體應用程序的分解,或特定計劃的服務交互。連貫地構建一個大型組織的微服務系統的惟一方法就是,逐條地,上下文地進行。
微服務上下文映射示例
來看一個例子。一家大型零售銀行但願引入以客戶爲中心的服務,以實現留住客戶的戰略目標。它但願提供一種新的以客戶爲中心的支付解決方案,容許客戶根據他們與銀行的關係(他們的帳戶,投資,資產,交互模式)進行購買,而不是將受權決策基於一個特定賬戶。
零售銀行業務自己就是一個複雜的業務領域。客戶,產品和服務渠道(分支機構,網上銀行,銷售點)等實體之間存在相互關係,以及與財務透明度和數據隱私相關的強制性規定。所以,儘管這種新的支付服務背後的想法很直觀,但它卻呈現出一個複雜的問題空間。那麼從哪裏開始呢?
繼DDD方法鬆散以後,咱們能夠首先將零售銀行業務領域劃分爲子域。做爲一個起點,並遵循康威法則的必然性,能夠從組成零售銀行的組織單位開始,並與以客戶爲中心的支付解決方案相關。這些是:
這些子域能夠經過如下方式進行可視化描述:
這給了咱們一個考慮如何分類建立以客戶爲中心的支付解決方案服務的起點。自助銀行和客戶與卡片管理子域名突出顯示,由於它們已被肯定爲解決方案的關鍵子域名。使用DDD的「語言邊界」概念,顯然有一些有界上下文出如今子域中。
在自助銀行內部,有兩種大相徑庭的有界上下文。網上銀行渠道與手機銀行渠道有共同的語言,他們都提供個性化的客戶體驗,而支持移動渠道的應用程序則是由網絡渠道構建和共享組件。咱們將這種狀況稱爲context Online Banking。另外一方面,銷售點具備獨特的語言,更多地集中在設備管理和商家關係上。咱們將稱之爲銷售點(context Point of Sale)。
客戶與卡片管理甚至更加分散。核心客戶信息,包括銀行客戶的權威列表,他們的聯繫信息和產品庫,造成了一個獨特的詞彙表,咱們稱之爲客戶信息有界的上下文。另外一種不一樣的語言被用來描述卡功能,這主要與支付活動有關。這是「消費者支付和交易」上下文。最後,還有一個客戶身份上下文專一於客戶安全和訪問控制。
產品子域名對於此付款解決方案並不重要,但值得注意的是零售貸款和貸款子域劃分爲單獨的PLC帳戶和信用卡上下文。完整的相關有界上下文以下所示:
在肯定了有界上下文以後,如今能夠考慮顧客將在其中使用哪些服務。如前所述,網上銀行有兩種服務消費者:網上銀行web App和手機銀行App。新的支付解決方案也將經過銷售點的POS網絡收到的消息請求所消耗。
客戶身份上下文必須提供客戶身份驗證服務,以確保只有合適的請求者才能訪問新的付款服務。客戶信息背景包含客戶和產品持有人之間的交叉參考,所以須要核心客戶信息服務來爲新的支付解決方案提供這些數據。
除此以外,跟蹤客戶財務活動,與其產品持有相關的財務事件,將有助於作出受權決策。所以,客戶活動分析服務能夠在客戶信息上下文中建立。
消費者支付和交易環境是爲新的以客戶爲中心的支付解決方案創建核心服務的場所。首先,客戶須要註冊新產品並設置其賬戶和產品偏好。爲此,引入了以客戶爲中心的支付管理服務。
對於非功能性緣由(例如性能,安全性和可用性),咱們將建立一個單獨的受權支付服務,稱爲以客戶爲中心的支付受權服務。最後,因爲向客戶賬戶發佈交易能夠晚於受權決定發佈,所以咱們將建立與受權服務分離的交易發佈服務(Transaction Posting Service)。
對於產品子域,咱們只會在每一個有界的上下文中引用單個同名服務。例如,存款帳戶上下文只包含一個存款帳戶服務。整個服務系統如今看起來像這樣:
這個設計過程的最後一步是註釋將發生在服務之間的交互。事實上,人們可能想要模擬有界上下文之間的相互做用,以便梳理出單個服務,但爲了覆蓋視覺效果,咱們將最後描述這一步驟。在這個階段舉例說明全部可能的交互會形成視覺混淆,所以只會關注一些可以幫助理解系統如何運做的關鍵信息。這裏有些例子:
客戶使用網上銀行Web應用程序經過以客戶爲中心的支付管理服務,註冊並設置新支付解決方案的偏好;以客戶爲中心的支付管理服務從客戶信息服務中檢索客戶的產品組合;客戶活動分析服務使用來自產品系統的信息構建客戶財務情況;客戶經過移動銀行應用程序執行以客戶爲中心的支付,該應用程序稱爲以客戶爲中心的支付受權服務;以客戶爲中心的支付受權服務,依次使用來自以客戶爲中心的支付管理服務和客戶活動分析服務的信息構建受權配置文件;一旦得到受權,支付將被轉發至交易發佈服務完成,而後調用相應的產品服務;
關於微服務系統有幾點須要注意。首先,不要假定在爲最終用戶活動提供服務時,這些交互中的每個都會實時發生。例如,儘管以客戶爲中心的受權服務須要來自其餘一些服務的信息,但可使用基於事件的方法結合緩存來確保其處理是獨立的,以便實時服務客戶的受權請求。
其次,能夠在有界上下文之間創建防腐層(ACL),以提供鬆散的語義耦合。最後,雖然這是一個至關複雜的圖片,但沒有實現細節。換句話說,這種模式可使用許多不一樣的技術來實現,包括語言,主機環境和網絡協議。
最終的上下文映射(包括交互)以下所示:
最終,此係統設計過程的目的是,幫助企業如何在複雜解決方案中定義微服務的服務邊界進行最佳猜想。但願這裏的方法既能爲服務創建一個良好的初始模型,又能更容易地從新繪製服務邊界。
Part 3:微服務設計畫布
微服務有自身的起源,一般從現有單體應用程序中涌現出來,以知足眼前的需求。提升交付速度的願望推進了微服務的採用,開發人員一般採起「代碼優先,問題排後」的方法,並重復實現有用的結果。這可行,但它是最佳的嗎?回答這個問題會帶來另外一個問題:在開發微服務以前應該考慮哪些設計因素?正如軟件架構師Simon Brown所說,「前期作大設計是愚蠢的,但沒有前期的設計更愚蠢。」
借鑑精益畫布(lean canvas )方法設計商業模型,介紹一下微服務設計畫布。這個畫布是一個工具,能夠幫助企業在構建服務以前捕獲服務中最重要的前端屬性。畫布採用了一種外部方法,它能夠很好地將您的界面與其底層實現鬆散耦合。
你能夠先在底部框中填寫服務的自由格式「說明」。從這裏開始,你應該完成「消費者任務」框,記錄服務消費者須要執行的任務。列舉服務的消費者以及他們須要執行的任務有助於明確服務的目的,並提供設計界面所需的材料輸入。這些信息能夠幫助填寫「界面」框。在這裏,消費者任務能夠細分爲與服務接口的特定交互。根據模式(查詢,命令,事件)對交互進行分類,將有助於造成底層服務實現,並最終推進API的設計。
除了服務的任務和交互以外,還必須考慮服務的非功能方面。可使用「質量(Qualities)」框來肯定服務屬性,例如可用性和性能級別,可擴展性方法和安全性指望。這將有助於消費者進一步瞭解服務,並影響其實施。總而言之,消費者的任務,界面和品質定義了服務的「表面」。這對系統的設計相當重要,由於它捕獲了系統中其餘利益相關者所需的最重要的信息。
在表面之下,還有一些關鍵的考慮因素。 「邏輯/規則」和「數據」框爲服務設計人員提供了一個位置,以記錄這些領域的關鍵因素。抵制在這個階段太深的誘惑。沒有必要爲服務的工做編寫一個完整的內部系統設計,可是可能須要感受獨特和支持表面屬性所需的項目。最後,應列出服務「依賴關係」,以便調出服務須要的任務。對於具備至關數量業務邏輯的任務繁重的微服務,須要與更多面向數據的服務進行交互是很天然的。可是,本着微服務架構的精神,目標是最大限度地減小這些依賴關係。
來看幾個示例畫布。首先是以客戶爲中心的支付管理服務畫布:
請注意,該服務看起來好像在交互中很直接,而且與其數據相對獨立。 從非功能角度來看,這不是關鍵任務,也不須要最高級別的事務完整性。 所以,它的實現可能至關簡單。
接下來是以客戶爲中心的支付受權服務的畫布:
這項服務有一些更復雜的考慮因素。首先,它預計將是高容量和低延遲。這對服務的工程設計產生了明確的影響,須要複雜的受權信息緩存。其次,因爲它的交互涉及金錢的流動,交易完整性和審計相當重要。最後,有一些事件交互意味着接口將超越典型的RESTful API。事實上,看到這些非功能性差別就清楚地說明,爲何將以客戶爲中心的支付解決方案的受權和管理功能,分解爲單獨的服務是一個很好的設計決策。在系統視圖和服務視圖之間迭代將有助於定義服務邊界。
但願這個微服務設計畫布能夠成爲着手微服務部署的企業的有用工具。它清楚地與API設計聯繫在一塊兒。
做者:Matt McLarty
原文連接:
一、Visualizing Microservices: API Design and Strategy
https://dzone.com/articles/vi...
二、Visualizing Microservices: Designing a Microservice System
https://dzone.com/articles/vi...
三、Visualizing Microservices: The Microservice Design Canvas
https://dzone.com/articles/vi...