精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

萬億級流量下怎樣保證系統(tǒng)不宕機?

網(wǎng)絡(luò) 網(wǎng)絡(luò)管理 架構(gòu)
本文在對歷史遺留系統(tǒng)問題深入分析后,找到問題的本質(zhì)解,制定切實有效的解決方案。通過運用整潔架構(gòu)設(shè)計理念,對歷史遺留系統(tǒng)進行全面的模型分析和架構(gòu)重新設(shè)計,并借助DDD戰(zhàn)術(shù)工具實現(xiàn)代碼開發(fā)。
最近,身邊好幾位在創(chuàng)業(yè)公司的技術(shù)朋友都在抱怨,說他們公司的系統(tǒng)不穩(wěn)定,代碼年代久遠(yuǎn),還找不到完整的設(shè)計文檔,現(xiàn)在接手后連碰都不敢碰那些陳舊的代碼。面對這些歷史遺留問題,我給他們講了一個身邊真實的故事。

以前有家公司,業(yè)務(wù)發(fā)展特別快,現(xiàn)有的系統(tǒng)功能跟不上市場需求了。于是,他們收購了一家小公司,并讓自己公司的技術(shù)團隊去接手被收購公司的系統(tǒng)。結(jié)果呢,技術(shù)團隊花了好大一番功夫梳理代碼,發(fā)現(xiàn)那代碼亂得不行,簡直就是 “意大利面條” 式的代碼,根本沒法維護。沒辦法,他們只能下定決心重構(gòu)這個系統(tǒng)。

半年后,業(yè)務(wù)又變了,這個系統(tǒng)要交給公司另一個部門的技術(shù)團隊來維護。新接手的團隊同樣先梳理代碼,梳理完后得出的結(jié)論是:這代碼可讀性極差,層級關(guān)系混亂,完全沒辦法繼續(xù)開發(fā)新功能了,所以希望再對這個系統(tǒng)進行重構(gòu)。這時候,公司老板找來了兩個技術(shù)團隊的負(fù)責(zé)人,問他們:“這個系統(tǒng)不是半年前剛重構(gòu)過的嗎?怎么換了個團隊維護就要重構(gòu)呢?你們這次重構(gòu)了,就能保證下次別人接手不再吐槽、不再重構(gòu)嗎?”

聽完這個故事后,朋友們沉默了一會兒,然后問我:“那我們該怎么辦呢?現(xiàn)在每周因為這些遺留系統(tǒng)導(dǎo)致的問題,搞得我焦頭爛額的。”

圖1 混亂不堪的系統(tǒng)現(xiàn)狀圖1 混亂不堪的系統(tǒng)現(xiàn)狀

不只是創(chuàng)業(yè)公司,這種情況在大公司也很常見,甚至可以說更加普遍。由于大公司的業(yè)務(wù)發(fā)展時間長、系統(tǒng)復(fù)雜度高,遺留下來的老舊系統(tǒng)數(shù)量更多,且這些系統(tǒng)的歷史往往更為久遠(yuǎn)。

下圖是某知名互聯(lián)網(wǎng)公司對其線上事故原因進行統(tǒng)計分析后得出的結(jié)果。從圖中可以看出,接近一半的線上事故問題,都可以追溯到業(yè)務(wù)代碼邏輯的缺陷或不合理之處。這進一步凸顯了代碼質(zhì)量和架構(gòu)合理性在軟件系統(tǒng)穩(wěn)定運行中的重要性。

圖2 某互聯(lián)網(wǎng)公司線上事故分析圖圖2 某互聯(lián)網(wǎng)公司線上事故分析圖

造成系統(tǒng)問題的原因和解決方案

運維抱怨道:“這些歷史遺留系統(tǒng)根本沒法維護,動不動就宕機,三天兩頭出問題。”

開發(fā)人員也無奈地說:“老功能動都不敢動,怕出問題,新功能更是沒法添加,每天都在忙著救火,搞穩(wěn)定性治理,忙得焦頭爛額。”

測試人員則表示:“一個接口或者消息,根本不知道有多少地方在使用,完全不清楚哪些部分會受影響,更別提會不會有漏測的地方,心里一點底都沒有。”

我相信,大家在面對各種歷史遺留問題時,如果詳細(xì)羅列出來,恐怕都能寫好幾篇論文了。不過,這些所謂的“歷史遺留問題”,從一開始就是問題嗎?或者說,如果原開發(fā)團隊還在維護這些系統(tǒng),對他們來說這些問題還會存在嗎?我覺得未必。那究竟是什么原因?qū)е逻@些問題一步步演變成現(xiàn)在這種難以維護的局面呢?顯然,壓死駱駝的絕不是最后一根稻草。

圖3 壓死駱駝的稻草圖3 壓死駱駝的稻草

因此,面對形形色色的歷史遺留問題,我們首先要做的是透過現(xiàn)象看清本質(zhì)。只有深入挖掘問題的根本原因,才能找到真正有效的解決方案,從而給出切實可行的具體措施來解決這些問題。

圖4 U型思考模型圖4 U型思考模型

對于“歷史遺留問題”,我們計劃運用 U 型思考模型的四步法展開分析。我們期望從問題的根本本質(zhì)出發(fā),盡力擺脫僅針對表面現(xiàn)象進行應(yīng)急處理的不良循環(huán)。

1.定義核心問題

無論是歷史遺留系統(tǒng)引發(fā)的訂單丟失、賬務(wù)對賬錯誤等資損問題,還是內(nèi)存泄漏、線程死鎖等系統(tǒng)性能問題,以及老功能修改困難、新需求開發(fā)受阻等效率問題,這些可能都只是表面現(xiàn)象。為什么這么說呢?因為這些問題都是當(dāng)前系統(tǒng)在特定時間、地點和條件下出現(xiàn)的具體表現(xiàn),而非問題的根源所在。

舉個例子,假設(shè)今天出現(xiàn)了一筆訂單,由于支付超時失敗,系統(tǒng)沒能及時提醒用戶重新支付,導(dǎo)致用戶端一直顯示“支付中”。如果我們僅把這些表面現(xiàn)象當(dāng)作核心問題,可能會通過延長支付超時時間或增加失敗重試機制來修改代碼。然而,明天可能又會出現(xiàn)因支付失敗重試機制導(dǎo)致的重復(fù)扣款問題。如此一來,我們就陷入了每天不斷應(yīng)對各種歷史遺留問題的循環(huán),疲于奔命。

或許有人會說,這都是當(dāng)初架構(gòu)設(shè)計不合理造成的,現(xiàn)在出現(xiàn)的各種問題都是這個原因。這種說法有其合理性,因為當(dāng)下的許多問題確實可以追溯到架構(gòu)設(shè)計的缺陷。但同時,這種說法也有局限性。我們不能簡單地將所有問題都?xì)w咎于一個模糊的概念,因為這樣做不利于我們深入挖掘問題的本質(zhì)。這就像是小區(qū)里發(fā)生盜竊事件,我們不能僅僅歸因于“人性本惡”,而忽視了小區(qū)安保松懈、外來人員隨意進出等更直接的原因。

那么,面對歷史遺留系統(tǒng),我們真正需要解決的核心問題是什么呢?我認(rèn)為,關(guān)鍵在于如何避免我們的系統(tǒng)在未來成為別人眼中的歷史遺留問題。這個觀點值得我們深入思考。

2.發(fā)現(xiàn)問題本質(zhì)

當(dāng)我們確定要解決的核心問題后,接下來要深入洞察問題的本質(zhì)原因。就像我在文章開頭提到的例子,為什么我們接手別人開發(fā)的系統(tǒng)時,常常覺得代碼混亂而不敢輕易修改?而當(dāng)我們重構(gòu)后的系統(tǒng)交給其他團隊維護時,他們?yōu)楹我矔X得代碼難以理解?難道是我們比之前的人更厲害,而后面的人又比我們厲害?顯然不是。這主要是因為每個人的編碼習(xí)慣和設(shè)計風(fēng)格不同。就像中國小學(xué)生和印度小學(xué)生做乘法的方式不同,我們可能完全看不懂印度小學(xué)生的計算過程,自然也不敢輕易修改。

圖5 傳統(tǒng)乘法 VS 印度乘法圖5 傳統(tǒng)乘法 VS 印度乘法

在軟件的開發(fā)和維護過程中,其生命周期往往從最初的理想狀態(tài)逐漸向復(fù)雜、混亂和無序狀態(tài)演變,最終因不可維護而被迫下線或需要重構(gòu)。這種導(dǎo)致軟件質(zhì)量逐步惡化的因素,被稱為軟件的熵增現(xiàn)象。隨著歷史遺留系統(tǒng)的不斷運行,代碼功能被頻繁修改和補充,時間一長,后續(xù)的開發(fā)者就越難理解最初的代碼邏輯。

圖6 生活中的熵增圖6 生活中的熵增

熵的概念最早起源于物理學(xué),用于度量一個熱力學(xué)系統(tǒng)的無序程度。熱力學(xué)第二定律,又稱“熵增定律”,表明了在自然過程中,一個孤立的系統(tǒng)總是從最初的集中、有序的排列狀態(tài),趨向于分散、混亂和無序;當(dāng)熵達到最大時,系統(tǒng)就會處于一種靜寂狀態(tài)。

因此,想讓歷史遺留系統(tǒng)保持穩(wěn)定,既能順暢維護,又能順利支持新老功能的開發(fā),關(guān)鍵在于以團隊熟悉的風(fēng)格來設(shè)計和開發(fā)系統(tǒng),使代碼與結(jié)構(gòu)清晰直觀,確保代碼能如實體現(xiàn)架構(gòu)設(shè)計,力求達到“代碼即設(shè)計”的境界。總的來說,就是要保持架構(gòu)模式的統(tǒng)一,確保代碼清晰且如實映射架構(gòu)設(shè)計。

3.找到問題的本質(zhì)解

在探索如何找到歷史遺留系統(tǒng)問題的根本解決方案之前,我們不妨借助時光機,回到上世紀(jì) 60 - 70 年代,一同梳理計算機軟件工程的發(fā)展脈絡(luò),答案其實就深藏于軟件工程的演變歷程中。當(dāng)提及軟件工程時,就不得不回顧軟件歷史上兩次極具影響力的 “軟件危機”。

軟件危機是指在軟件開發(fā)及維護過程中遭遇的一系列棘手問題,這些問題可能大幅縮短軟件產(chǎn)品的使用壽命,甚至使其徹底報廢。

  • 第一次軟件危機(20 世紀(jì) 60 - 70 年代) :當(dāng)時軟件開發(fā)主要依賴機器語言或匯編語言,針對特定機器進行設(shè)計與編寫。軟件規(guī)模較小,無需系統(tǒng)化開發(fā)方法,多為個人設(shè)計、編碼與使用。程序依賴特定機器硬件特性,代碼復(fù)雜難懂且不可移植,難以開發(fā)復(fù)雜功能軟件。1968 年,北大西洋公約組織的計算機科學(xué)家在聯(lián)邦德國召開國際會議,首度提出“軟件工程”一詞,標(biāo)志著這門新興工程學(xué)科的誕生,旨在研究和攻克軟件危機。在此階段,更高級的結(jié)構(gòu)化編程語言如 C 語言(1972 年誕生)相繼出現(xiàn),結(jié)構(gòu)化編程思想占據(jù)主導(dǎo),提升了代碼的可讀性和可維護性。
  • 第二次軟件危機(20 世紀(jì) 80 - 90 年代) :此次危機源于軟件復(fù)雜性的進一步提升。大規(guī)模軟件動輒數(shù)百萬行代碼,涉及上百名程序員。如何高效、可靠地構(gòu)建和維護此類規(guī)模軟件成為新難題。例如,《人月神話》中提到的IBM 公司開發(fā)的OS/360 系統(tǒng),雖投入巨大資源,仍延期交付且存在大量錯誤。當(dāng)時人們期望軟件代碼具備可組合性、可擴展性和可維護性。盡管結(jié)構(gòu)化編程改善了代碼可讀性,但從開發(fā)者視角出發(fā),主要運用數(shù)據(jù)流圖(DFD)進行系統(tǒng)分析,難以直觀反映現(xiàn)實場景,導(dǎo)致開發(fā)人員與用戶溝通困難,需求分析師應(yīng)運而生。為應(yīng)對此次危機,面向?qū)ο缶幊陶Z言(如 C++、C#、Java 等)誕生,同時催生了設(shè)計模式、重構(gòu)、測試、需求分析等更優(yōu)的軟件工程方法。

鑒于如今系統(tǒng)愈發(fā)復(fù)雜,需求不確定性增加,在當(dāng)今 VUCA 時代(易變性、不確定性、復(fù)雜性、模糊性),回顧軟件危機及軟件工程發(fā)展歷程顯得尤為重要。面對復(fù)雜混亂的歷史遺留系統(tǒng)問題,軟件工程宛如一劑良方。維基百科定義軟件工程涵蓋 “軟件開發(fā)技術(shù)” 和 “軟件項目管理” 兩方面。其中,“軟件項目管理” 主要涉及項目管理知識體系,如 RUP 和敏捷 Scrum 等,暫非本次重點。“軟件開發(fā)技術(shù)” 才是我們關(guān)注的核心,包括結(jié)構(gòu)化編程、面向?qū)ο箝_發(fā)、MVC、領(lǐng)域驅(qū)動設(shè)計、整潔架構(gòu)等開發(fā)方法。以下是按時間維度梳理的部分常見軟件開發(fā)方法:

圖7 常見軟件開發(fā)方法圖7 常見軟件開發(fā)方法

在軟件開發(fā)中,有多種方法可供選擇,團隊可以根據(jù)項目和自身情況靈活運用。重要的是在團隊內(nèi)保持統(tǒng)一的架構(gòu)模式,確保代碼風(fēng)格一致,避免因風(fēng)格差異導(dǎo)致成員間難以理解彼此代碼。

有些工程師只關(guān)注完成功能需求并交付,忽視軟件的維護和擴展性,這是系統(tǒng)一兩年后難以維護的常見原因。其實,軟件開發(fā)不僅要寫代碼,更要重視需求分析,理解需求本質(zhì),與團隊統(tǒng)一概念和語言,實現(xiàn)有效溝通。

  • 需求分析是軟件開發(fā)的關(guān)鍵階段。開發(fā)人員應(yīng)積極參與需求討論,運用第一性原理思考,洞察需求本質(zhì)。與團隊對齊專有名詞和關(guān)鍵問題,達成統(tǒng)一認(rèn)知。這一階段產(chǎn)出需求規(guī)約文檔,對應(yīng)面向?qū)ο蠓治觯∣OA)階段,為后續(xù)設(shè)計和編碼提供依據(jù)。
  • 接下來是面向?qū)ο笤O(shè)計(OOD)階段。根據(jù)需求規(guī)約文檔,設(shè)計清晰合理的技術(shù)方案,確定系統(tǒng)的類結(jié)構(gòu)、對象交互和模塊劃分,確保設(shè)計邏輯清晰,為編碼提供明確指導(dǎo)。
  • 最后是面向?qū)ο缶幋a(OOP)階段。需按照OOD階段的設(shè)計方案編寫代碼,確保代碼完整反映設(shè)計邏輯。注重代碼的可讀性和可維護性,遵循團隊統(tǒng)一的編碼規(guī)范。

通過遵循OOA、OOD和OOP的流程,團隊可以更好地管理軟件開發(fā)項目,提高代碼質(zhì)量,增強系統(tǒng)的可維護性和擴展性。

4.解決問題的有效方案

軟件開發(fā)技術(shù)飛速進步,開發(fā)方法學(xué)也持續(xù)更新,比如水平分層從 MVC 三層架構(gòu)到 DDD 四層架構(gòu)、CQRS架構(gòu),垂直拆分從單體架構(gòu)到 SOA、微服務(wù)架構(gòu)(MSA)、服務(wù)網(wǎng)格(Service Mesh)等。萬變不離其宗,這些方法學(xué)旨在應(yīng)對系統(tǒng)復(fù)雜性,確保代碼可開發(fā)、易維護,防止軟件系統(tǒng)陷入 “危機”。

以下是某真實項目工程代碼結(jié)構(gòu)(公司類似工程眾多)。正如那句調(diào)侃:“三個月前寫這段代碼時,只有上帝和我懂;如今,恐怕只有上帝還看得懂了。”

圖8 某真實工程代碼現(xiàn)狀圖8 某真實工程代碼現(xiàn)狀

軟件開發(fā)大師 Bob 大叔(Robert C. Martin)在其著作《整潔架構(gòu)之道》中,提出了一個衡量軟件架構(gòu)設(shè)計質(zhì)量的標(biāo)準(zhǔn):

一個系統(tǒng)架構(gòu)的優(yōu)劣可以通過滿足用戶需求的成本來判斷。若在系統(tǒng)整個生命周期內(nèi),需求變更成本始終很低,那么這個設(shè)計就是好的。反之,如果每次發(fā)布都會增加后續(xù)變更的成本,那么這個設(shè)計就有問題。

關(guān)于整潔架構(gòu)圖的介紹如下:

圖9 整潔架構(gòu)圖圖9 整潔架構(gòu)圖

1.Entities(實體) :包含核心的業(yè)務(wù)規(guī)則,擁有狀態(tài)屬性以及業(yè)務(wù)邏輯操作。

2.Application(應(yīng)用層) :僅包含業(yè)務(wù)流程,代表各種用例場景,主要負(fù)責(zé)編排和調(diào)度 Entities 中的業(yè)務(wù)邏輯操作,具體的實現(xiàn)會在后續(xù)案例代碼中展示。

3.接口依賴方向 :所有接口(Controllers/Gateways/Presenters)只能向圓圈內(nèi)部依賴,不能反向依賴。例如,Controller 可以調(diào)用 Application,但 Application 不能調(diào)用 Controller 接口。對于數(shù)據(jù)庫操作,以往常常直接將 Entity 領(lǐng)域?qū)ο髠鬟f到 Mapper 對象中,導(dǎo)致領(lǐng)域?qū)ο髧?yán)重依賴數(shù)據(jù)庫操作對象。在 DDD(領(lǐng)域驅(qū)動設(shè)計)中,應(yīng)通過依賴反轉(zhuǎn)來改變這種現(xiàn)象(整潔架構(gòu)借鑒了 DDD 的很多概念,比如 Repository 等)。

4.Use Cases(用例) :是梳理和理解需求的重要工具,它代表業(yè)務(wù)場景,是架構(gòu)設(shè)計中非常關(guān)鍵的概念,不懂得用例的架構(gòu)師難以進行有效的架構(gòu)設(shè)計。

現(xiàn)在,讓我們重新聚焦于核心問題。我認(rèn)為,大家都能完成功能需求開發(fā),也都會使用各種開發(fā)工具,遵守編碼規(guī)范。然而,為何仍有眾多遺留系統(tǒng)問題困擾著我們?這些遺留系統(tǒng),有時并非我們從其他團隊接手的復(fù)雜代碼,而是我們自己團隊在半年或一年前編寫的代碼,如今卻難以理解和維護。

因此,我希望每位程序員不僅要掌握“軟件開發(fā)的工具和語言環(huán)境”,更要靈活運用“軟件開發(fā)的方法”,實現(xiàn)知行合一。在此案例中,我們將積極踐行《整潔代碼》和《整潔架構(gòu)設(shè)計之道》,致力于提升代碼的可讀性,降低服務(wù)組件的依賴耦合性,使變更的影響局限在最小的單元范圍內(nèi)。最后,通過一張圖來簡潔地總結(jié)我們解決歷史遺留系統(tǒng)問題的思考路徑和方法:

圖10 系統(tǒng)化解決問題思考方法圖10 系統(tǒng)化解決問題思考方法

在系統(tǒng)開發(fā)中踐行整潔架構(gòu)之道

在項目開發(fā)中,我們也希望工程代碼結(jié)構(gòu)清晰、整潔舒適。接下來,我將介紹整潔架構(gòu)在會員系統(tǒng)中的實踐經(jīng)驗,包括需求分析的用例梳理(OOA)、領(lǐng)域模型設(shè)計和程序設(shè)計(OOD),以及代碼編寫(OOP)等內(nèi)容。

1.項目背景簡單介紹

會員系統(tǒng)是企業(yè)或商家提升用戶忠誠度和銷售額的有效手段,其主要特點如下。

  • 會員注冊:用戶可以通過會員系統(tǒng)注冊為會員,會員系統(tǒng)將收集用戶的個人信息,并為其生成唯一的會員賬號(通常為手機號碼)。
  • 會員信息管理:對會員的詳細(xì)信息進行管理,包括個人資料、會員狀態(tài)和消費歷史等。
  • 獎勵和折扣管理:基于會員的忠誠度、購買歷史或其他標(biāo)準(zhǔn)為會員設(shè)計獎勵和折扣。
  • 積分和獎勵:會員在滿足一定條件的消費條件后可以獲得積分或獎勵,并可在未來的消費中使用這些積分或獎勵。會員系統(tǒng)應(yīng)在結(jié)賬時顯示可用的積分,并方便用戶使用。
  • 會員觸達:通過電子郵件或短信等方式向會員發(fā)送促銷活動通知。

2.通過用例梳理分析需求

了解項目背景后,通常下一步是編寫需求文檔,也就是PRD文檔。但許多PRD文檔是用自然語言編寫的,這使得閱讀和理解變得較為困難,還容易遺漏一些業(yè)務(wù)流程和場景。

那么,除了使用PRD這類自然語言編寫的需求文檔外,有沒有更直觀、易懂的方式來梳理業(yè)務(wù)需求呢?答案是肯定的,我們可以使用用例規(guī)約文檔來實現(xiàn)這個目的。

第一步:確定干系人

根據(jù)PRD文檔,以及和業(yè)務(wù)溝通交流,我們首先需要確定使用該系統(tǒng)的相關(guān)人員有哪些,以及他們對系統(tǒng)的目標(biāo)和訴求是什么?以下為簡化的“干系人-目標(biāo)”圖表:

表 1

干系人

目    標(biāo)

描    述

企業(yè)經(jīng)營者

(1)管理配置優(yōu)惠折扣活動。

(2)查看促銷活動的效果。

(3)制定會員等級規(guī)則。

(4)管理會員相關(guān)信息

企業(yè)經(jīng)營者是會員系統(tǒng)項目的主要干系人,負(fù)責(zé)制定會員等級規(guī)則,設(shè)定獎勵和折扣活動,管理會員信息和監(jiān)督項目的實施

收銀員

(1)查看會員信息和權(quán)益。

(2)幫助會員更好地注冊。

(3)幫助會員享受權(quán)益或兌換獎勵

收銀員或服務(wù)員是企業(yè)與會員之間的橋梁。他們需要能夠訪問會員系統(tǒng),以便為會員解決問題和提供支持

用戶

(1)會員注冊。

(2)為會員卡儲值。

(3)享受會員權(quán)益,例如折扣等。

(4)參加促銷活動

用戶是最終使用會員系統(tǒng)的干系人。他們需要通過會員系統(tǒng)注冊并領(lǐng)取獎勵和折扣

技術(shù)開發(fā)者

(1)系統(tǒng)日志記錄,便于排查問題。

(2)用戶使用埋點分析

技術(shù)開發(fā)者可以提供對會員系統(tǒng)的技術(shù)支持。他們需要理解會員系統(tǒng)的工作原理,并能夠幫助企業(yè)解決出現(xiàn)的問題

……

……

……

在梳理項目干系人及其目標(biāo)時,我們要全面覆蓋所有相關(guān)方,不能有所遺漏。例如,技術(shù)開發(fā)者的目標(biāo)和需求對系統(tǒng)開發(fā)也至關(guān)重要,不能忽視。在這一階段,項目干系人的目標(biāo)可能還比較籠統(tǒng),需要通過深入訪談來進一步細(xì)化和完善。

第二步:設(shè)計概要用例圖

在完成“干系人 - 目標(biāo)”梳理后,接下來可以從這些目標(biāo)中提取用例名稱。因為每個用例都是為了實現(xiàn)某個干系人的一個具體目標(biāo)而存在的。同時,一個用例往往包含多個場景,比如系統(tǒng)在成功或失敗等不同場景下的處理方式等。以下是一個簡單的示例用例圖:

圖11 會員系統(tǒng)概要用例圖圖11 會員系統(tǒng)概要用例圖

有了這樣的概要用例,我們對系統(tǒng)需要具備什么樣的功能和能力就有了一個比較明確的方向了,當(dāng)然如果覺得這個用例太過于抽象了,那么我們可以再繼續(xù)梳理下一層稍微詳細(xì)點的用例,這里建議不要超過三層,因為超過三層的會顯得過于細(xì)節(jié)化了,而我們在這里主要是為了梳理清楚實現(xiàn)用戶目標(biāo)系統(tǒng)應(yīng)該具備的能力就足夠了。對于每個用例更詳細(xì)的將在接下來的“書寫核心用例”中介紹。

第三步:書寫核心用例

概要用例有助于我們從宏觀上把握系統(tǒng)的功能,但對研發(fā)團隊來說,利用它不足以進行研發(fā)工作。因此,在確定用例的優(yōu)先級之后,我們應(yīng)著手對核心且高價值的用例進行詳細(xì)設(shè)計,并編寫詳細(xì)的用例。一個詳細(xì)的用例通常包含以下幾部分。

◎用例名稱:簡單明了地描述用例的主要功能。

◎參與者:與用例交互的用戶或其他系統(tǒng)。

◎前置條件:在執(zhí)行用例之前,系統(tǒng)必須處于什么狀態(tài)。

◎后置條件:在執(zhí)行用例之后,系統(tǒng)應(yīng)該處于什么狀態(tài)。

◎正常場景:描述用例在正常情況下的執(zhí)行流程。

◎異常場景:描述用例在異常情況下的執(zhí)行流程。

在編寫詳細(xì)用例時,我們必須特別注意覆蓋所有正常場景和異常場景,以防遺漏場景。當(dāng)然,我們不必為每個用例都編寫詳細(xì)的文檔,只需對復(fù)雜的核心用例編寫詳細(xì)的文檔,這樣可以顯著提升效率。例如,注冊會員的詳細(xì)用例如表2所示。

表 2

名    稱

會員注冊

描述

作為用戶,我希望能夠輕松注冊為會員,以便享受積分獎勵、折扣優(yōu)惠等會員權(quán)益

參與者

用戶:能夠享受會員權(quán)益、折扣及參與促銷活動,能夠購買僅限會員購買的商品。

收銀員:在用戶注冊遇到問題時,及時提供幫助

前置條件

企業(yè)經(jīng)營者已經(jīng)在系統(tǒng)中配置好了相應(yīng)的會員折扣

后置條件

注冊成功,贈送積分和折扣券

正常場景

(1)系統(tǒng)顯示“注冊”選項。

(2)用戶選擇“注冊”選項。

(3)系統(tǒng)顯示注冊頁面,請求用戶輸入必要的信息,例如姓名、電話號碼、電子郵件等。

(4)用戶輸入所有必要的信息。

(5)系統(tǒng)驗證用戶信息的有效性。異常場景處理參考“異常場景一”。

?系統(tǒng)驗證用戶的手機號碼格式是否正確。

?系統(tǒng)驗證用戶的電子郵件格式是否正確。

?系統(tǒng)驗證用戶的手機號碼是否已被使用。

(6)若用戶提供的信息有效,則系統(tǒng)會保存該信息并生成唯一的用戶ID。

(7)系統(tǒng)向用戶發(fā)送一條短信驗證碼,以驗證用戶的手機號碼是否正確。異常場景處理參考“異常場景二”。

(8)用戶輸入收到的短信驗證碼,確認(rèn)自己的手機號碼正確。

(9)在用戶完成驗證后,系統(tǒng)發(fā)送歡迎消息,并提供給用戶其賬戶信息和相關(guān)優(yōu)惠信息

異常場景

異常場景一如下。

(1)若用戶提供的信息無效,則系統(tǒng)會顯示錯誤的消息,并請求用戶重新輸入必要的信息。

(2)若用戶輸入無效信息超過5次,則系統(tǒng)會提示用戶嘗試其他注冊方式。

異常場景二如下。

(1)若手機號碼驗證失敗,則系統(tǒng)會提示用戶檢查其手機號碼是否正確。

(2)若用戶無法收到短信驗證碼,則系統(tǒng)會提供重新發(fā)送驗證碼的選項。

(3)若用戶仍然無法收到短信驗證碼,則系統(tǒng)會提供其他驗證方式,比如郵箱驗證等。

(4)若短信驗證碼過期,則系統(tǒng)會提示用戶重新發(fā)送短信驗證碼

特殊需求

個人信息安全,需要對用戶的手機號碼等做脫敏處理后存儲

風(fēng)險預(yù)估

其他

討論項:一個人是否可以辦理多張會員卡

以上詳細(xì)用例展示了用例作為一種簡潔、高效的結(jié)構(gòu)化需求分析工具的價值。在梳理用戶需求時,我們往往更關(guān)注正常場景,容易忽視異常場景。因此,在完成詳細(xì)用例的編寫后,我們必須重點討論和評審其是否全面覆蓋了所有異常場景。

3.領(lǐng)域模型設(shè)計和提煉

完成用例梳理后,很多人可能會直接進入系統(tǒng)設(shè)計階段。通常的做法是先設(shè)計數(shù)據(jù)庫表結(jié)構(gòu)和字段,接著根據(jù)前端界面和交互需求定義接口及其參數(shù),最后依據(jù)流程圖用代碼逐個實現(xiàn)這些接口。這種基于數(shù)據(jù)庫的開發(fā)方式被稱為“事務(wù)腳本模式”。這里我們不深入探討事務(wù)腳本模式的潛在問題,而是著重介紹如何利用前面梳理的用例來設(shè)計和提煉領(lǐng)域模型。領(lǐng)域模型是對領(lǐng)域內(nèi)概念類或現(xiàn)實世界對象的可視化表示。

首先:領(lǐng)域和子域劃分

通過與業(yè)務(wù)專家溝通,采用歸納法將功能相近的用例歸納并提煉共性。例如,將用戶和收銀員的注冊會員、查看會員信息等功能歸納為會員管理域;將會員卡儲值、核銷會員權(quán)益等功能歸納為會員卡權(quán)益管理域;將用戶參加促銷活動、企業(yè)配置活動規(guī)則等功能歸納為營銷活動管理域。這些領(lǐng)域劃分結(jié)果如圖12所示。

圖12 會員系統(tǒng)領(lǐng)域劃分圖12 會員系統(tǒng)領(lǐng)域劃分

對領(lǐng)域的劃分其實在與業(yè)務(wù)專家的溝通過程中就能很清晰地判斷出來,通過用例歸納法大多是對子域進行細(xì)化和驗證。而對于各個領(lǐng)域,我們還可以進一步細(xì)化。例如,對于營銷活動管理領(lǐng)域,根據(jù)用戶和企業(yè)經(jīng)營者職責(zé)的不同,可以將其繼續(xù)劃分為活動規(guī)則配置、券與禮品配置、營銷活動報表三個子域,如圖13所示。

圖13營銷活動管理領(lǐng)域的子域劃分圖13營銷活動管理領(lǐng)域的子域劃分

其次:尋找領(lǐng)域?qū)ο?/strong>

劃分領(lǐng)域是宏觀層面的業(yè)務(wù)垂直切分,他在DDD中是包含在戰(zhàn)略建模范圍中的,并且領(lǐng)域還可以很好地幫助我們劃分微服務(wù)。但是只劃分好微服務(wù)不是我們的目的,我們希望能更好地開發(fā)出可讀性高、易維護和易推展的代碼。而面向?qū)ο缶幊趟枷胫校詈诵牡木褪侨绾魏侠淼膭澐謱︻I(lǐng)域?qū)ο螅簿褪钦f面向?qū)ο蠓治龅木杈褪菑念I(lǐng)域到重要概念和對象的分解。

那么如何找到領(lǐng)域中重要的概念和對象呢?這里主要參考Craig Larman的《UML和模式應(yīng)用》書中的三種方法:

1.重用和修改現(xiàn)有的模型。因為在許多常見的領(lǐng)域中都存在已發(fā)布的、繪制精細(xì)的領(lǐng)域模型和數(shù)據(jù)模型,比如像RBAC(Role-Based Access Control)權(quán)限管理模型等。這里推薦Martin Fowler的《分析模式》一書,在該書中總結(jié)了很多常用通常的領(lǐng)域模型。

2.使用分類列表方式。該方式有興趣可以去研究學(xué)習(xí)下,這里不過多介紹。

3.通過識別名詞短語尋找概念類,又稱為用例建模法。該方式是我重點推薦的方式,我們可以通過對所有詳細(xì)用例的文本進行分析,識別出其中的關(guān)鍵名詞和名詞短語,將其作為候選的概念類或?qū)傩浴H缦聢D所示步驟:

圖14 用例建模法圖14 用例建模法

名詞短語法可以比較容易地找出領(lǐng)域?qū)ο蠛蛯ο笾g的關(guān)系,從而提煉出領(lǐng)域模型,具體可以采用以下步驟來提煉領(lǐng)域模型。

  • 從用例集中找出名詞短語。舉例:不同等級的會員卡優(yōu)惠不一樣,這句話中的名詞短語有“等級”和“會員卡”。
  • 根據(jù)名詞短語梳理領(lǐng)域?qū)ο蠡驅(qū)傩浴Ee例:前文中的“會員卡”可以抽象為領(lǐng)域?qū)ο螅瘛暗燃墶笨赡芫椭皇菚T卡對象中的一個屬性值了。
  • 從用例集中找出動詞和形容詞。舉例:一個人可以辦理多張會員卡。其中“辦理”為動詞。
  • 根據(jù)動詞和形容梳理領(lǐng)域?qū)ο笾g的關(guān)系。舉例:前文中提到的動詞短語“辦理多張會員卡”,可以推測出“會員”對象和“會員卡”之間存在一對多的關(guān)系。

通過以上步驟,最后我們繪制出的會員領(lǐng)域模型如下圖所示:

圖14 用例建模法圖14 用例建模法

說到這里,可能會有人覺得架構(gòu)師只是寫PPT和文檔、講理論,其實不然。架構(gòu)師不僅要會畫圖,更要寫代碼,而且代碼要能精準(zhǔn)體現(xiàn)設(shè)計的領(lǐng)域模型。接下來,讓我們進入大家都很熟悉的代碼實現(xiàn)環(huán)節(jié)。

4.戰(zhàn)略設(shè)計:水平和垂直劃分服務(wù)或模塊

我們需要先把架構(gòu)設(shè)計做好水平和垂直劃分,對應(yīng)于DDD中提出的戰(zhàn)略設(shè)計部分,他是架構(gòu)設(shè)計中的核心穩(wěn)定的主體結(jié)構(gòu),就像設(shè)計房屋大廈中的主體結(jié)構(gòu)一樣,一經(jīng)設(shè)計,未來如果需要大變動,那么將會付出非常大的代價的。在軟件的架構(gòu)設(shè)計中,這個主體主要包括微服務(wù)如何劃分,各服務(wù)之間的依賴關(guān)系是什么樣的,以及各微服務(wù)內(nèi)部的層次結(jié)構(gòu)是什么樣的。在會員系統(tǒng)項目中,各微服務(wù)和模塊設(shè)計如下圖所示:

圖16 會員系統(tǒng)邏輯架構(gòu)圖圖16 會員系統(tǒng)邏輯架構(gòu)圖

而微服務(wù)內(nèi)部層次結(jié)構(gòu)按照DDD的四層結(jié)構(gòu)劃分的。分層架構(gòu)的一個重要原則是每層只能與位于其下方的層發(fā)生耦合。分層架構(gòu)可以簡單分為兩種,即嚴(yán)格分層架構(gòu)和松散分層架構(gòu)。在嚴(yán)格分層架構(gòu)中,某層只能與位于其直接下方的層發(fā)生耦合,而在松散分層架構(gòu)中,則允許某層與它的任意下方層發(fā)生耦合。我們采用的是DDD的松散分層架構(gòu)圖如下。

圖17 DDD架構(gòu)分層圖17 DDD架構(gòu)分層

其中各層介紹如下:

  • 用戶接口層(User Interface):這是用戶與系統(tǒng)進行交互的界面層,是系統(tǒng)的最外層,負(fù)責(zé)處理用戶輸入和展示系統(tǒng)輸出。
  • 應(yīng)用層(Application):負(fù)責(zé)展現(xiàn)層與領(lǐng)域?qū)又g的協(xié)調(diào),協(xié)調(diào)業(yè)務(wù)對象來執(zhí)行特定的應(yīng)用程序任務(wù)。它不包含業(yè)務(wù)邏輯,所以相對來說是較“薄”的一層。
  • 領(lǐng)域?qū)樱―omain):負(fù)責(zé)表達業(yè)務(wù)概念,實現(xiàn)全部業(yè)務(wù)邏輯并且通過各種校驗手段保證業(yè)務(wù)正確性,是最核心關(guān)鍵的部分。而什么是業(yè)務(wù)邏輯呢?它包括業(yè)務(wù)的流程、策略、規(guī)則、狀態(tài)、以及完整性約束等,所以領(lǐng)域?qū)邮禽^“胖”的一層。
  • 基礎(chǔ)設(shè)施層(Infrastructure):這一層是系統(tǒng)的支撐層,提供了系統(tǒng)運行所需的基礎(chǔ)服務(wù)和設(shè)施,為其他層的實現(xiàn)提供技術(shù)支撐。

其對應(yīng)會員系統(tǒng)工程代碼結(jié)構(gòu)如下圖所示:

圖18 會員系統(tǒng)工程結(jié)構(gòu)圖圖18 會員系統(tǒng)工程結(jié)構(gòu)圖

5.戰(zhàn)術(shù)設(shè)計:使用DDD工具實現(xiàn)領(lǐng)域模型

在前文中介紹了如何根據(jù)用例來分析和劃分領(lǐng)域和子域,根據(jù)領(lǐng)域和子域創(chuàng)建了微服務(wù)和服務(wù)內(nèi)的模塊,并且提煉了對應(yīng)領(lǐng)域的領(lǐng)域模型,接下來將根據(jù)核心詳細(xì)用例繼續(xù)設(shè)計系統(tǒng)內(nèi)部的具體實現(xiàn)邏輯。根據(jù)詳細(xì)用例,我們可以找到用戶和系統(tǒng)之間的交互關(guān)系。在會員系統(tǒng)中,根據(jù)會員注冊這個詳細(xì)用例,我們采用UML時序圖來設(shè)計用戶和系統(tǒng)之間的交互關(guān)系,如下圖所示:

圖19 會員注冊交互圖圖19 會員注冊交互圖

在上圖中只反映了用戶與系統(tǒng)之間的交互關(guān)系。因為用戶只關(guān)心如何使用系統(tǒng)達到自己的目的,所以我們在前期優(yōu)先設(shè)計用戶與系統(tǒng)之間的交互關(guān)系,而且此時系統(tǒng)實現(xiàn)對于用戶來說還是“黑盒”,后續(xù)可以繼續(xù)對該“黑盒”(新會員注冊對象NewMemberRegister)進行完善。在這里,用戶和新會員注冊對象之間的兩次交互對應(yīng)分層架構(gòu)中的接口層(可能有兩個接口),而新會員注冊對象對應(yīng)分層架構(gòu)中的應(yīng)用層。為了實現(xiàn)用戶與系統(tǒng)之間的兩次交互,在應(yīng)用層的新會員注冊對象中就需要具備對應(yīng)的業(yè)務(wù)流程,對于其詳細(xì)的業(yè)務(wù)流程,可以繼續(xù)使用UML流程圖或時序圖來完善設(shè)計。這里使用UML時序圖來完善新用戶注冊的詳細(xì)業(yè)務(wù)流程,下圖所示為關(guān)于新用戶注冊的業(yè)務(wù)流程時序圖。

圖20 會員注冊時序圖

在通過UML時序圖和流程圖完成“新會員注冊”用例對應(yīng)的系統(tǒng)設(shè)計后,接下來我們將使用DDD中提供的戰(zhàn)術(shù)設(shè)計工具來設(shè)計高內(nèi)聚和低耦合的具體代碼。Eric Evans在他最經(jīng)典的《領(lǐng)域驅(qū)動設(shè)計:軟件核心復(fù)雜性應(yīng)對之道》一書中提供了以下具體的工具來實現(xiàn)這一目標(biāo)。

  • 實體(Entity):實體是一個不由自身屬性定義而由它自身身份定義的對象,它是具有狀態(tài)和行為的。實體對象具有唯一性并且是可持續(xù)變化的,也就是說在實體的生命周期內(nèi),無論其如何變化,其仍舊是同一個實體。它的唯一性由唯一的身份標(biāo)識來決定的,而它的可變性也正反映了實體本身的狀態(tài)和行為。
  • 值對象(Value Object):只包含元素屬性的不可變對象。值對象是將一個值用對象的方式來表述,進而表達一個具體的固定不變的概念。比如某個地址(Address)對象,它不用唯一身份標(biāo)識id來決定它的唯一性,它只用通過固定不變的概念來表示一個具體的地址就好。
  • 應(yīng)用服務(wù)(Application Service),是用來表達用戶故事(User Story)和用例(User Case)的主要手段。應(yīng)用層通過應(yīng)用服務(wù)接口來暴露系統(tǒng)的全部功能。在應(yīng)用服務(wù)的實現(xiàn)中,它負(fù)責(zé)編排和轉(zhuǎn)發(fā),它將要實現(xiàn)的功能委托給一個或多個領(lǐng)域?qū)ο髞韺崿F(xiàn),它本身只負(fù)責(zé)處理業(yè)務(wù)用例的執(zhí)行順序以及結(jié)果的拼裝。通過這樣的方式能很好的隱藏領(lǐng)域?qū)拥膹?fù)雜性及其內(nèi)部實現(xiàn)機制。應(yīng)用層除了定義應(yīng)用服務(wù)之外,在該層我們可以進行安全認(rèn)證,權(quán)限校驗,持久化事務(wù)控制,調(diào)用外部系統(tǒng)或者向其他系統(tǒng)發(fā)送事件消息等。另外,應(yīng)用層作為展示層與領(lǐng)域?qū)拥臉蛄海故緦邮褂肰O(視圖模型)進行界面展示,與應(yīng)用層通過DTO(數(shù)據(jù)傳輸對象)進行數(shù)據(jù)交互,從而達到展示層與DO(領(lǐng)域?qū)ο螅┙怦畹哪康摹?/li>
  • 領(lǐng)域服務(wù)(Domain Service),當(dāng)領(lǐng)域中的某個操作過程或轉(zhuǎn)換過程不是實體或值對象的職責(zé)時(比如跨多個領(lǐng)域?qū)ο蟮牟僮鳎覀儽銘?yīng)該將該操作放在一個單獨的接口中,即領(lǐng)域服務(wù)。領(lǐng)域服務(wù)是用來協(xié)調(diào)領(lǐng)域?qū)ο笸瓿赡硞€操作,用來處理業(yè)務(wù)邏輯的,它本身是一個行為,所以是無狀態(tài)的,狀態(tài)由領(lǐng)域?qū)ο螅ň哂袪顟B(tài)和行為)保存。
  • 模塊(Module):是指提供特定功能的相對獨立的單元,也就是對功能的分解和組合。模塊的用途是通過分解領(lǐng)域模型為不同的模塊,以降低領(lǐng)域模型的復(fù)雜性,提高領(lǐng)域模型的可讀性。
  • 聚合(Aggregate):聚合是由聚合根(ROOT ENTITY) 綁定在一起的對象的集合,是領(lǐng)域?qū)ο蟮娘@示分組,來表達整體的概念(也可以是單一的領(lǐng)域?qū)ο螅淖谥际菫榱酥С诸I(lǐng)域模型的行為和不變性,同時充當(dāng)一致性和事務(wù)性邊界。聚合根通過禁止外部對象對其成員的引用來保證在聚合內(nèi)進行的更改是一致性的,所以它的難點一般在于一致性的維護上:聚合內(nèi)實現(xiàn)事務(wù)一致性,聚合外實現(xiàn)最終一致性。
  • 工廠(Factory):工廠是用來封裝對象創(chuàng)建所必需的知識,它們對創(chuàng)建聚合特別有用。一個對象的創(chuàng)建可能是它自身的主要操作,但是復(fù)雜的組裝操作不應(yīng)該成為被創(chuàng)建對象的職責(zé),因為組裝這樣的職責(zé)會產(chǎn)生笨拙的設(shè)計,也很難讓人理解。而工廠可以幫助封裝復(fù)雜對象的創(chuàng)建過程,并且當(dāng)聚合根建立時,所有聚合包含的對象也隨之建立了,整個過程是又是原子化的。
  • 倉儲(Repository):倉儲是對聚合的管理,它介于領(lǐng)域模型和數(shù)據(jù)模型之間,主要用于聚合的持久化和檢索,同時對領(lǐng)域模型和數(shù)據(jù)模型進行了隔離,以便我們關(guān)注于領(lǐng)域模型而不需要考慮如何進行持久化。

接下來使用這些領(lǐng)域驅(qū)動設(shè)計中提供的戰(zhàn)術(shù)建模工具來完成會員系統(tǒng)領(lǐng)域模型的代碼開發(fā)。

首先創(chuàng)建微服務(wù)的項目工程,然后在項目工程的領(lǐng)域?qū)觿?chuàng)建會員領(lǐng)域模型的領(lǐng)域?qū)ο螅詈髮⒏鱾€領(lǐng)域?qū)ο蟀凑詹煌穆氊?zé)分配到對應(yīng)的微服務(wù)中,如下圖所示。

圖21 會員系統(tǒng)工程結(jié)構(gòu)圖圖21 會員系統(tǒng)工程結(jié)構(gòu)圖

在上圖中創(chuàng)建了會員(Member)對象與會員卡(Card)對象等領(lǐng)域?qū)ο螅⑶視T對象與會員卡對象為一對多的關(guān)系。在具體的實現(xiàn)過程中,代碼必須真實地反映領(lǐng)域模型,若在代碼實現(xiàn)中發(fā)現(xiàn)之前設(shè)計的領(lǐng)域模型不合理,就需要及時地調(diào)整設(shè)計中的模型結(jié)構(gòu),盡量保證模型和代碼始終一致。在創(chuàng)建領(lǐng)域?qū)嶓w對象后,我們還需要在應(yīng)用層實現(xiàn)業(yè)務(wù)流程,并調(diào)用相應(yīng)的領(lǐng)域?qū)ο髞硗瓿蓸I(yè)務(wù)邏輯處理。會員系統(tǒng)案例中會員注冊用例場景的業(yè)務(wù)流程編排邏輯代碼示例如下:

public class NewMemberRegister 
{
 
@Resource
private RegisterRepository registerRepo;
/**
* 
會員注冊業(yè)務(wù)流程實現(xiàn)
* @param memberInfoDTO
注冊信息
* @return
注冊結(jié)果
*/
public RegisterResultDTO registerMember(MemberInfoDTO memberInfoDTO)
{
RegisterResultDTO resultDTO = null;
/
/ 
第
1
步,判斷用戶是否已是會員
boolean isExist = registerRepo.isMemberExist(memberInfoDTO.getPhone());
if(isExist)
{
resultDTO = new RegisterResultDTO(RegisterConst.MEMBER_EXIST,RegisterConst.MEMBER_EXIST_MSG);
return resultDTO;
}
// 
第
2
步,創(chuàng)建會員聚合對象
Member member = MemberFactory.createMember(memberInfoDTO);
// 
第
3
步,執(zhí)行注冊會員業(yè)務(wù)邏輯。例如,根據(jù)儲值金額的不同,開通不同等級的會員卡
boolean isSuccess = member.applyMemberCard(memberInfoDTO.getMoney());
if(!isSuccess)
{
resultDTO = new RegisterResultDTO(RegisterConst.MEMBER_APPLY,RegisterConst.MEMBER_APPLY_MSG);
return resultDTO;
}
// 
第
4
步,持久化聚合根數(shù)據(jù)
boolean isSave = registerRepo.saveMember(member);
if(!isSave)
{
resultDTO = new RegisterResultDTO(RegisterConst.MEMBER_SAVE_ERROR,RegisterConst.MEMBER_SAVE_MSG);
return resultDTO;
}
// 
第
5
步,返回會員卡辦理成功的消息
resultDTO = assembleRegisterResultDTO(member);
return resultDTO;
}
private RegisterResultDTO assembleRegisterResultDTO(Member member)
{
// 
把領(lǐng)域?qū)ο筠D(zhuǎn)換為傳輸對象
DTO
,此處省略代碼
return resultDTO;
}
}

該實現(xiàn)代碼對應(yīng)時序設(shè)計圖(圖20),主要在應(yīng)用層的 NewMemberRegister 對象的registerMember()方法中實現(xiàn)會員注冊的業(yè)務(wù)流程編排。對領(lǐng)域?qū)ο蟮膭?chuàng)建則由具體的工廠類實現(xiàn),因為會員實體和會員卡實體為一對多的關(guān)系,所以這里使用了單獨的工廠類(MemberFactory)來實現(xiàn),同時,會員實體充當(dāng)聚合根對象。代碼示例如下:

public class MemberFactory 
{
 
/**
 
* 
工廠方法,默認(rèn)綁定一張會員卡,若創(chuàng)建多張會員卡,則請使用
createMoreMember()
工廠方法
 
* @param memberInfoDTO
 
* @return Member
對象
 
*/
 
public static Member createMember(MemberInfoDTO memberInfoDTO)
{
 
// 
創(chuàng)建
Member
對象,并為其賦值
 
Member member = new Member();
 
// 
省略
Member
賦值代碼
 
Card card = new Card();
 
// 
省略
Card
賦值代碼
 
// 
綁定一張會員卡
 
member.bindCard(card);
 
return member;
 
}
}

具體的會員注冊業(yè)務(wù)邏輯主要被封裝在Member和Card實體中。例如,在新用戶注冊場景中,根據(jù)儲值金額開通不同等級的會員卡并為之賦予相應(yīng)權(quán)益的業(yè)務(wù)邏輯,對應(yīng)的實現(xiàn)代碼被封裝在Member實體中。代碼示例如下:

public class Member 
{
 
/*
電話號碼
*
/
private String phone;
/*
姓名
*/
private String name;
/*
會員卡列表
*
/
private List<Card> cards;
/**
* 
新會員注冊業(yè)務(wù)邏輯,根據(jù)用戶儲值金額的不同,開通不同等級的會員卡
* @param money
* @return
*/
public boolean applyMemberCard(int money)
{
switch (money)
{
case CardLevelConst.LEVEL1_MONEY :
// 
普通卡,設(shè)置普通卡權(quán)益,例如打
9
折
// 
此處省略代碼
break;
case CardLevelConst.LEVEL2_MONEY:
// 
金卡,設(shè)置金卡權(quán)益。例如,打
88
折,同時贈送一張
10
元代金券
// 
此處省略代碼
break;
case CardLevelConst.LEVEL3_MONEY:
// 
黑金卡,設(shè)置黑金卡權(quán)益。例如,打
6
折,同時贈送一張
50
元代金券
// 
此處省略代碼
break;
default:
// 
不符合辦卡條件
return false;
}
return true;
}
/**
*
為會員創(chuàng)建一張會員卡片,并將其與會員綁定
* @param card
*/
public void bindCard(Card card)
{
if(CollectionUtils.isEmpty(cards))
{
cards = new ArrayList<>();
}
cards.add(card);
}
}

對實體對象的持久化操作,則采用RegisterRepository實現(xiàn),從而使領(lǐng)域?qū)ο蠛蛿?shù)據(jù)庫操作解耦,也保證了聚合根內(nèi)對象的數(shù)據(jù)一致性。代碼如下:

public class RegisterRepositoryImpl implements RegisterRepository 
{
 
private MemberMapper memberMapper; // MyBatis
的
mapper
對象
private CardMapper cardMapper;
// MyBatis
的
mapper
對象
@Override
public boolean isMemberExist(String phone) 
{
return memberMapper.findByPhone(phone);
}
@Override
public boolean saveMember(Member member) 
{
MemberPO memberPO = assembleMemberPO(member);
List<CardPO> cardPOList = assembleCardPO(member.getCards());
// 
在同一個事務(wù)中保存
MemberPO
和
CardPO
數(shù)據(jù)
memberMapper.save(memberPO);
cardMapper.saveAll(cardPOList);
return false;
}
private MemberPO assembleMemberPO(Member member)
{
// 
該方法把領(lǐng)域?qū)ο筠D(zhuǎn)換為數(shù)據(jù)庫存儲對象,此處省略代碼
}
private List<CardPO> assembleCardPO(List<Card> cards)
{
// 
該方法把領(lǐng)域?qū)ο筠D(zhuǎn)換為數(shù)據(jù)庫存儲對象,此處省略代碼
}
}

至此,我們利用 DDD 工具實現(xiàn)了會員系統(tǒng)中的會員注冊用例。通過這種方式編寫的代碼,不僅整潔清晰,完整體現(xiàn)了設(shè)計模型,還能追溯到對應(yīng)的需求分析,從而確保了實現(xiàn)與設(shè)計的一致性。

整潔架構(gòu)實踐總結(jié)

本文在對歷史遺留系統(tǒng)問題深入分析后,找到問題的本質(zhì)解,制定切實有效的解決方案。通過運用整潔架構(gòu)設(shè)計理念,對歷史遺留系統(tǒng)進行全面的模型分析和架構(gòu)重新設(shè)計,并借助DDD戰(zhàn)術(shù)工具實現(xiàn)代碼開發(fā)。在此過程中,整個團隊嚴(yán)格保持統(tǒng)一的代碼風(fēng)格,從而使歷史遺留系統(tǒng)煥然一新,變得整潔、清晰且易于維護。這不僅顯著提升了系統(tǒng)的可讀性和可擴展性,還為未來的功能開發(fā)和系統(tǒng)升級奠定了堅實基礎(chǔ)。

責(zé)任編輯:武曉燕 來源: 君哥聊技術(shù)
相關(guān)推薦

2024-06-19 09:38:05

2019-03-13 09:27:57

宕機Kafka數(shù)據(jù)

2021-04-21 14:56:28

負(fù)載均衡高并發(fā)優(yōu)化技術(shù)架構(gòu)

2018-01-09 09:45:02

秒級監(jiān)控阿里

2020-01-13 08:43:20

Elasticsear分布式搜索

2021-05-19 20:41:23

日志檢索系統(tǒng)

2020-09-01 07:49:14

JVM流量系統(tǒng)

2009-07-06 15:05:23

2022-05-19 09:31:50

Kafka 集群數(shù)據(jù)存儲服務(wù)端

2019-10-25 09:28:12

算法設(shè)計操作系統(tǒng)

2020-10-22 15:55:06

數(shù)據(jù)分析架構(gòu)索引

2019-12-25 09:10:44

技術(shù)研發(fā)指標(biāo)

2019-12-25 10:17:53

騰訊Elasticsear開源

2018-05-21 09:15:06

Redis美團點評數(shù)據(jù)庫運維

2023-09-07 20:31:48

外灘大會螞蟻集團圖學(xué)習(xí)系統(tǒng)

2020-12-31 07:34:04

Redis數(shù)據(jù)宕機

2018-09-12 15:21:05

云宕機云計算數(shù)據(jù)中心

2018-05-28 08:20:12

服務(wù)器Redis優(yōu)化

2010-07-05 16:15:41

流量控制

2016-11-23 12:55:09

京東活動系統(tǒng)流量
點贊
收藏

51CTO技術(shù)棧公眾號

日本老师69xxx| 亚洲人成网站777色婷婷| 老司机av福利| 日韩有码第一页| 久热国产精品| 久久99亚洲精品| 国产精品久久综合| 日本成人精品在线| 91成人福利视频| 自拍偷拍一区| 日韩欧美在线123| 日韩视频免费在线播放| av片在线观看免费| 国产农村妇女毛片精品久久麻豆 | 日韩视频免费观看高清| av一区二区高清| 亚洲国产精品久久久| 欧美三级理论片| 国产传媒av在线| 亚洲视频你懂的| 日本精品视频一区| 天堂中文在线资源| 狠狠色丁香九九婷婷综合五月| 45www国产精品网站| 麻豆精品一区二区三区视频| 精品国产一区二区三区小蝌蚪| 日韩精品中文字幕一区| 依人在线免费视频| 黑人巨大精品| 无码av免费一区二区三区试看 | 91精品一区二区三区久久久久久| 久久精品免费一区二区| 国产精品国精产品一二| 亚洲欧美日韩成人高清在线一区| 日本不卡一区| 日av在线播放| wwww国产精品欧美| 精品中文字幕人| 亚洲av综合色区无码一二三区| 蜜臀av性久久久久av蜜臀妖精| 欧洲成人在线观看| 黄色片免费观看视频| 亚洲高清自拍| 欧美大秀在线观看| 久草视频在线免费看| 久久精品高清| www.精品av.com| 香蕉成人在线视频| 国产精品久久久久久久久久久久久久久久| 亚欧洲精品视频在线观看| 欧美成人vps| 91香蕉国产线在线观看| 粉嫩一区二区三区在线观看| 欧美日韩高清一区| 女同激情久久av久久| 久久精品 人人爱| 欧美熟乱第一页| 中文字幕国内自拍| 欧美性生活一级| 欧美一区二区三区的| 伊人成人免费视频| 一区二区免费| 亚洲成人av片在线观看| 国产熟女高潮一区二区三区| 午夜精品影视国产一区在线麻豆| 精品无码久久久久久国产| av女人的天堂| 日韩精品免费一区二区在线观看| 中文字幕成人在线| 日本精品在线免费观看| 女生裸体视频一区二区三区| 欧美精品福利在线| 国产精品久久久久久久久久久久久久久久久 | 天天色综合天天色| 国产一区二区高清在线| 精品精品国产高清a毛片牛牛 | 毛葺葺老太做受视频| 日韩av超清在线观看| 欧美精品久久99久久在免费线| 欧美一级免费在线| 久久影视三级福利片| 亚洲色图第一页| 国产精品白丝喷水在线观看| 国产精品黄色| 国产99久久精品一区二区 夜夜躁日日躁 | 午夜日韩在线| 91高潮精品免费porn| 成人黄色三级视频| 懂色av中文一区二区三区| 麻豆一区区三区四区产品精品蜜桃| 国产精品视频一区二区久久| 亚洲美女屁股眼交| 无罩大乳的熟妇正在播放| 成人性片免费| 亚洲精品国产精品国自产在线| 欧美特级黄色录像| 欧美aa国产视频| 国产成人一区二| 亚洲av无码专区在线| 国产日产欧美一区二区三区| 国产乱子伦精品视频| 波多视频一区| 欧美va亚洲va国产综合| 色噜噜噜噜噜噜| 日韩午夜精品| 成人深夜直播免费观看| 神马久久久久| 一区二区三区国产| 午夜精品在线免费观看| 国产精品玖玖玖在线资源| 日韩在线免费观看视频| 日本一区二区免费在线观看| 久久精品久久精品| 欧美1o一11sex性hdhd| 青青草原av在线| 欧美日韩在线亚洲一区蜜芽| 疯狂揉花蒂控制高潮h| 女主播福利一区| 成人黄色激情网| 国产系列在线观看| 日韩欧美黄色动漫| 国产+高潮+白浆+无码| 一区二区三区毛片免费| 国产成人精品最新| 神马电影在线观看| 亚洲第一搞黄网站| 成年人性生活视频| 国产精品99一区二区三区| 国产成人综合精品| 免费在线观看污视频| 污片在线观看一区二区| 中文字幕第九页| 综合激情网站| 91网站在线看| 欧美边添边摸边做边爱免费| 色综合久久88色综合天天6| 免费黄色三级网站| 亚洲大黄网站| av一区二区在线看| 日本三级在线观看网站| 日韩无一区二区| 任我爽在线视频| 精品写真视频在线观看| 亚洲一区二区三区免费观看| 岛国一区二区| www.美女亚洲精品| 国产精品久久久久久久久毛片 | 国产福利一区在线| 国产精品啪啪啪视频| 国产专区精品| 久久99精品久久久久久琪琪| 国产suv一区二区| 亚洲精品国产无套在线观| 九九九久久久久久久| 女人天堂亚洲aⅴ在线观看| 99久久精品无码一区二区毛片| a级影片在线| 亚洲成人精品久久久| 成人精品在线看| 久久久精品国产免费观看同学| 久久精品99国产| 日本成人小视频| 91欧美视频网站| 四虎亚洲成人| 亚洲精品久久久久久久久| 国产成人无码一区二区在线播放| 久久精品夜色噜噜亚洲aⅴ| 中国黄色片免费看| 夜间精品视频| 精品视频高清无人区区二区三区| 天天综合av| 在线视频精品一| 国产尤物视频在线观看| 亚洲综合一二区| 亚洲国产欧美视频| 老汉av免费一区二区三区| 女人床在线观看| 日韩精品导航| 国产欧美日韩视频| 精品精品导航| 亚洲天堂免费观看| 国产老妇伦国产熟女老妇视频| 亚洲一区二区精品3399| 国产jk精品白丝av在线观看| 精品一区二区三区免费| 国内精品视频一区二区三区| 欧美日韩激情| 成人av男人的天堂| 自拍偷自拍亚洲精品被多人伦好爽| 日韩最新免费不卡| 色窝窝无码一区二区三区成人网站| 色老头久久综合| 久久久91视频| 久久精品人人做| 亚洲成a人无码| 日本特黄久久久高潮| 五月天激情图片| 欧美美女一区| 九色综合日本| 欧美视频二区欧美影视| 国产精品扒开腿做爽爽爽男男| av网站免费在线观看| 亚洲一二在线观看| 六月丁香综合网| 欧美精品亚洲一区二区在线播放| 亚洲欧美在线观看视频| 自拍偷自拍亚洲精品播放| 毛片网站免费观看| 粉嫩嫩av羞羞动漫久久久| 中日韩av在线播放| 久久久久一区| 女人喷潮完整视频| 欧美日韩一区二区高清| 一本一生久久a久久精品综合蜜 | 免费网站在线观看视频| 日韩电影在线视频| 日本一区二区精品| 国产精品久久久久av蜜臀| 亚洲伊人第一页| 日本久久二区| 国产精品直播网红| 成人免费av电影| 欧美在线视频一区二区| 久久五月精品中文字幕| 久久久精品网站| yw193.com尤物在线| 日韩av在线天堂网| 午夜福利视频一区二区| 精品久久五月天| 精品国产av 无码一区二区三区| 欧美日韩免费视频| 日本精品入口免费视频| 欧美性猛交xxxx富婆| 1级黄色大片儿| 亚洲电影激情视频网站| 久久久久久久国产精品毛片| 亚洲精品一卡二卡| 日本精品人妻无码77777| 自拍偷拍欧美激情| 四虎地址8848| 亚洲欧美日韩国产手机在线| 三上悠亚在线观看视频| 中文字幕一区二区三区在线不卡 | 色的视频在线免费看| 亚洲最新av在线网站| jzzjzzjzz亚洲成熟少妇| 亚洲天堂网站在线观看视频| 国产小视频在线观看| 亚洲人成网站777色婷婷| 超碰国产在线| 中文综合在线观看| 国产在线看片| 欧美国产精品人人做人人爱| 波多野结衣乳巨码无在线观看| 欧美精品福利在线| 深夜av在线| 国产成人精品av在线| 性欧美freehd18| 国产欧美日韩综合精品| 高清久久精品| 国产高清在线一区二区| 卡通动漫国产精品| 免费精品视频一区| 青青草成人影院| 在线观看成人免费| 亚洲三级影院| 日韩av播放器| 国产精品自产自拍| 国产 xxxx| 国产日产欧美一区二区三区| 91狠狠综合久久久| 亚洲一区二区黄色| 午夜精品久久久久久久蜜桃| 欧美人与z0zoxxxx视频| 性生活视频软件| 亚洲区一区二区| 国产不卡在线| 欧美中文字幕在线播放| 日韩成人一区| 国内精品**久久毛片app| 精品影片在线观看的网站| 一区二区不卡在线| 国产日韩欧美一区在线| jizz欧美性11| 成人精品国产免费网站| 懂色av蜜桃av| 亚洲大片精品永久免费| 欧美特级黄色片| 日韩欧美在线网站| 国产系列电影在线播放网址| 欧美另类在线播放| 精品欧美一区二区三区在线观看| 91午夜在线播放| 久久综合欧美| 大西瓜av在线| 老司机午夜精品| 亚洲蜜桃精久久久久久久久久久久| 中文字幕av资源一区| 日本在线视频中文字幕| 欧美日韩精品三区| 午夜在线视频免费| 久久在线免费观看视频| 毛片无码国产| 国产欧美一区二区视频| 99久久www免费| 国产激情在线观看视频| 成人免费视频视频| 永久免费看片直接| 色婷婷精品久久二区二区蜜臀av| 国产高清不卡视频| 一区二区中文字幕| 日本不卡1234视频| 99re6在线| 久久精品青草| 国产一级做a爰片久久| 91视频国产资源| 久久久久噜噜噜亚洲熟女综合| 欧美日韩成人在线一区| 精品福利视频导航大全| 69久久夜色精品国产69乱青草| 欧美1区2区3| 性欧美18一19内谢| 日本成人中文字幕在线视频 | 精品国产无码一区二区| 国产一区二区三区四区福利| 少妇视频一区| 好吊妞www.84com只有这里才有精品| 午夜国产一区二区| 中文字幕av不卡在线| 久久精品一区二区三区av| 一级免费在线观看| 亚洲精品电影在线| tube8在线hd| 国产日韩欧美精品| 在线看片日韩| 国产精品手机在线观看| 亚洲国产精品一区二区久久恐怖片 | 狠狠色伊人亚洲综合成人| 综合 欧美 亚洲日本| 欧美天堂一区二区三区| 91精品人妻一区二区三区蜜桃2 | 黄页网站大全在线免费观看| 成人国产精品日本在线| 99re6这里只有精品| 欧美大尺度做爰床戏| 中文字幕一区免费在线观看| 欧美另类高清videos的特点| 在线播放国产一区二区三区| 欧美日韩不卡| 亚洲国产一区二区三区在线播| 免费观看久久久4p| 欧美一级特黄高清视频| 91精品中文字幕一区二区三区| 福利视频在线| 国产高清一区二区三区| 国产精品女主播一区二区三区| 国产伦精品一区二区三区妓女| 日韩欧美高清视频| аⅴ资源新版在线天堂| 91精品久久久久久久久青青| 偷偷www综合久久久久久久| 999热精品视频| 亚洲一二三四区| 污污视频在线观看网站| 国产成人一区三区| 亚洲九九在线| 国产人妻黑人一区二区三区| 欧美三级免费观看| 99视频在线观看地址| 亚洲自拍偷拍视频| 亚洲精品护士| 农村老熟妇乱子伦视频| 日韩午夜在线播放| а√天堂8资源在线| 欧美一区二区三区四区五区六区| 日本怡春院一区二区| 欧美成人片在线观看| 亚洲毛茸茸少妇高潮呻吟| 国产福利91精品一区二区| 91网站在线观看免费| 2022国产精品视频| 97免费观看视频| 97高清免费视频| 日韩免费在线| 亚洲欧美一区二区三区不卡| 天天影视涩香欲综合网 | 久久久久久久久久久久久久久久久久av | 日韩av网站在线播放| 精品精品欲导航| 国产91亚洲精品久久久| 老司机激情视频| 欧美国产亚洲另类动漫| 亚洲av综合色区无码一二三区| 国产精品成久久久久三级| 欧美欧美天天天天操| 精品国产成人亚洲午夜福利| 日韩欧美一级二级| 欧美日韩尤物久久| 国产欧美日韩网站| 亚洲视频图片小说|