成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

DDD診所——聚合過大綜合癥

開發
在實踐DDD時,我們應該關注聚合的劃分和優化,以確保在保持業務一致性和完整性的同時,避免因聚合過大導致的性能和可用性問題。

作者 | 付施威

一、DDD診所 —— 聚合過大綜合癥

“DDD診所”是Thoughtworks DDD社區的一項活動,通過對同事們在實施DDD過程中遇到的問題進行分析和解答,共同提高開發水平。我們將其中一些典型案例整理成文供大家參考。之后也會考慮在適當的時候將這一形式對外部開放。

就診日期:2022年6月8日

患者:某DevOps平臺持續集成模塊

診金:0元(免費義診)

二、【患者主訴】

疑似問題設計

某DevOps平臺需提供持續交付流水線設計功能,使用戶可在界面上規劃完整流程。因此,流水線設計頁面功能繁雜,涵蓋階段規劃、前置觸發條件設置、質量門禁控制等。隨著功能擴展,頁面復雜度逐漸提升。此類功能旨在協助用戶優化持續交付流水線管理,提升交付效能與質量。

圖片圖片

持續交付流水線界面原

功能介紹:

  • 設計不同的階段:用戶可以根據需要設置不同的階段,例如開發階段、測試階段等。對于每個階段,用戶可以設置不同的步驟,例如Checkout、編譯、構建鏡像和部署等。
  • 設計前置觸發條件:用戶可以選擇兩種觸發方式,一種是某個代碼倉庫提交觸發,另一種是定時任務。用戶可以設置多個前置觸發條件。
  • 設置質量門禁:用戶可以選擇給階段設置質量門禁,例如單元測試覆蓋率大于80%等。這些門禁指標可以在質量門禁管理功能中設置。在流水線執行時,如果不滿足門禁指標,會阻止流水線進入下一個階段。

項目架構師在接到需求后,根據需求設計了一個名為“持續交付流水線領域模型”。該模型的目的是方便用戶在界面上完成一系列操作,如代碼質量檢查、編譯代碼、構建鏡像和部署等。這些操作被看作是一個整體,并被組織在一個叫做“流水線”的聚合中。這個聚合包括質量門禁、不同的階段和觸發規則等。這種設計旨在保證流水線中各個組成部分的一致性。

請注意,圖中的“<>”是一種自定義的衍生關系,意味著該對象映射自其他上下文。

圖片圖片

持續交付流水線領域模型

團隊按照這個模型落地了代碼,隨著交付的深入,這個模型的缺點也浮現出來。

引發問題

1. 認知負載上升

這個聚合包含了7個實體(不包括抽象類),每個實體都有自己相關的業務,因此這個聚合的認知負載相對較大。此外,該部分業務需要集成不同的外部依賴系統,如Sonar(用于實現質量門禁)、定時任務組件(用于定時任務觸發器)、GitLab或GitHub(用于代碼提交觸發器)等。盡管可以通過使用Repository模式和依賴倒置原則來分離功能和實現,但開發人員或維護人員仍需要掌握相關知識。如果某個人接手了這個功能(例如修改質量門禁相關功能),他/她基本上需要了解整個系統的工作方式。

2. 部分可用性難以實現

這個功能集成了多個第三方系統,并被設計為一個聚合。由于這些功能中的任何一部分不可用時,整個功能都將受到影響,因此難以實現部分可用性。例如,當Sonar服務暫時不可用時,代碼觸發和階段維護的部分也無法為用戶提供服務。如果后續用戶提出了部分可用性需求,要求Sonar不可用的情況下,要提示質量門禁設置失敗,但同時,其他部分仍需為用戶提供服務,那么根據這個設計就很難實現了,只能推倒重建,成本非常高。

不幸的是,在設計過程中我們不知不覺地構建了一個分布式單體。分布式單體架構是對一種設計糟糕的微服務架構的戲稱。一般指那種由于架構師沒有充分考慮和掌握分布式的優勢和代價,憑感覺設計出的微服務架構。這種架構導致設計出的系統既不能享受分布式的彈性優勢,又丟失了單體服務易于實現ACID事務強一致性方面的便利。通常出現在未經良好設計的微服務風格的分布式軟件中。

3. 犧牲了性能和并發性

當前的交互設計是用戶在設計界面對流水線的各部分進行設計,設計完成后按提交按鈕提交所有部分。實際上,用戶在每次修改時,不一定需要同時修改質量門禁、階段、觸發規則等所有的部分。然而由于聚合模式的特點,我們每次都需要對整個聚合的所有實體進行整存整取。即使用戶只想修改其中一部分(如“觸發規則”),我們仍需要更新名為“流水線”的聚合的整個7個模型,這將導致巨大的性能浪費。此外,如果兩個用戶同時操作業務上互不影響的兩部分如“觸發規則”和“質量門禁”時,會相互沖突,有一個用戶要被提示“設計已變更,修改失敗”,降低了系統的吞吐量。

三、【診斷】

初步診斷,患者的病情主要是聚合過大綜合癥,即聚合設計不合理,導致聚合過大。在DDD實踐中,合理劃分聚合是個比較有挑戰的問題。

聚合過大綜合癥的病理分析

在DDD的落地實踐過程中,聚合的大小經常被描述為一個不可言說的知識。很多時候,憑經驗和感覺會導致比較差的設計。然而,在實踐中,識別大聚合仍有跡可循,一般來說,出現了這三種情況時,就需要警惕聚合過大綜合癥:

1. 寬聚合

一個聚合聚合了多個同級實體,一個“父親”多個 “兒子”。如圖所示:一旦超過三就有大聚合的風險。

2. 深聚合

聚合的深度過深,例如聚合根有兒子實體,也有孫子實體,也有重孫實體。當層級達到三層時,就存在大聚合的風險。

3. 胖聚合

盡管結構簡單,但實體對象實例多。例如訂單和訂單行作為了一個聚合,而實際業務經常出現有幾千個訂單行的訂單。這種也存在大聚合的風險。

圖片圖片

聚合過大的三個征兆

正如該案例所表現的那樣,這是一個具有寬聚合和深聚合的聚合過大綜合癥癥狀。聚合過大綜合癥會導致一系列問題,例如認知負荷增加、部分可用性下降以及性能問題。而在該案例中,這些問題正是由聚合過大綜合癥所導致的。

四、【治療建議】

出現聚合過大綜合癥,大多數情況是由于聚合劃分不合理所導致的。為了解決這個問題,我們可以回顧《領域驅動設計》一書中有關聚合模式的定義,以了解如何合理地劃分聚合。

識別聚合的方法

在《領域驅動設計:軟件核心復雜性應對之道》一書中,聚合的定義如下:

在具有復雜關聯的模型中,要想保證對象更改的一致性是很困難的。需要維護適用于密切相關的對象組的Invariant,而不僅僅是離散的對象。然而,過于謹慎的鎖定機制又會導致多個用戶之間毫無意義地互相干擾,從而使系統不可用。 我們應該將 Entity和 Value Object分門別類地聚集到Aggregate中并定義每Aggregate的邊界。在每Aggregate中,選擇一個Entity作為根,并通過根來控制對邊界內其他對象的所有訪問。只允許外部對象保持對根的引用。對內部成員的臨時引用可以被傳遞出去,但僅在一次操作中有效。由于根控制訪問,因此不能繞過它來修改內部對象。這種設計有利于確保Aggregate中的對象滿足所有固定規則,也可以確保在任何狀態變化時Aggregate作為一個整體滿足固定規則。

根據聚合模式的定義,我們可以得出判斷兩個實體(Entity)是否屬于一個聚合的依據,需要把握兩個條件:

1. 存在整體部分關系

當某個Entity是另一個Entity的部分時,稱為整體部分關系。例如:

  • 汽車輪胎是汽車的一部分
  • 學生是班級的一部分
  • 訂單行是訂單的一部分

2. 實體之間存在變更時需要遵守的固定規則(Invariants)

固定規則或稱為不變量不變式,來自契約式設計。

在計算機科學中,不變量是指在計算機程序執行的某一階段始終為真的邏輯論斷。例如,循環不變量是一個條件,在一個循環的每個迭代開始和結束時都是真的。--- wiki <https://en.wikipedia.org/wiki/Invariant_(mathematics)>

在劃分聚合時,我們關注的是一些由業務原因所約束的固定規則。這些規則通常是通過與業務人員溝通,了解“A更新的時候,會不會引起B的某個屬性的更新”,“如果兩個實體暫時不一致,是否會導致難以承受的業務后果”等問題來得出的。

例如,在訂單系統中,假設需求是整個訂單的總價等于訂單行的總價之和,且總價必須小于3000(左圖)。在這種情況下,訂單與訂單行之間就存在固定規則。因此,可以把它們放在同一個聚合中,并通過整存整取來維護這個固定規則。然而,如果業務場景是訂單僅作為訂單行的分組,用戶需要按照訂單行逐一結賬(右圖)那么訂單和訂單行就無需劃分成一個聚合。

圖片圖片

固定規則是劃分聚合的重要條件

需要注意的是,固定規則中的一部分是由技術實現所約束的固定規則,例如數據庫ID不重復、訂單編號唯一等。這些規則通常是全局性的固定規則,需要在整個系統范圍內遵循。然而,由于這些全局性的固定規則通常與特定的業務邏輯無關,因此在劃分聚合時,它們通常不是參考因素。

大聚合都必須拆小么?

盡管利用業務固定規則通常能夠確定較小的業務一致性邊界,從而得出比較合適的聚合規模,但并不是所有業務都適用這一原則。在有些業務場景中,大聚合可能是不可避免的。在這種情況下,如果想維護固定規則,是否采用聚合模式,需要權衡使用大聚合帶來的成本是否可以接受。聚合模式是一種設計模式,而非萬能的解決方案,在不適用的場景下強行應用聚合可能會導致收益不成正比。

聚合模式是為了解決復雜業務中的一致性問題,將具備固定規則的一組對象整存整取的一種方案。采用聚合模式的優點在于比較簡單地就能實現固定規則約束,代價就是整存整取帶來的性能損失等問題。

五、【治療方案】

在案例中,盡管流水線各部分之間存在整體部分關系,通過對業務進行分析,我們確定了以下固定規則:

  • 階段內的步驟之間存在嚴格的順序依賴,因為下一個步驟通常依賴上一個步驟的產出物。因此,存在一個固定規則:某個步驟的執行順序必須按照階段的步驟列表中的順序關系。
  • 階段質量門禁和門禁項之間存在固定規則,即當在門禁項發生變更時,門禁版本也必須隨之更新門禁的版本有一定的業務含義(例如,門禁版本更新需要在界面上進行明確提示)。

圖片圖片

整改后的聚合

因此,根據上述整改方案,原本的一個大聚合被拆分成了四個小聚合,每個聚合只包含少量實體。這種改動可以有效地降低聚合的規模,從而更好地平衡性能和業務一致性之間的關系。

六、【總結】

在領域驅動設計實踐中,聚合的劃分確實是一個難以把握的問題。聚合本身是一種有代價的模式,不合理的聚合劃分可能導致嚴重的問題,從而引發一系列疑問,例如“為什么使用DDD后仍然遇到各種問題?”聚合過大綜合癥是聚合劃分中的一種常見問題,當模型中出現寬聚合、深聚合或胖聚合時,我們需要警惕聚合過大綜合癥及其帶來的難以維護、犧牲可用性和性能損失等問題。

要解決這個問題,我們需要回顧聚合解決的核心問題:如何維護對象之間的固定規則。再次考慮聚合的劃分時,需要滿足兩個條件:整體-部分關系和實體間需要遵循的固定規則。當使用聚合模式的代價過大時,可以考慮其他方法來實現,例如通過鎖機制鎖定需要維護一致性的對象方法。

總之,在實踐DDD時,我們應該關注聚合的劃分和優化,以確保在保持業務一致性和完整性的同時,避免因聚合過大導致的性能和可用性問題。在面臨聚合模式代價過大的情況時,可以靈活選擇其他方法來實現業務一致性和完整性。

責任編輯:趙寧寧 來源: Thoughtworks洞見
相關推薦

2011-10-20 13:14:20

噴墨打印機常見問題

2012-05-09 17:27:50

創新BlackBerry RIM

2021-06-16 11:18:22

物聯網建筑綜合癥IoT

2020-01-20 13:56:12

物聯網病態建筑綜合癥智能建筑

2013-02-01 10:12:57

2018-08-17 15:00:03

京東

2017-12-25 11:24:57

程序員代碼編程

2021-11-18 13:14:08

DDD聚合代碼

2015-05-25 11:12:02

程序猿個個經典

2019-08-02 16:15:13

2021-12-09 09:54:02

領導者疫情情商

2014-05-12 10:12:09

程序員

2015-12-25 11:34:25

2022-01-29 00:02:32

嵌入式系統開發系統

2015-07-02 13:42:50

2019-02-11 13:55:03

Linux重復性壓迫損傷命令

2014-04-14 16:02:01

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 午夜欧美一区二区三区在线播放 | 日韩成人免费av | 亚洲午夜精品在线观看 | 99pao成人国产永久免费视频 | 国产电影精品久久 | 国产一级一级毛片 | 日韩性在线 | 久久久久久久久久久久久久av | 在线亚洲一区二区 | 亚洲成人免费视频 | 中文字幕91av | 99九九视频 | 999精品视频| 国产精品视频一区二区三区不卡 | 做a网站 | 九色 在线 | 国产视频第一页 | 久久成人精品视频 | 色婷婷综合久久久久中文一区二区 | 亚洲精品专区 | xxxxx黄色片| 国产精品区二区三区日本 | 久久久高清 | 欧洲精品视频一区 | 在线观看中文字幕 | 亚洲成人中文字幕 | 午夜国产一级 | 日韩a| 欧美激情第一区 | 国产精品亚洲综合 | 日本不卡在线观看 | 在线中文视频 | 国产精品一区二区av | 免费视频一区二区 | 国产色网站 | 91九色在线观看 | 国产精品99久久久精品免费观看 | 91就要激情 | wwwxxx国产 | 日本福利一区 | 亚洲欧美综合精品久久成人 |