日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

界限上下文识别

發(fā)布時間:2023/12/14 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 界限上下文识别 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

限界上下文就是“邊界”,這與面向?qū)ο笤O(shè)計中的職責分配其實是同一道理。限界上下文的識別并不是一蹴而就的,需要演化和迭代,結(jié)合著我對限界上下文的理解,我認為通過從業(yè)務(wù)邊界到工作邊界再到應(yīng)用邊界這三個層次抽絲剝繭,分別以不同的視角、不同的角色協(xié)作來運用對應(yīng)的設(shè)計原則,會是一個可行的識別限界上下文的過程方法。當然,這個過程相對過重,如果僅以此作為輸出限界上下文的方法,未免有些得不償失。需要說明的是,這個過程除了能夠幫助我們更加準確地識別限界上下文之外,還可以幫助我們分析需求、識別風險、確定架構(gòu)方案。整體過程如下圖所示:

?業(yè)務(wù)邊界識別限界上下文

領(lǐng)域驅(qū)動設(shè)計圍繞著“領(lǐng)域”來開展軟件設(shè)計。在明確了系統(tǒng)的問題域和業(yè)務(wù)期望后,開發(fā)團隊與領(lǐng)域?qū)<医?jīng)過充分地溝通與交流,可以梳理出主要的業(yè)務(wù)流程,這些業(yè)務(wù)流程體現(xiàn)了各種參與者在這個過程中通過業(yè)務(wù)活動共同協(xié)作,最終完成具有業(yè)務(wù)價值的領(lǐng)域功能。顯然,業(yè)務(wù)流程結(jié)合了參與角色(Who)、業(yè)務(wù)活動(What)和業(yè)務(wù)價值(Why)。在業(yè)務(wù)流程的基礎(chǔ)上,我們就可以抽象出不同的業(yè)務(wù)場景,這些業(yè)務(wù)場景又由多個業(yè)務(wù)活動組成,我們可以利用前面提到的領(lǐng)域場景分析方法剖析場景,以幫助我們識別業(yè)務(wù)活動,例如采用用例對場景進行分析,此時,一個業(yè)務(wù)活動實則就是一個用例。

例如,在針對一款文學(xué)閱讀產(chǎn)品進行需求分析時,我們得到的業(yè)務(wù)流程為:

登錄讀者根據(jù)作品名或者作者名查詢自己感興趣的作品。在找到自己希望閱讀的作品后,開始閱讀。若閱讀的作品為長篇,可以按照章節(jié)閱讀,倘若作品為收費作品,則讀者需要支付相應(yīng)的費用,支付成功后可以閱讀購買后的作品。在閱讀時,倘若讀者看到自己喜歡的句子或段落,可以作標記,也可以撰寫讀書筆記,還可以將自己喜歡的內(nèi)容分享給別的朋友。讀者可以對該作品和作者發(fā)表評論,關(guān)注自己喜歡的作品和作者。注冊用戶可以申請成為駐站作者。審核通過的作者可以在創(chuàng)作平臺上發(fā)布自己的作品,發(fā)布作品時,可以根據(jù)需要設(shè)置作品的章節(jié)。作者可以在發(fā)布作品之前預(yù)覽作品,無論作品是否已經(jīng)發(fā)布,都可以對作品的內(nèi)容進行修改。作者可以設(shè)置自己的作品為收費或免費作品,并自行確定閱讀作品所需的費用。如果是新作品發(fā)布,系統(tǒng)會發(fā)送消息通知該作者的關(guān)注者;若連載作品有新章節(jié)發(fā)布,系統(tǒng)會發(fā)送消息通知該作品的關(guān)注者。駐站作者可以為自己的作品建立作品讀者群,讀者可以申請加入該群,加入群的讀者與作者可以在線實時聊天,也可以發(fā)送離線信息,或者將自己希望分享的內(nèi)容發(fā)布到讀者群中。注冊用戶之間可以發(fā)起一對一的私聊,也可以直接給注冊用戶發(fā)送私信。通過對以上業(yè)務(wù)流程進行分析,結(jié)合在各個流程環(huán)節(jié)中需要的知識以及參與角色的不同,可以劃分如下業(yè)務(wù)場景:

閱讀作品創(chuàng)作作品支付社交消息通知注冊與登錄可以看到,業(yè)務(wù)流程是一個由多個用戶角色參與的動態(tài)過程,而業(yè)務(wù)場景則是這些用戶角色執(zhí)行業(yè)務(wù)活動的靜態(tài)上下文。從業(yè)務(wù)流程中抽象出來的業(yè)務(wù)場景可能是交叉重疊的,例如在讀者閱讀作品流程與作者創(chuàng)作流程中,都牽涉到支付場景的相關(guān)業(yè)務(wù)。

接下來,我們利用領(lǐng)域場景分析的用例分析方法剖析這些場景。我們往往通過參與者(Actor)來驅(qū)動對用例的識別,這些參與者恰好就是參與到場景業(yè)務(wù)活動的角色。根據(jù)用例描述出來的業(yè)務(wù)活動應(yīng)該與統(tǒng)一語言一致,最好直接從統(tǒng)一語言中擷取。業(yè)務(wù)活動的描述應(yīng)該精準地表達領(lǐng)域概念,且通過盡可能簡潔的方式進行描述,通常格式為動賓形式。以閱讀作品場景為例,可以包括如下業(yè)務(wù)活動:

查詢作品收藏作品關(guān)注作者瀏覽作品目錄閱讀作品標記作品內(nèi)容撰寫讀書筆記評價作品評價作者分享選中的作品內(nèi)容分享作品鏈接購買作品一旦準確地用統(tǒng)一語言描述出這些業(yè)務(wù)活動,我們就可以從如下兩個方面識別業(yè)務(wù)邊界,進而提煉出初步的限界上下文:

語義相關(guān)性功能相關(guān)性語義相關(guān)性

從語義角度去分析業(yè)務(wù)活動的描述,倘若是相同的語義,可以作為歸類的特征。語義相關(guān)性主要來自于描述業(yè)務(wù)活動的賓語。例如,前述業(yè)務(wù)活動中的查詢作品、收藏作品、分享作品、閱讀作品都具有“作品”的語義,基于這一特征,我們可以考慮將這些業(yè)務(wù)活動歸為同一類。

識別語義相關(guān)性的前提是準確地使用統(tǒng)一語言描述業(yè)務(wù)活動。在描述時,應(yīng)盡量避免使用“管理(manage)”或“維護(maintain)”等過于抽象的詞語。抽象的詞語容易讓我們忽視隱藏的領(lǐng)域語言,缺少對領(lǐng)域的精確表達。例如,在文學(xué)閱讀產(chǎn)品中,我們不能寬泛地寫出“管理作品”、“管理作者”、“維護支付信息”等業(yè)務(wù)活動,而應(yīng)該挖掘業(yè)務(wù)含義,只有如此才能得到諸如收藏作品、撰寫作品、發(fā)布作品、設(shè)置作品收費模式、查詢支付流水、對賬等符合領(lǐng)域知識的描述。當然,這里也有一個業(yè)務(wù)活動層次的問題。在進行業(yè)務(wù)分析時,若我們發(fā)現(xiàn)只能使用“管理”或“維護”之類的抽象字眼來表述該用戶活動時,則說明我們選定的用戶活動層次過高,應(yīng)該繼續(xù)細化。細化后的業(yè)務(wù)活動既能更好地表達領(lǐng)域知識,又能讓我們更好地按照語義相關(guān)性去尋找業(yè)務(wù)的邊界,可謂一舉兩得。

在進行語義相關(guān)性判斷時,還需要注意業(yè)務(wù)活動之間可能存在不同的語義相關(guān)性。例如,在文學(xué)閱讀產(chǎn)品中,查詢作品、閱讀作品與撰寫作品具有“作品”的語義相關(guān),而評價作品與評價作者又具有“評價”的語義相關(guān),究竟應(yīng)該以哪個語義為準呢?沒有標準!我們只能按照相關(guān)性的耦合程度進行判斷。如果我們將評價視為一個相對獨立的限界上下文,則評價作品與評價作者放入評價上下文會更好。

功能相關(guān)性

從功能角度去分析業(yè)務(wù)活動是否彼此關(guān)聯(lián)和依賴,倘若存在關(guān)聯(lián)和依賴,可以作為歸類的特征,這種關(guān)聯(lián)性,代表了功能之間的相關(guān)性。倘若兩個功能必須同時存在,又或者缺少一個功能,另一個功能是不完整的,則二者就是功能強相關(guān)的。通常,這種功能相關(guān)性極具有欺騙性,因為系統(tǒng)總是包含這樣那樣彼此依賴的功能。要判斷這種依賴關(guān)系的強弱,并不比分析人與人之間的關(guān)系簡單。倘若我們運用用例分析方法,就可以通過用例之間的關(guān)系來判別功能相關(guān)性,如用例的包含與擴展關(guān)系,其中包含關(guān)系展現(xiàn)了功能的強相關(guān)性。所謂“功能相關(guān)性”,指的就是職責的內(nèi)聚性,強相關(guān)就等于高內(nèi)聚。故而從這個角度看,功能相關(guān)性的判斷標準恰好符合“高內(nèi)聚、松耦合”的設(shè)計原則。

仍然以前面提到的文學(xué)閱讀產(chǎn)品為例。發(fā)布作品與驗證作品內(nèi)容是功能相關(guān)的,且屬于用例的包含關(guān)系,因為如果沒有對發(fā)布的作品內(nèi)容進行驗證,就不允許發(fā)布作品。對于這種強相關(guān)的功能,我們通常都會考慮將其歸入到同一個限界上下文。又例如發(fā)布作品與設(shè)置作品收費模式是功能相關(guān)的,但并非強相關(guān),因為設(shè)置作品收費模式并非發(fā)布作品的前置約束條件,屬于用例中的擴展關(guān)系。但由于二者還存在語義相關(guān)性,因而將其放入到同一個限界上下文中也是合理的。

兩個相關(guān)的功能未必一定屬于同一個限界上下文。例如,購買作品與支付購買費用是功能相關(guān)的,且前者依賴于后者,但后者從領(lǐng)域知識的角度判斷,卻應(yīng)該分配給支付上下文,我們非但不能將其緊耦合在一起,還應(yīng)該竭盡所能降低二者之間的耦合度。因此,我在識別限界上下文時,僅僅將“功能相關(guān)性”作為一種可行的參考,它并不可靠,卻能給你一些提醒。事實上,功能相關(guān)性往往會與上下文之間的協(xié)作關(guān)系有關(guān)。由于這種功能相關(guān)性恰恰對應(yīng)了用例之間的包含與擴展關(guān)系,它們往往又可成為識別限界上下文邊界的關(guān)鍵點。我在后面講解上下文映射時還會詳細闡釋。

為業(yè)務(wù)邊界命名

無論是語義相關(guān)性還是功能相關(guān)性,都是分類業(yè)務(wù)活動的一種判斷標準。一旦我們將識別出來的業(yè)務(wù)活動進行歸類,就自然而然地為它們劃定了業(yè)務(wù)邊界,接下來,我們需要對劃定的業(yè)務(wù)邊界進行命名,這個命名的過程其實就是識別所有業(yè)務(wù)活動共同特征,并以最準確地名詞來表達該特征。倘若我們劃分的業(yè)務(wù)活動欠妥當,對這個業(yè)務(wù)邊界命名就會成為一種巨大的挑戰(zhàn)。例如,我們從建立讀者群、加入讀者群,發(fā)布群內(nèi)消息、實時聊天、發(fā)送離線消息、一對一私聊與發(fā)送私信等業(yè)務(wù)活動找到“社交”的共同特征,因而得到社交上下文。但如果我們將閱讀作品、收藏作品與關(guān)注作者、查看作者信息放在一個業(yè)務(wù)邊界內(nèi),命名就變得有些棘手了,我們總不可能稱呼其為“作品與作者”上下文吧!因此,對業(yè)務(wù)邊界的命名可以算作是對限界上下文識別的一種檢驗手段。

整體而言,從業(yè)務(wù)邊界識別上下文的重點在于“領(lǐng)域”。若理解領(lǐng)域邏輯有誤,就可能影響限界上下文的識別。因此,這個階段需要開發(fā)團隊與領(lǐng)域?qū)<揖o密合作,這個階段也將是一個充分討論和分析的過程。它是一個迭代的過程。很多時候,如果我們沒有真正去實現(xiàn)這些限界上下文,我們有可能沒有完全正確地理解它。當我們距離真正理解業(yè)務(wù)還有距離的時候,不妨先“草率”地規(guī)劃它,待到一切都明朗起來,再尋機重構(gòu)。

從工作邊界識別限界上下文

正如架構(gòu)設(shè)計需要多個視圖來全方位體現(xiàn)架構(gòu)的諸多要素,我們也應(yīng)借助更多的角度全方位分析限界上下文。如果說為限界上下文劃分業(yè)務(wù)邊界,更多的是從業(yè)務(wù)相關(guān)性(內(nèi)聚)判斷業(yè)務(wù)的歸屬,那么基于團隊合作劃分工作邊界可以幫助我們確定限界上下文合理的工作粒度。

倘若我們認可第 3-2 課中提及的三個原則或?qū)嵺`:2PTs 規(guī)則、特性團隊、康威定律,則意味著項目經(jīng)理需要將一個限界上下文要做的工作分配給大約 7~10 人的特性團隊。如此看來,對限界上下文的粒度識別就變成了對工作量的估算。我們并沒有嚴謹?shù)乃惴ㄈ蚀_估算工作量,可是對于一個有經(jīng)驗的項目經(jīng)理(或者技術(shù)負責人),要進行工作量的大致估算,還是能夠辦到的。當我們發(fā)現(xiàn)一個限界上下文過大,又或者特性團隊的工作分配不均勻時,就應(yīng)該果斷對已有限界上下文進行切分。

工作分配的基礎(chǔ)在于“盡可能降低溝通成本”,遵循康威定律,溝通其實就是項目模塊之間的依賴,這個過程同樣不是一蹴而就的。康威認為:

在大多數(shù)情況下,最先產(chǎn)生的設(shè)計都不是最完美的,主導(dǎo)的系統(tǒng)設(shè)計理念可能需要更改。因此,組織的靈活性對于有效的設(shè)計有著舉足輕重的作用,必須找到可以鼓勵設(shè)計經(jīng)理保持他們的組織精簡與靈活的方法。

特性團隊正是用來解決這一問題的。換言之,當我們發(fā)現(xiàn)團隊規(guī)模越來越大,失去了組織精簡與靈活的優(yōu)勢,實際上就是在傳遞限界上下文過大的信號。項目經(jīng)理對此需要有清醒認識,當團隊規(guī)模違背了 2PTs 時,就該坐下來討論一下如何細分團隊的問題了。因此,按照團隊合作的角度劃分限界上下文,其實是一個動態(tài)的過程、演進的過程。

我在給某音樂網(wǎng)站進行領(lǐng)域驅(qū)動設(shè)計時,通過識別業(yè)務(wù)相關(guān)性劃分了如下限界上下文。

Media Player(online & offline):提供音頻和視頻文件的播放功能,區(qū)分在線播放與離線播放;Music:與音樂相關(guān)的業(yè)務(wù),包括樂庫、歌單、歌詞;FM Radio:電臺;Live:直播;MV:短視頻和 MV;Singer:歌手;Musician:音樂人,注意音樂人與歌手的區(qū)別;Music Community:音樂社區(qū);File Sharing:包括下載和傳歌等與文件有關(guān)的功能;Tag:支持標簽管理,包括音樂的分類如最新、話題等分類標簽還有歌曲標簽;Loyalty:與提高用戶粘度有關(guān)的功能,如關(guān)注、投票、收藏、歌單等功能;Utilities:音樂工具,包括音效增強等功能;Recommendation:推薦;Search:對整個音樂網(wǎng)站內(nèi)容的搜索,包括對人、歌曲、視頻等內(nèi)容的搜索;Activity:音樂網(wǎng)站組織的活動;Advertisement:推廣與廣告;Payment:支付。在識別限界上下文時,我將直播(Live)視為與音樂、電臺、MV 短視頻同等層次的業(yè)務(wù)分類,然而,殊不知該音樂網(wǎng)站直播模塊的開發(fā)團隊已經(jīng)隨著功能的逐漸增強發(fā)展到了接近 200 人規(guī)模的大團隊,這顯然不是一個限界上下文邊界可以控制的規(guī)模。即使屬于直播業(yè)務(wù)的業(yè)務(wù)活動都與直播領(lǐng)域知識有關(guān),我們也應(yīng)該基于 2PTs 原則對直播限界上下文作進一步分解,以滿足團隊管理以及團隊成員充分溝通的需要。

如果我們從團隊合作層面看待限界上下文,就從技術(shù)范疇上升到了管理范疇。Jurgen Appelo 在《管理 3.0:培養(yǎng)和提升敏捷領(lǐng)導(dǎo)力(Management 3.0: Leading Agile Developers,Developing Agile Leaders)》這本書中提到,一個高效的團隊需要滿足兩點要求:

共同的目標團隊的邊界

雖然 Jurgen Appelo 在提及邊界時,是站在團隊結(jié)構(gòu)的角度來分析的;可在設(shè)計團隊組織時確定工作邊界的原則,恰恰與限界上下文的控制邊界暗暗相合。總結(jié)書中對邊界的闡釋,大致包括:

團隊成員應(yīng)對團隊的邊界形成共識,這就意味著團隊成員需要了解自己負責的限界上下文邊界,以及該限界上下文如何與外部的資源以及其他限界上下文進行通信。團隊的邊界不能太封閉(拒絕外部輸入),也不能太開放(失去內(nèi)聚力),即所謂的“滲透性邊界”,這種滲透性邊界恰恰與“高內(nèi)聚、松耦合”的設(shè)計原則完全契合。針對這種“滲透性邊界”,團隊成員需要對自己負責開發(fā)的需求“抱有成見”,在識別限界上下文時,“任勞任怨”的好員工并不是真正的好員工。一個好的員工明確地知道團隊的職責邊界,他應(yīng)該學(xué)會勇于承擔屬于團隊邊界內(nèi)的需求開發(fā)任務(wù),也要敢于推辭職責范圍之外強加于他的需求。通過團隊每個人的主觀能動,就可以漸漸地形成在組織結(jié)構(gòu)上的“自治單元”,進而催生出架構(gòu)設(shè)計上的“自治單元”。同理,“任勞任怨”的好團隊也不是真正的好團隊,團隊對自己的邊界已經(jīng)達成了共識,為什么還要違背這個共識去承接不屬于自己邊界內(nèi)的工作呢?這并非團隊之間的“惡性競爭”,也不是工作上的互相推諉;恰恰相反,這實際上是一種良好的合作,表面上維持了自己的利益,然而在一個組織下,如果每個團隊都以這種方式維持自我利益,反而會形成一種“互利主義”。

這種“你給我搔背,我也替你抓抓癢”的互利主義最終會形成團隊之間的良好協(xié)作。如果團隊領(lǐng)導(dǎo)者與團隊成員能夠充分認識到這一點,就可以從團隊層面思考限界上下文。此時,限界上下文就不僅僅是架構(gòu)師局限于一孔之見去完成甄別,而是每個團隊成員自發(fā)組織的內(nèi)在驅(qū)動力。當每個人都在思考這項工作該不該我做時,變相地就是在思考職責的分配是否合理,限界上下文的劃分是否合理。

從應(yīng)用邊界識別限界上下文

質(zhì)量屬性

管理的目的在于打造高效的團隊,但最后還是要落腳到技術(shù)實現(xiàn)上來,不懂業(yè)務(wù)分析的架構(gòu)師不是一個好的程序員,而一個不懂得提前識別系統(tǒng)風險的程序員更不是一個好的架構(gòu)師。站在技術(shù)層面上看待限界上下文,我們需要關(guān)注的其實是質(zhì)量屬性(Quality Attributes)。如果把關(guān)乎質(zhì)量屬性的問題都視為在將來可能會發(fā)生,其實就是“風險(Risk)”。

架構(gòu)是什么?Martin Fowler 認為:架構(gòu)是重要的東西,是不容易改變的決策。如果我們未曾預(yù)測到系統(tǒng)存在的風險,不幸它又發(fā)生了,帶給系統(tǒng)架構(gòu)的改變可能是災(zāi)難性的。利用限界上下文的邊界,就可以將這種風險帶來的影響控制在一個極小的范圍,這也是前面提及的安全。為什么說限界上下文是領(lǐng)域驅(qū)動設(shè)計中最重要的元素,答案就在這里。

我曾經(jīng)負責開發(fā)一款基于大數(shù)據(jù)平臺的 BI 產(chǎn)品,在架構(gòu)設(shè)計時,對性能的評估方案是存在問題的,我們當時考慮了符合生產(chǎn)規(guī)模的數(shù)據(jù)量,并以一個相對可行的硬件與網(wǎng)絡(luò)環(huán)境,對 Spark + Parquet 的技術(shù)選型進行測試,測試結(jié)果滿足了設(shè)定的響應(yīng)時間值。然而,兩個因素的缺失為我們的架構(gòu)埋下了禍根。在測試時,我們沒有考慮并發(fā)訪問量,測試的業(yè)務(wù)場景也過于簡單。我們懷著一種鴕鳥心態(tài),在理論上分析這種決策(Spark 是當時最快速的基于內(nèi)存的數(shù)據(jù)分析平臺,Parquet 是列式存儲,尤為適合統(tǒng)計分析)是對的,然后就按照我們期望的形式去測試,實際上是將風險悄悄地埋藏起來。

當產(chǎn)品真正銷售給客戶使用時,我們才發(fā)現(xiàn)客戶的業(yè)務(wù)場景非常復(fù)雜,對性能的要求也更加苛刻。例如,它要求達到 100 ~ 500 的并發(fā)訪問量,同時對大數(shù)據(jù)量進行統(tǒng)計分析與指標運算,并期望實時獲得分析結(jié)果;而客戶所能提供的 Spark 集群卻是有限度的。事實上,基于 Spark 的 driver-worker 架構(gòu),它本身并不擅長完成高并發(fā)的數(shù)據(jù)分析任務(wù)。對于一個分析任務(wù),Spark 可以利用集群的力量由多個 worker 同時并行地執(zhí)行成百上千的 task,但瓶頸在 driver 端,一旦上游同時有多個請求涌入,響應(yīng)能力就不足了。最終,我們的產(chǎn)品在真正的壓力測試下一敗涂地。

幸而,我們劃定了限界上下文,并由此建立了數(shù)據(jù)分析微服務(wù)。針對客戶高并發(fā)的實時統(tǒng)計分析需求,在保證 REST API 不變的情況下,我們更改了技術(shù)選型,選擇基于 ElasticSearch 的數(shù)據(jù)分析微服務(wù)替換舊服務(wù)。這種改變幾乎不影響產(chǎn)品的其他模塊與功能,前端代碼僅僅做了少量修改。3 個人的團隊在近一個月的周期內(nèi)基本完成了這部分數(shù)據(jù)分析功能,及時掐斷了炸藥的導(dǎo)火線。

重用和變化

無論是重用領(lǐng)域邏輯還是技術(shù)實現(xiàn),都是在設(shè)計層面上我們必須考慮的因素,需求變化更是影響設(shè)計策略的關(guān)鍵因素。我在前面分析限界上下文的本質(zhì)時,就提及一個限界上下文其實是一個“自治”的單元。基于自治的四個特征,我們也可以認為這個自治的單元其實就是邏輯重用和封裝變化的設(shè)計單元。這時,對限界上下文邊界的考慮,更多是出于技術(shù)設(shè)計因素,而非業(yè)務(wù)因素。在后面講解的上下文映射(Context Map)模式時,Eric Evans 總結(jié)的共享內(nèi)核其實就是重用的體現(xiàn),而開放主機服務(wù)與防腐層則是對變化的主動/被動應(yīng)對。

運用重用原則分離出來的限界上下文往往對應(yīng)于子領(lǐng)域(Sub Domain),尤其作為支撐子領(lǐng)域。我在為一家公司的物流聯(lián)運管理系統(tǒng)提供領(lǐng)域驅(qū)動設(shè)計咨詢時,通過與領(lǐng)域?qū)<业臏贤?#xff0c;我注意到他在描述運輸、貨站以及堆場的相關(guān)業(yè)務(wù)時,都提到了作業(yè)和指令的概念。雖然屬于不同的領(lǐng)域,但指令的收發(fā)、作業(yè)的制訂與調(diào)度都是相同的,區(qū)別只在于作業(yè)與指令的內(nèi)容,以及作業(yè)調(diào)度的周期。為了避免在運輸、貨站與堆場各自的限界上下文中重復(fù)設(shè)計與實現(xiàn)作業(yè)與指令等領(lǐng)域模型,我們可以將作業(yè)與指令單獨劃分到一個專門的限界上下文中。它作為上游限界上下文,提供對運輸、貨站與堆場的業(yè)務(wù)支撐。

限界上下文對變化的應(yīng)對,其實是“單一職責原則”的體現(xiàn),即一個限界上下文不應(yīng)該存在兩個引起它變化的原因。還是這個物流聯(lián)運管理系統(tǒng),最初團隊的設(shè)計人員將運費計算與賬目、結(jié)賬等功能放在了財務(wù)上下文中。當國家的企業(yè)征稅策略發(fā)生變化時,會引起財務(wù)上下文的變化,引起變化的原因是財務(wù)規(guī)則與政策的調(diào)整。倘若運費計算的規(guī)則也發(fā)生了變化,同樣會引起財務(wù)上下文的變化,但引起變化的原因卻是物流運輸?shù)臉I(yè)務(wù)需求。如果我們將運費計算單獨從財務(wù)上下文中分離出來,就可以獨立演化,符合前面提及的“自治”原則,實現(xiàn)了兩種不同關(guān)注點的分離。

遺留系統(tǒng)

自治原則的唯一例外是遺留系統(tǒng),因為領(lǐng)域驅(qū)動設(shè)計建議的通常做法是將整個遺留系統(tǒng)視為一個限界上下文。那么,什么是遺留系統(tǒng)?根據(jù)維基百科的定義,它是一種舊的方法、舊的技術(shù)、舊的計算機系統(tǒng)或應(yīng)用程序,這個定義并不能解釋遺留系統(tǒng)的真相。我認為,系統(tǒng)之所以成為遺留系統(tǒng),關(guān)鍵在于知識的缺乏。文檔不夠全面真實,掌握系統(tǒng)知識的團隊成員泰半離開,系統(tǒng)的代碼可能是一個大泥團。因此,我對遺留系統(tǒng)的定義是“一個還在運行和使用,但已步入軟件生命衰老期的缺乏足夠知識的軟件系統(tǒng)”。

倘若運用領(lǐng)域驅(qū)動設(shè)計的系統(tǒng)要與這樣一個遺留系統(tǒng)打交道,應(yīng)該怎么辦?竊以為,粗暴地將整個遺留系統(tǒng)包裹在一個限界上下文中,未免太理想化和簡單化了。要點還是自治,這時候我們應(yīng)該站在遺留系統(tǒng)的調(diào)用者來觀察它,考慮如何與遺留系統(tǒng)集成,然后逐步對遺留系統(tǒng)進行抽取與遷移,形成自治的限界上下文。

在這個過程中,我們可以借鑒技術(shù)棧遷移中常常運用的“抽象分支(Branch By Abstraction)”手法。該手法會站在消費者(Consumer)一方觀察遺留系統(tǒng),找到需要替換的單元(組件);然后對該組件進行抽象,從而將消費者與遺留系統(tǒng)中的實現(xiàn)解耦。最后,提供一個完全新的組件實現(xiàn),在保留抽象層接口不變的情況下替換掉遺留系統(tǒng)的舊組件,達到技術(shù)棧遷移的目的:

如上圖所示的抽象層,本質(zhì)就是后面我們要提到的“防腐層(Anticorruption Layer)”,通過引入這么一個間接層來隔離與遺留系統(tǒng)之間的耦合。這個防腐層往往是作為下游限界上下文的一部分存在。若有必要,也可以單獨為其創(chuàng)建一個獨立的限界上下文。

設(shè)計驅(qū)動力

結(jié)合業(yè)務(wù)邊界、工作邊界和應(yīng)用邊界,形成一種層層推進的設(shè)計驅(qū)動力,可以讓我們對限界上下文的設(shè)計變得更加準確,邊界的控制變得更加合理,畢竟,限界上下文的識別對于整個系統(tǒng)的架構(gòu)至關(guān)重要。在領(lǐng)域驅(qū)動的戰(zhàn)略設(shè)計階段,如果我們對識別出來的限界上下文的準確性還心存疑慮,那么比較實際的做法是保持限界上下文一定的粗粒度。倘若覺得功能的邊界不好把握分寸,可以考慮將這些模棱兩可的功能放在同一個限界上下文中。待到該限界上下文變得越來越龐大,以至于一個 2PTs 團隊無法完成交付目標;又或者該限界上下文的功能各有不同的質(zhì)量屬性要求;要么就是因為重用或變化,使得我們能夠更清楚地看到分解的必要性;此時我們再對該限界上下文進行分解,就會更加有把握。這是設(shè)計的實證主義態(tài)度。

通過以上過程去識別限界上下文,僅僅是一種對領(lǐng)域問題域的靜態(tài)劃分,我們還缺少另外一個重要的關(guān)注點,即:限界上下文之間是如何協(xié)作的?倘若限界上下文識別不合理,協(xié)作就會變得更加困難,尤其當一個限界上下文對應(yīng)一個微服務(wù)時,協(xié)作成本更會顯著增加。反過來,當我們發(fā)現(xiàn)彼此協(xié)作存在問題時,說明限界上下文的劃分出現(xiàn)了問題,這算是對識別限界上下文的一種驗證方法。Eric Evans 將這種體現(xiàn)限界上下文協(xié)作方式的要素稱之為“上下文映射(Context Map)”。

理解限價上下文

一個軟件系統(tǒng)通常被分為多個限界上下文,這是運用“分而治之”思想來降低業(yè)務(wù)復(fù)雜度的有效手段,設(shè)計的難題往往會停留在“如何分”,然而限界上下文之間的“怎么合”問題同樣值得關(guān)注,分與合遵循的還是軟件設(shè)計的最高原則——高內(nèi)聚、松耦合。分是合的基礎(chǔ),基于內(nèi)聚相關(guān)度進行合理的分配,可以在一定程度減少限界上下文之間不必要的關(guān)聯(lián)。假設(shè)分配是合理的,則接下來的“合”就是要盡可能地降低彼此之間的耦合。

既然前面提及限界上下文的識別是一個迭代過程,當我們在思考限界上下文該如何協(xié)作時,倘若發(fā)現(xiàn)協(xié)作總有不合理之處,就可能會是一個“設(shè)計壞味道”的信號,它告訴我們:之前識別的限界上下文或有不妥,由是可以審視之前的設(shè)計,進而演進為更為準確的限界上下文劃分。即使拋開對設(shè)計的促進作用,思考限界上下文是如何協(xié)作的,仍然格外重要,我們既要小心翼翼地維護限界上下文的邊界,又需要它們彼此之間良好的協(xié)作,并思考協(xié)作的具體實現(xiàn)方式,這個思考過程既牽涉到邏輯架構(gòu)層面,又與物理架構(gòu)有關(guān),足以引起我們的重視。

領(lǐng)域驅(qū)動設(shè)計通過上下文映射(Context Map) 來討論限界上下文之間的協(xié)作問題,上下文映射是一種設(shè)計手段,Eric Evans 總結(jié)了諸如共享內(nèi)核(Shared Kernel)、防腐層(Anticorruption Layer)、開放主機服務(wù)(Open Host Service)等多種模式。由于上下文映射本質(zhì)上是與限界上下文一脈相承的,因此要掌握這些協(xié)作模式,應(yīng)該從限界上下文的角度進行理解,著眼點還是在于“邊界”。領(lǐng)域驅(qū)動設(shè)計認為:上下文映射是用于將限界上下文邊界變得更清晰的重要工具。所以當我們正在為一些限界上下文的邊界劃分而左右為難時,不妨先放一放,在定下初步的限界上下文后,通過繪制上下文映射來檢驗,或許會有意外收獲。

限界上下文的一個核心價值,就是利用邊界來約束不同上下文的領(lǐng)域模型,以保證模型的一致性。然而,每個限界上下文都不是獨立存在的,多數(shù)時候,都需要多個限界上下文通力協(xié)作,才能完成一個完整的用例場景。例如,客戶之于商品、商品之于訂單、訂單之于支付,貫穿起來才能完成“購買商品”的核心流程。

兩個限界上下文之間的關(guān)系是有方向的,領(lǐng)域驅(qū)動設(shè)計使用兩個專門的術(shù)語來表述它們:“上游(Upstream)”和“下游(Downstream)”,在上下文映射圖中,以 U 代表上游,D 代表下游,理解它們之間的關(guān)系,正如理解該術(shù)語隱喻的河流,自然是上游產(chǎn)生的變化會影響到下游,反之則不然。故而從上游到下游的關(guān)系方向,代表了影響產(chǎn)生的作用力,影響作用力的方向與程序員慣常理解的依賴方向恰恰相反,上游影響了下游,意味著下游依賴于上游。

在劃分限界上下文的業(yè)務(wù)邊界時,我們常常從“語義相關(guān)性”與“功能相關(guān)性”兩個角度去判別職責劃分的合理性。在上下文映射中,我發(fā)現(xiàn)之所以兩個業(yè)務(wù)邊界的限界上下文能產(chǎn)生上下游協(xié)作關(guān)系,皆源于二者的功能相關(guān)性,這種功能相關(guān)存在主次之分,往往是上游限界上下文作為下游限界上下文的功能支撐,這就意味著在當前的協(xié)作關(guān)系下,下游限界上下文中的用例才是核心領(lǐng)域。例如,訂單與支付,下訂單用例才是核心功能,支付功能作為支撐的公開服務(wù)而被調(diào)用;例如,郵件與文件共享,寫郵件用例才是核心功能,上傳附件作為支撐的公開服務(wù)而被調(diào)用;例如,項目管理與通知,分配任務(wù)用例才是核心功能,通知功能作為支撐的公開服務(wù)而被調(diào)用。巧的是,這種主次功能的調(diào)用關(guān)系,幾乎對應(yīng)的就是用例圖中的包含用例或擴展用例。

如果我們通過用例圖來幫助識別限界上下文,那么,用例圖中的包含用例或擴展用例或許是一個不錯的判斷上下文協(xié)作關(guān)系的切入點。選擇從包含或擴展關(guān)系切入,既可能確定了職責分離的邏輯邊界,又可以確定協(xié)作關(guān)系的方向,這就是用例對領(lǐng)域驅(qū)動設(shè)計的價值所在了。

那么,如何將上下文映射運用到領(lǐng)域驅(qū)動的戰(zhàn)略設(shè)計階段?Eric Evans 為我們總結(jié)了常用的上下文映射模式。為了更好地理解這些模式,結(jié)合限界上下文對邊界的控制力,再根據(jù)這些模式的本質(zhì),我將這些上下文映射模式分為了兩大類:團隊協(xié)作模式與通信集成模式。前者對應(yīng)的其實是團隊合作的工作邊界,后者則從應(yīng)用邊界的角度分析了限界上下文之間應(yīng)該如何進行通信才能提升設(shè)計質(zhì)量。針對通信集成模式,結(jié)合領(lǐng)域驅(qū)動設(shè)計社區(qū)的技術(shù)發(fā)展,在原有上下文映射模式基礎(chǔ)上,增加了發(fā)布/訂閱事件模式。

總結(jié)

以上是生活随笔為你收集整理的界限上下文识别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。