基于事件驱动架构构建微服务第1部分:应用程序特定的业务规则
原文鏈接:https://logcorner.com/building-microservices-through-event-driven-architecture-part1-application-specific-business-rules/
如今,洋蔥或六邊形等架構(gòu)為代碼的可測(cè)試性和維護(hù)、與外部框架的獨(dú)立性提供了重要幫助。
在本教程中,我將展示如何使用Clean架構(gòu),以及諸如領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)、測(cè)試(行為)驅(qū)動(dòng)開發(fā)(TDD)、CQRS、事件溯源、容器化、Oauth2和Oidc等方法和工具來構(gòu)建微服務(wù)架構(gòu)。
關(guān)于Clean架構(gòu)的更多信息,我建議您閱讀Robert C. Martin (Uncle Bob)的這篇文章:https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
依賴規(guī)則
同心圓代表軟件的不同區(qū)域。一般來說,越深入代表你的軟件層次越高。外圓是戰(zhàn)術(shù)實(shí)現(xiàn)機(jī)制,內(nèi)圓是戰(zhàn)略核心策略。
使這個(gè)架構(gòu)工作的最重要的規(guī)則是依賴規(guī)則。這個(gè)規(guī)則說明了源代碼依賴只能指向內(nèi)部。內(nèi)圈的任何東西都不可能知道外圈的任何東西。特別是,在外圈中聲明的部分不能被內(nèi)圈中的代碼提及。包括,函數(shù),類。變量或任何其他命名的軟件實(shí)體。
同樣,外圈中使用的數(shù)據(jù)格式不應(yīng)該被內(nèi)圈使用,特別是如果這些格式是由外圈中的框架生成的。我們不希望外圈的任何東西影響內(nèi)圈。
命令查詢責(zé)任分離 (CQRS)
CQRS將命令與查詢分開。命令是更改應(yīng)用程序狀態(tài)并且不返回?cái)?shù)據(jù)的操作。查詢是返回?cái)?shù)據(jù)但不更改應(yīng)用程序狀態(tài)的操作。因此,在微服務(wù)領(lǐng)域,通過使用兩個(gè)數(shù)據(jù)庫創(chuàng)建應(yīng)用程序,CQRS將是一個(gè)非常有用的概念:
1.一個(gè)關(guān)系型數(shù)據(jù)庫,它針對(duì)在命令端寫入進(jìn)行了優(yōu)化。
2.查詢端使用NoSQL數(shù)據(jù)庫,以便盡可能快地讀取數(shù)據(jù)。
由于大多數(shù)應(yīng)用程序讀取數(shù)據(jù)的頻率遠(yuǎn)高于寫入數(shù)據(jù)的頻率,因此在我們的容器化方法中,我們可以在2個(gè)pod上部署命令端,在10個(gè)pod上部署查詢端。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)
CQRS適合領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)。DDD專注于構(gòu)建豐富的領(lǐng)域模型來處理復(fù)雜的業(yè)務(wù)邏輯。
更改數(shù)據(jù)會(huì)導(dǎo)致更多錯(cuò)誤。因此,清楚地了解應(yīng)用程序的哪個(gè)部分更改了數(shù)據(jù)以及應(yīng)用程序的哪個(gè)部分不更改數(shù)據(jù)將有助于可維護(hù)性和調(diào)試。
事件溯源
事件溯源將對(duì)象的所有更改存儲(chǔ)為事件存儲(chǔ)中的一系列事件。https://eventstore.org/
我將使用這個(gè)概念來構(gòu)建以下內(nèi)容:
領(lǐng)域服務(wù)實(shí)現(xiàn)領(lǐng)域相關(guān)的概念(實(shí)體、值對(duì)象、聚合、領(lǐng)域事件),在關(guān)系數(shù)據(jù)庫中記錄一個(gè)命令,在事件存儲(chǔ)中記錄一個(gè)事件。全部作為一個(gè)單元,以進(jìn)行數(shù)據(jù)更改
生產(chǎn)者從事件存儲(chǔ)中獲取事件并將其發(fā)送到服務(wù)總線(事件存儲(chǔ)是一個(gè)只附加表)
消費(fèi)者,服務(wù)總線的訂閱者,從服務(wù)總線獲取事件并將其作為預(yù)先計(jì)算的數(shù)據(jù)寫入NoSQL數(shù)據(jù)庫
ReadModel服務(wù)查詢NOSQL數(shù)據(jù)庫
發(fā)生的一切都保存在事件存儲(chǔ)中?
我將建立一個(gè)系統(tǒng),幫助演講者和與會(huì)者注冊(cè)和跟蹤事件(會(huì)議、談話、聚會(huì)等…)
我的項(xiàng)目結(jié)構(gòu)如下:
EduSync.Speech.Domain
容納核心領(lǐng)域的最內(nèi)層。它包含我們的領(lǐng)域?qū)ο蠛蜆I(yè)務(wù)規(guī)則。定義了我們的外部接口。
數(shù)據(jù)庫、網(wǎng)絡(luò)連接、文件系統(tǒng)、用戶界面或特殊框架,都是不允許的。
核心領(lǐng)域不知道自己之外的任何東西。
這些依賴項(xiàng)及其實(shí)現(xiàn)是使用接口注入我們的核心域的。
EduSync.Speech.Application
指向核心領(lǐng)域并包含特定于應(yīng)用程序的業(yè)務(wù)規(guī)則。
編排數(shù)據(jù)流并使用領(lǐng)域模型。
不依賴于數(shù)據(jù)庫、UI 或特殊框架。
EduSync.Speech.Presentation
該層包含Web、UI和展示邏輯。在我們的API上下文中,這意味著它通過網(wǎng)絡(luò)接受http請(qǐng)求形式的輸入(POST/PUT/PATCH/DELETE),并以JSON格式的內(nèi)容返回其輸出。
EduSync.Speech.Infrastructure
該層包含數(shù)據(jù)庫和網(wǎng)關(guān)。在這里,我們定義數(shù)據(jù)訪問層、存儲(chǔ)庫等。
它包含在我們的Domain中定義的接口的物理實(shí)現(xiàn)。?
測(cè)試驅(qū)動(dòng)開發(fā)
實(shí)現(xiàn)“語音注冊(cè)”用例
為了使我的測(cè)試變?yōu)榫G色,我首先需要實(shí)現(xiàn)的是RegisterSpeechUseCase
使這個(gè)架構(gòu)工作的最重要的規(guī)則是依賴規(guī)則。這個(gè)規(guī)則說源代碼依賴只能指向內(nèi)部。內(nèi)圈中的任何東西都不可能知道外圈中的任何東西。
因此,讓我們定義IRegisterSpeechUseCase接口及其實(shí)現(xiàn)RegisterSpeechUseCase。這些類型屬于EduSync.Speech.Application。
它將輸入對(duì)象作為命令。
然后是接口?
然后RegisterSpeechUseCase如下所示:
讓我們定義IUnitOfWork和ISpeechRepository等依賴項(xiàng),這些接口屬于核心域,將在基礎(chǔ)設(shè)施上實(shí)現(xiàn)。
ISpeechRepository需要一個(gè)語音實(shí)體,所以讓我們?cè)诤诵挠蛏蟿?chuàng)建它
一切都編譯成功,但我的測(cè)試失敗了。
如您所見,測(cè)試失敗是因?yàn)槲因?yàn)證需要調(diào)用CreateAsync和Commit方法,所以讓我們?cè)赗egisterSpeechUseCase類上調(diào)用SpeechRepository.CreateAsync和IUnitOfWork.Commit
然后在我的單元測(cè)試的arrange部分創(chuàng)建SpeechRepository.CreateAsync和IUnitOfWork.Commit的mock
所有測(cè)試都是綠色的了,但我的代碼覆蓋率還不夠:
例如,如果我注釋掉這個(gè)塊,我的測(cè)試將成功,但如果command為空,我的應(yīng)用程序?qū)⒃谶\(yùn)行時(shí)崩潰?
讓我們添加一個(gè)新的測(cè)試來修復(fù)它?
最后,LogCorner.EduSync.Speech.Application的代碼覆蓋率為100%
但是如果我替換了賦值會(huì)發(fā)生什么?
var?title?=?command.Type; var?urlValue?=?command.Title; var?description?=?command.Url; var?type?=?command.Description;?所有測(cè)試都會(huì)成功,但我的應(yīng)用程序?qū)⑻幱跓o效狀態(tài),因?yàn)樗鼘⒉迦霕?biāo)題而不是 url,...。
我可以在測(cè)試斷言中使用moqSpeechRepository.Verify修復(fù)它,但我會(huì)保留它并在通過引入值對(duì)象實(shí)現(xiàn)我的領(lǐng)域時(shí)修復(fù)它
下一步,我將實(shí)現(xiàn)領(lǐng)域模型。
源代碼可在此處獲得:RegisterSpeechUseCase(https://github.com/logcorner/LogCorner.EduSync/tree/Feature/Task/RegisterSpeechUseCase)
歡迎關(guān)注我的個(gè)人公眾號(hào)”My IO“
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的基于事件驱动架构构建微服务第1部分:应用程序特定的业务规则的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WPF 实现任务栏角徽
- 下一篇: 听说过Netflix的Chaos Mon