深圳網(wǎng)站建設(shè)_請(qǐng)到中投網(wǎng)絡(luò)!四平網(wǎng)站seo
目錄
1、軟件架構(gòu)概述
1.1 軟件架構(gòu)概念
1.2 軟件架構(gòu)分類
1.3 軟件架構(gòu)模式
1.4 軟件架構(gòu)風(fēng)格
2、領(lǐng)域驅(qū)動(dòng)軟件架構(gòu)
2.1 架構(gòu)風(fēng)格
六邊行架構(gòu)(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)首選)
為什么選擇REST架構(gòu)
松耦合
可伸縮性
易用性
約束性
2.2 架構(gòu)模型
命令和查詢職責(zé)分離(CQRS)
大家好,我是老王隨聊?;I備了一周之久的架構(gòu)篇終于出爐了……
前面我們介紹了關(guān)于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)業(yè)務(wù)戰(zhàn)略層面的幾個(gè)概念:領(lǐng)域、子域、界限上下文以及界限上下文映射圖。那接下來(lái)我們要知道如何基于技術(shù)戰(zhàn)略層面進(jìn)行領(lǐng)域驅(qū)動(dòng)軟件架構(gòu)設(shè)計(jì)。本篇主要內(nèi)容包含兩部分:軟件架構(gòu)概述和領(lǐng)域驅(qū)動(dòng)軟件架構(gòu)。
下圖是從軟件架構(gòu)層面整理的DDD架構(gòu)圖(完善中)。
?
在開(kāi)始講領(lǐng)域驅(qū)動(dòng)架構(gòu)之前,我們需要先了解關(guān)于軟件架構(gòu)的一些常見(jiàn)架構(gòu)風(fēng)格和模型,因?yàn)檫@些內(nèi)容也將會(huì)在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中使用到,便于我們更好的了解這些架構(gòu)模型在領(lǐng)域驅(qū)動(dòng)中應(yīng)該如何發(fā)揮其價(jià)值,如何集眾所長(zhǎng)。另外,即便是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)這種新的方法論,在技術(shù)層面也依然采用現(xiàn)有的一些常見(jiàn)設(shè)計(jì)架構(gòu)思想,無(wú)非就是新瓶裝舊酒,關(guān)鍵在于酒怎么裝的問(wèn)題。
1、軟件架構(gòu)概述
1.1 軟件架構(gòu)概念
在軟件工程領(lǐng)域,“架構(gòu)”主要是指軟件架構(gòu),其主要目的在于指導(dǎo)架構(gòu)師和開(kāi)發(fā)人員如何進(jìn)行軟件設(shè)計(jì),也就是為我們提供軟件系統(tǒng)各個(gè)方面的設(shè)計(jì)方向。
軟件架構(gòu),并不是指可編碼能實(shí)際落地的文檔,而是一個(gè)系統(tǒng)的草圖?。它的主要工作是對(duì)一系列相關(guān)業(yè)務(wù)的一種抽象建模,把各種對(duì)象抽象成可直接構(gòu)成系統(tǒng)應(yīng)用的組件,并對(duì)各組件之間如何映射、如何通信進(jìn)行了明確且細(xì)致的描述。最終,在實(shí)現(xiàn)編碼階段,這些抽象組件將被細(xì)化為具體的某個(gè)類或者對(duì)象。
那在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中,除了我們看到的軟架構(gòu)外,還隱含著另外一種架構(gòu)—即業(yè)務(wù)架構(gòu)。該業(yè)務(wù)架構(gòu)的設(shè)計(jì)思想將伴隨著整個(gè)業(yè)務(wù)系統(tǒng)的生命周期,關(guān)于業(yè)務(wù)架構(gòu)方面的內(nèi)容我在后面的文章會(huì)講到。
1.2 軟件架構(gòu)分類
通常一個(gè)良好的軟件架構(gòu),需要具備以下特性:可靠性、安全性、擴(kuò)展性、可定制化、可伸縮、可維護(hù)、易用性和市場(chǎng)機(jī)制這八個(gè)特點(diǎn),不同的軟件架構(gòu)模式側(cè)重的特點(diǎn)不同。
從我們?nèi)粘KP(guān)注的角度來(lái)看,大體可以分為三類:邏輯架構(gòu)、物理架構(gòu)和系統(tǒng)架構(gòu)。
邏輯架構(gòu)指的是軟件系統(tǒng)中元件之間的關(guān)系。比如常用的分層架構(gòu)就是一種邏輯架構(gòu),每一次包含多個(gè)邏輯元件;物理架構(gòu)通常是指軟件系統(tǒng)在硬件上的部署方式。比如微服務(wù)架構(gòu)、垮機(jī)房垮區(qū)域的分布式架構(gòu)等;系統(tǒng)架構(gòu)指的是系統(tǒng)非功能性特征,比如云架構(gòu),考慮系統(tǒng)的穩(wěn)定性、可擴(kuò)展等。
1.3 軟件架構(gòu)模式
從軟件架構(gòu)模式角度看,大致可以劃分為:分層模式(常用的標(biāo)準(zhǔn)架構(gòu))、客戶端/服務(wù)模式、事件總線模式、管道和過(guò)濾器模式、微核模式、微服務(wù)模式和云模式等;
分層架構(gòu),將軟件分成若干個(gè)水平層,每一層都有清晰的角色和分工,不需要知道其他層的細(xì)節(jié),層與層之間是通過(guò)接口通信;
事件驅(qū)動(dòng)架構(gòu),就是通過(guò)事件進(jìn)行通信的軟件架構(gòu),主要用于系統(tǒng)之間解耦或異步任務(wù)處理;
微核模式,也叫插件模式,指的是軟件的內(nèi)核相對(duì)較小,主要功能和業(yè)務(wù)邏輯都通過(guò)插件實(shí)現(xiàn),主要用于提升系統(tǒng)組件單元的可插拔性;
云架構(gòu),主要解決系統(tǒng)的擴(kuò)展性和并發(fā)的問(wèn)題,是最容易擴(kuò)展的架構(gòu);
管道和過(guò)濾器模式,是面向數(shù)據(jù)流的軟件體系結(jié)構(gòu),其優(yōu)點(diǎn)將整個(gè)系統(tǒng)的輸入輸出行為理解為單個(gè)過(guò)濾器行為的疊加與組合,目的在于將復(fù)雜問(wèn)題分解,做到化繁為簡(jiǎn)的效果。
1.4 軟件架構(gòu)風(fēng)格
從架構(gòu)風(fēng)格的抽象緯度劃分,常見(jiàn)的分布式應(yīng)用架構(gòu)風(fēng)格有以下三種:
分布式對(duì)象(簡(jiǎn)稱DO),它要解決的主要問(wèn)題是位于不同進(jìn)程中的對(duì)象之間的調(diào)用問(wèn)題,常見(jiàn)的架構(gòu)實(shí)例有CORBA、RMI、EJB、DCOM、NET Remoting等。
遠(yuǎn)程過(guò)程調(diào)用(簡(jiǎn)稱RPC),遠(yuǎn)程過(guò)程調(diào)用采用客戶機(jī)/服務(wù)器(C/S)模式。請(qǐng)求程序就是一個(gè)客戶機(jī),而服務(wù)提供程序就是一臺(tái)服務(wù)器。和常規(guī)或本地過(guò)程調(diào)用一樣,遠(yuǎn)程過(guò)程調(diào)用是同步操作,在遠(yuǎn)程過(guò)程結(jié)果返回之前,需要暫時(shí)中止請(qǐng)求程序。使用相同地址空間的低權(quán)進(jìn)程或低權(quán)線程允許同時(shí)運(yùn)行多個(gè)遠(yuǎn)程過(guò)程調(diào)用。常見(jiàn)的架構(gòu)實(shí)例有SOAP、XML-RPC、Hessian、DWR等。WEB服務(wù)提供一個(gè)分布式函數(shù)或方法接口供用戶調(diào)用,這是一種比較傳統(tǒng)的方式。通常,在WSDL中對(duì)RPC接口進(jìn)行定義(類似于早期的XML-RPC)。
表述性狀態(tài)轉(zhuǎn)移(簡(jiǎn)稱REST),WEB服務(wù)類似于HTTP或其他類似協(xié)議,它們把接口限定在一組廣為人知的標(biāo)準(zhǔn)動(dòng)作中(比如HTTP的GET、PUT、DELETE)以供調(diào)用。此類WEB服務(wù)關(guān)注與那些穩(wěn)定的資源的互動(dòng),而不是消息或動(dòng)作。此種服務(wù)可以通過(guò)WSDL來(lái)描述SOAP消息內(nèi)容,通過(guò)HTTP限定動(dòng)作接口;或者完全在SOAP中對(duì)動(dòng)作進(jìn)行抽象。架構(gòu)實(shí)例有HTTP、WebDAV。
不同架構(gòu)模式和風(fēng)格會(huì)之間有非常大的差別。這里暫且不聊對(duì)比差異,先了解在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)該如何使用這些架構(gòu)模式和架構(gòu)風(fēng)格。
2、領(lǐng)域驅(qū)動(dòng)軟件架構(gòu)
2.1 架構(gòu)風(fēng)格
六邊行架構(gòu)(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)首選)
我們知道,六邊形架構(gòu)是一種對(duì)稱性的架構(gòu)風(fēng)格,其原理采用了端口適配器模式。其目的在于構(gòu)建一種持久生命力的架構(gòu),各端口之間是一種平等方式與系統(tǒng)交互,是內(nèi)部和外部的關(guān)系,不存在前端和后端嚴(yán)格劃分的概念。六邊形架構(gòu)如下圖所示。
?
那為什么領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)會(huì)將六邊形架構(gòu)作為首選?
核心原因在于,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)與傳統(tǒng)的分層架構(gòu)相比,其希望我們將重點(diǎn)的工作放在領(lǐng)域?qū)釉O(shè)計(jì)上。領(lǐng)域?qū)?、基礎(chǔ)設(shè)施層只依賴由領(lǐng)域模型所定義的抽象接口,而客戶層是一種平等的方式與業(yè)務(wù)模型進(jìn)行交互。因此與傳統(tǒng)風(fēng)層結(jié)構(gòu)相比,其采用了依賴倒置原則。以上的交互和依賴倒置正好與六邊形架構(gòu),所以這才是真正選擇六邊形架構(gòu)的原因。
當(dāng)然,如果你的項(xiàng)目采用了領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的方式,不一定必須采用六邊形架構(gòu),具體采用哪種風(fēng)格需要我們?cè)谧黾軜?gòu)設(shè)計(jì)前,從性價(jià)比通盤考慮后再選擇。
另外需要注意的一點(diǎn),即使你的系統(tǒng)采用了六邊形架構(gòu),那同時(shí)也依然可以在六邊形架構(gòu)內(nèi)部使用其他類型架構(gòu)。比如SOA架構(gòu)、REST或者事件驅(qū)動(dòng)架構(gòu),也有可能采用CQRS;或者數(shù)據(jù)網(wǎng)織或基于網(wǎng)格的分布式緩存;還有可能采用Map- Reduce這種分布式并行處理方式。六邊形架構(gòu)可為系統(tǒng)其他架構(gòu)提供堅(jiān)實(shí)的基礎(chǔ)支撐,這也體現(xiàn)了六邊行架構(gòu)很好的包容性。
為什么選擇SOA架構(gòu)
面向服務(wù)的體系結(jié)構(gòu)?(SOA),是一個(gè)組件模型,它將應(yīng)用程序的不同功能(即服務(wù))通過(guò)服務(wù)之間定義良好的接口和契約聯(lián)系起來(lái)。接口是采用中立的方式進(jìn)行定義的,它應(yīng)該獨(dú)立于實(shí)現(xiàn)服務(wù)的硬件平臺(tái)、操作系統(tǒng)和編程語(yǔ)言。這使得構(gòu)建在各種這樣的系統(tǒng)中的服務(wù)可以以一種統(tǒng)一和通用的方式進(jìn)行交互。
?
這里提到SOA架構(gòu),主要是與從六邊形架構(gòu)相比,它們都為領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)提供了共同的基礎(chǔ)價(jià)值。
在SOA架構(gòu)中,這8大設(shè)計(jì)原則依然適應(yīng)六邊形架構(gòu),而且有一部分特性對(duì)六邊形架構(gòu)進(jìn)行了很好的補(bǔ)充。比如服務(wù)抽象、松耦合、服務(wù)重用性、服務(wù)組合性、服務(wù)契約、服務(wù)自治性、服務(wù)無(wú)狀態(tài)性、服務(wù)可發(fā)現(xiàn)性,這些特性均可以與六邊形架構(gòu)進(jìn)行很好的結(jié)合。在上圖中,服務(wù)邊界位于最左側(cè),而領(lǐng)域模型位于中心位置,消費(fèi)方可以通過(guò)REST、SOAP和消息機(jī)制獲取服務(wù)。
為什么選擇REST架構(gòu)
REST,表述性狀態(tài)傳遞,屬于Web架構(gòu)的一種軟件架構(gòu)風(fēng)格,REST也是web架構(gòu)的理論擴(kuò)展。它是一種針對(duì)網(wǎng)絡(luò)應(yīng)用?的設(shè)計(jì)和開(kāi)發(fā)方式,可以降低開(kāi)發(fā)的復(fù)雜性,提高系統(tǒng)的可伸縮性。
在了解領(lǐng)域設(shè)計(jì)驅(qū)動(dòng)之前,要說(shuō)明兩點(diǎn):
第一,REST并不是一種具體的技術(shù),也不是一種具體的規(guī)范,而是一種內(nèi)涵非常豐富的架構(gòu)風(fēng)格,一整套研究和評(píng)價(jià)軟件架構(gòu)的方法論,這套方法論的核心詞在“架構(gòu)風(fēng)格”。
第二,架構(gòu)風(fēng)格是一種研究和評(píng)價(jià)軟件架構(gòu)設(shè)計(jì)的方法,它是比架構(gòu)本身更加抽象的概念。一種架構(gòu)風(fēng)格是由一組相互協(xié)作的架構(gòu)約束來(lái)定義的,而架構(gòu)約束是對(duì)軟件的運(yùn)行環(huán)境施加在架構(gòu)設(shè)計(jì)之上的一種約束行為,對(duì)架構(gòu)進(jìn)行更好的規(guī)范。
尤其是第二點(diǎn),對(duì)于我們進(jìn)行軟件設(shè)計(jì)所起到的作用更大。
?
在三種主流的Web服務(wù)?實(shí)現(xiàn)方案中,因?yàn)镽EST模式的Web服務(wù)與復(fù)雜的SOAP?和XML-RPC?對(duì)比來(lái)講明顯的更加簡(jiǎn)潔,當(dāng)前很多企業(yè)開(kāi)發(fā)系統(tǒng),越來(lái)越多的web服務(wù)開(kāi)始采用REST風(fēng)格設(shè)計(jì)和實(shí)現(xiàn)。
我們知道,在 REST 架構(gòu)風(fēng)格中,數(shù)據(jù)和功能被視為資源,并使用統(tǒng)一資源標(biāo)識(shí)符 (URI) 進(jìn)行訪問(wèn)。通過(guò)使用一組簡(jiǎn)單的、定義良好的操作來(lái)處理資源??蛻舳撕头?wù)器通過(guò)使用標(biāo)準(zhǔn)化的接口和協(xié)議(通常是 HTTP)來(lái)交換資源。另外,其資源是與表現(xiàn)形式進(jìn)行分離的,以便可以以各種格式訪問(wèn)其內(nèi)容,例如 HTML、XML、純文本、PDF、JPEG、JSON 等。
?那REST在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中的作用是什么呢?依然是其與六邊行架構(gòu)所提供的共同價(jià)值所決定的,即松耦合、可伸縮和易用性。
松耦合
符合REST原則的系統(tǒng)具有更好的松耦合。通常來(lái)講,添加新資源并在已有資源中創(chuàng)建到新資源的鏈接是非常簡(jiǎn)單的,要添加新的格式同樣如此。REST API使用URI來(lái)進(jìn)行資源的定位,所以這個(gè)URI需要直觀并且容易使用。
可伸縮性
基于基于REST的系統(tǒng)也是非常容易理解的。因?yàn)榇藭r(shí)系統(tǒng)被分為很多較小的資源模塊,每一個(gè)資源塊都可以獨(dú)立測(cè)試和調(diào)試,并且每一個(gè)資源模塊都表示了一個(gè)可重用的入口點(diǎn)。該架構(gòu)本身具有很好的松耦合和可伸縮性。
易用性
采用REST架構(gòu)風(fēng)格,對(duì)于開(kāi)發(fā)、測(cè)試、運(yùn)維人員來(lái)說(shuō),都會(huì)更簡(jiǎn)單。可以充分利用大量HTTP服務(wù)器端和客戶端開(kāi)發(fā)庫(kù)、Web功能測(cè)試/性能測(cè)試工具、HTTP緩存、HTTP代理服務(wù)器、防火墻。這些開(kāi)發(fā)庫(kù)和基礎(chǔ)設(shè)施早已成為了日常用品,不需要什么火箭科技(例如神奇昂貴的應(yīng)用服務(wù)器、中間件)就能解決大多數(shù)可伸縮性方面的問(wèn)題。
約束性
另外,REST架構(gòu)風(fēng)格最重要的架構(gòu)約束有6個(gè):客戶-服務(wù)器(Client-Server)、無(wú)狀態(tài)(Stateless)、通信的會(huì)話狀態(tài)(Session State)、緩存(Cache)、統(tǒng)一接口(Uniform Interface)、分層系統(tǒng)(Layered System)。這些特性對(duì)六邊形架構(gòu)也進(jìn)行了很好的規(guī)范約束。
2.2 架構(gòu)模型
我們前面提到,架構(gòu)模式通常分分層模式(常用的標(biāo)準(zhǔn)架構(gòu))、客戶端/服務(wù)模式、事件總線模式、命令和查詢職責(zé)分離模式、管道和過(guò)濾器模式、微核模式、微服務(wù)模式和云模式等。從作者的視角,為什么要單獨(dú)大篇幅去講命令查詢模式呢?這是我們需要重點(diǎn)關(guān)注的地方。
命令和查詢職責(zé)分離(CQRS)
CQRS 是“命令和查詢責(zé)任分離”的英文縮寫,它是一種將數(shù)據(jù)存儲(chǔ)的讀取操作和更新操作分離的模式,類似于我們?cè)跀?shù)據(jù)庫(kù)層面的讀寫分離。它主要解決了,在復(fù)雜系統(tǒng)中當(dāng)多種讀取形式和寫入工作負(fù)載非對(duì)稱,并且讀寫的性能要求有很大差異時(shí),會(huì)倒置模型執(zhí)行太多操作且過(guò)度復(fù)雜的問(wèn)題。這樣做的好處就是可以最大限度地提高系統(tǒng)的性能、可縮放性和安全性。
?
但CQRS這種模式在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)當(dāng)中是最優(yōu)的嗎?凡事都有兩面性,固然優(yōu)點(diǎn)需要借鑒學(xué)習(xí),但也需要我們用批判精神來(lái)看待其不足。那CQRS在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中不好的一面也體現(xiàn)的會(huì)更明顯。
第一,CQRS無(wú)法很好的解決事務(wù)性。
對(duì)于之前采用的單一數(shù)據(jù)源,我們通常依靠關(guān)系型數(shù)據(jù)庫(kù)的事務(wù)特性能夠很好的保證數(shù)據(jù)的完整性。但是在?CQRS?中這一切都發(fā)生了變化。因?yàn)樵贑QRS中一個(gè)?command?觸發(fā)的事件,在?query?端可能需要更新很多個(gè)數(shù)據(jù)模型,而這是有可能失敗的。一旦更新失敗那么數(shù)據(jù)就會(huì)長(zhǎng)時(shí)間的處于不一致?tīng)顟B(tài),這時(shí)需要外部的介入單獨(dú)處理。從事務(wù)的角度來(lái)看?CQRS,需要面對(duì)的是問(wèn)題是如何解決最終一致性。
第二,數(shù)據(jù)時(shí)效性問(wèn)題。
在 CQRS模式中,當(dāng)command?端完成數(shù)據(jù)更新后,需要通過(guò)事件形式通知查詢端系統(tǒng),這也就意味著系統(tǒng)之間會(huì)存在一定時(shí)間差,此時(shí)如果業(yè)務(wù)對(duì)于數(shù)據(jù)的實(shí)時(shí)性要求非常高,那么可能?CQRS 的技術(shù)架構(gòu)選型就不適合了,此時(shí)可能需要對(duì)實(shí)時(shí)的數(shù)據(jù)接口進(jìn)行區(qū)分加以特殊處理。
第三,查詢模式設(shè)計(jì)的復(fù)雜性問(wèn)題。
雖然 CQRS 為我們分離了領(lǐng)域模型和服務(wù)于查詢功能的數(shù)據(jù)模型,但這意味著我們需要單獨(dú)設(shè)計(jì)另一套針對(duì)查詢功能的數(shù)據(jù)模型。
這種做法帶來(lái)的問(wèn)題就是當(dāng)查詢接口越來(lái)越多時(shí)就會(huì)難以管理,仍然需要按照 DDD 中劃分領(lǐng)域的思路將屬于一個(gè)領(lǐng)域的查詢集中管理作為整個(gè)查詢系統(tǒng)的一個(gè)上下文,甚至需要獨(dú)立出一個(gè)新的微服務(wù),這也無(wú)形之中,CQRS 在帶來(lái)架構(gòu)自由與便利的同時(shí)也不可避免的引入了額外的復(fù)雜性與技能要求。
那作者為什么還要在DDD中提及CQRS架構(gòu)模式呢?
我個(gè)人理解主要有以下兩點(diǎn):
1)選擇與領(lǐng)域驅(qū)動(dòng)契合的點(diǎn)—邊界清晰職責(zé)明確
如果你所面對(duì)的業(yè)務(wù)系統(tǒng)已經(jīng)非常龐大,而且業(yè)務(wù)流程龐雜邏輯繁瑣,那么不妨嘗試使用 CQRS 將 Command 與 Query 進(jìn)行拆分,將領(lǐng)域模型與數(shù)據(jù)模型的邊界劃分的更清晰些。
2)領(lǐng)域驅(qū)動(dòng)架構(gòu)設(shè)計(jì)需要集眾所長(zhǎng)
從作者所的文章中,我們看到無(wú)論采用CQRS、消息總線模型、長(zhǎng)時(shí)處理模型哪種單一架構(gòu)模型,都不能完美解決系統(tǒng)中所存在的各種問(wèn)題。所以需要我們使用多種架構(gòu)模式來(lái)共同協(xié)作,以此完善整個(gè)系統(tǒng)架構(gòu)。
總之,在軟件架構(gòu)設(shè)計(jì)中,無(wú)論是架構(gòu)風(fēng)格還是架構(gòu)模式,都需要集眾所長(zhǎng),避其所短,方能設(shè)計(jì)出架構(gòu)良好的系統(tǒng)。