譯者 | 李睿
審校 | 重樓
領域驅動設計(DDD)是軟件開發(fā)的一種重要戰(zhàn)略方法。它涉及對業(yè)務領域的深入理解和建模,尤其適用于具有復雜業(yè)務規(guī)則、流程和交互的復雜領域。然而,有效地實現(xiàn)DDD需要紀律性、領域的深刻理解,以及避免可能導致次優(yōu)設計和技術債務的常見陷阱。本文中將探討在DDD中應該避免的10件事,并舉例說明這些陷阱。
1.過于關注技術模式
(1)示例場景
團隊在開始開發(fā)項目時,在還沒有完全理解業(yè)務領域的情況下,就過度創(chuàng)建了存儲庫、聚合和值對象。例如,他們開發(fā)一個復雜的存儲庫來管理客戶實體,而不了解客戶在業(yè)務中是如何表示和利用的。因此,這個存儲庫包含了許多與領域的實際用例和需求不一致的不必要的方法。
(2)避免技巧
DDD的主要重點應該是理解領域。這涉及一個協(xié)作過程,團隊與領域專家緊密合作,以建立對基本業(yè)務概念的共同理解和共同語言。像存儲庫和聚合這樣的技術模式應該自然地從領域模型中出現(xiàn),而不是在開始時過早地實現(xiàn)或過分強調。
2.過度設計模型
(1)示例場景
團隊嚴格遵守DDD原則,創(chuàng)建了一個詳細的領域模型,該模型包含每個可能的領域概念的單獨類。例如,他們?yōu)椤翱蛻裘Q”(CustomerName)、“客戶郵箱”(CustomerEmail)和“客戶地址”(CustomerAddress)創(chuàng)建了單獨的類,而這些本來可以組合成一個更直接的“客戶”(Customer)值對象。結果模型變得過于復雜,難以維護,幾乎沒有附加價值。
(2)避免技巧
為了防止?jié)撛诘膯栴},團隊有責任維護一個簡單且準確反映領域的領域模型。這種謹慎的方法對于專注于對具有戰(zhàn)略重要性的領域組件進行建模以及簡化或排除不太重要的元素至關重要。需要記住,DDD主要關注的是戰(zhàn)略設計,而不是通過不必要的復雜性來不必要地使領域模型復雜化。
3.忽視通用的語言
(1)示例場景
在協(xié)作環(huán)境中,開發(fā)人員和領域專家使用不同的技術詞匯是很常見的。例如,雖然領域專家通常使用“采購訂單”這一術語,但開發(fā)人員可能會在他們的代碼庫中使用OrderEntity。這種術語差異可能導致各種挑戰(zhàn),包括誤解、處理不當?shù)膶崿F(xiàn),以及代碼與具體業(yè)務需求之間的同步需求。這些差異可能會阻礙有效溝通,并妨礙將業(yè)務邏輯準確轉換為技術實現(xiàn)。因此,確保開發(fā)人員和領域專家之間對術語有共同的理解,對于促進有效協(xié)作并使技術解決方案與業(yè)務需求保持一致至關重要。
(2)避免技巧
建立和維護一種通用語言對于確保項目各個方面的清晰溝通和理解至關重要。這個過程需要與領域專家密切合作,以開發(fā)和維護一致的詞匯表。語言應該統(tǒng)一地應用于代碼、文檔、對話和所有形式的交流中。通過這樣做,可以防止誤解,并保證模型準確地反映業(yè)務需求。這種方法有助于所有利益相關者保持一致,并促進了整個項目生命周期的凝聚力。
4.對有限語境的誤解
(1)示例場景
當團隊試圖在例如“賬單”(Billing)、“客戶服務”(Customer Service)和“營銷” (Marketing)各種子域中使用單個“客戶”實體時,會導致應用程序不同部分之間的歧義和不必要的互連。例如,在“賬單”語境中對“客戶”實體所做的修改可能會無意中影響“營銷”語境,從而導致不可預見的行為和數(shù)據(jù)差異。
(2)避免技巧
在定義有界語境時,明確劃分具有不同職責的領域區(qū)域至關重要。每個有界語境都應該擁有自己的模型和明確定義的邊界。為了維護每個語境模型的完整性,必須通過定義良好的接口或反腐敗層促進語境之間的集成。這些措施確保保留每個有界語境的職責和完整性。
5.不符合商業(yè)戰(zhàn)略
(1)示例場景
團隊對DDD的采用純粹是技術性的,他們專注于對領域所有方面的建模,而沒有考慮業(yè)務戰(zhàn)略。他們投入了大量精力來建模領域的周邊元素,例如“員工出勤”和“辦公用品管理”,而忽視了提供最大價值的核心業(yè)務流程:“訂單履行”。 由于采用這種方法,生成的模型很復雜,但需要與業(yè)務的戰(zhàn)略目標保持一致。
(2)避免技巧
利用DDD深入分析和專注于領域中最重要和最有影響力的部分是至關重要的。確定向業(yè)務交付最高價值的方面,并確保建模工作與業(yè)務的總體優(yōu)先事項和戰(zhàn)略目標緊密結合。積極與關鍵業(yè)務利益相關者合作,以全面了解對他們而言最具價值的領域,并在建模工作中優(yōu)先考慮這些領域。這種方法將最佳地反映業(yè)務的關鍵需求,并有助于成功實現(xiàn)戰(zhàn)略目標。
6.過度使用實體而不是值對象
(1)示例場景
許多軟件開發(fā)人員將“貨幣”(Currency)概念化為具有唯一標識符的實體本質上將其視為獨立對象。但是,將“貨幣”視為由其屬性(例如“美元”或“歐元”)定義的值對象可能更有效。通過堅持使用前一種方法,團隊無意中引入了不必要的復雜性,例如需要管理“貨幣”實體的生命周期、狀態(tài)和身份。這不必要地使代碼庫變得復雜,使其更加笨重并增加了其冗余性。
(2)避免技巧
在設計軟件時,盡可能地利用值對象是有益的,特別是對于保持不變且不需要唯一標識的類型和對象。值對象是有利的,因為它們更易于管理和預測,通常導致代碼更易于維護。這些對象可以有效地表示特定于領域的值,例如日期、貨幣值、測量值和其他基本概念。
7.忽略聚合及其邊界
(1)示例場景
在DDD的語境中,聚合表示作為數(shù)據(jù)更改的單個單元的相關對象的集群或組。當團隊將“產品”(Product)建模為獨立實體時,他們可能會忽略其聚合邊界,從而允許多個服務獨立地修改它。這可能導致不同服務對同一“產品”的更新沖突,從而導致數(shù)據(jù)不一致和違反業(yè)務規(guī)則。定義和尊重聚合邊界對于維護數(shù)據(jù)完整性和確??绮煌到y(tǒng)部分的一致性至關重要。
(2)避免技巧
聚合是DDD中的一個基本概念,它涉及將一組相關對象視為數(shù)據(jù)更改的單元。聚合包含一個特定的對象,稱為聚合根,它作為聚合內所有修改的入口點。在聚合中封裝相關對象并通過聚合根進行修改,可以更容易地執(zhí)行業(yè)務規(guī)則并維護數(shù)據(jù)一致性和完整性。這種方法有助于確保所有操作和更改都發(fā)生在聚合的定義邊界內,從而可以更好地控制和管理復雜的數(shù)據(jù)結構。
8.未能有效地使用域事件
(1)示例場景
團隊忽略域事件并直接調用服務。這導致他們的系統(tǒng)變得緊密耦合,增加了不同系統(tǒng)部分之間的依賴關系。因此,修改或擴展系統(tǒng)變得更具挑戰(zhàn)性,因為一個服務中的任何更改都會直接影響其他服務,從而導致更改的多米諾骨牌效應,并使系統(tǒng)更加脆弱。
另一方面,在另一種情況下,其他的一個團隊過度使用領域事件,為每一個小的變化都發(fā)出一個事件,例如“客戶創(chuàng)建”(CustomerCreated)、“客戶更新”(CustomerUpdated)和“客戶刪除”(CustomerDeleted),即使系統(tǒng)的其他部分并不需要這些事件。這將導致生成和處理過多的事件,從而導致性能下降、復雜性增加和不必要的資源消耗。系統(tǒng)中充斥著毫無實際意義的事件,導致事件疲勞,使識別和響應關鍵事件變得更加困難。
(2)避免技巧
在開發(fā)系統(tǒng)時,利用領域事件來捕獲領域內的重大變化是至關重要的。這些事件應該經過精心設計,以服務于明確的目的,并在系統(tǒng)內傳達有意義的狀態(tài)變化。通過使用領域事件,可以有效地解耦系統(tǒng)的各個部分,從而促進系統(tǒng)的可擴展性和改進可維護性。
然而,謹慎行事并避免過度使用領域事件是至關重要的,因為這樣做可能導致不必要的復雜性和潛在的性能問題。至關重要的是要取得平衡,只使用真正有益的領域事件,而不是不加選擇地將其納入整個系統(tǒng)。這種方法最終將有助于建立一個更加精簡和可管理的系統(tǒng)架構。
9.忽視了與領域專家合作的重要性
(1)示例場景
開發(fā)團隊在沒有征求貸款經理或該領域其他專家的意見的情況下,開始創(chuàng)建“貸款審批”流程。因此,該模型省略了關鍵的業(yè)務規(guī)則,包括特定的風險評估標準、驗證步驟和監(jiān)管要求。這一重大疏忽導致軟件解決方案需要與業(yè)務需求保持一致,導致其被利益相關者拒絕。
(2)避免技巧
在設計和開發(fā)過程的每個階段與領域專家建立密切合作是至關重要的。定期與他們接觸以確認對該領域的理解是準確的很重要,可以讓領域專家參與討論、設計會議和模型評審,以收集他們具有價值的見解。諸如事件風暴和領域故事講述等技術可以促進協(xié)作建模,確保模型忠實地代表領域。
10.將DDD視為靈丹妙藥
(1)示例場景
團隊錯誤地認為DDD普遍適用于所有軟件項目,而無論領域的復雜性如何。這導致他們將DDD原則應用于簡單的CRUD應用程序,例如“待辦事項列表”或“聯(lián)系人管理”系統(tǒng)。其結果是,代碼庫過于復雜,難以維護,開發(fā)成本高昂,遠遠超過了項目的需求。
(2)避免技巧
DDD最適合以復雜性著稱的領域,特別是那些以復雜的業(yè)務規(guī)則和流程為特征的領域。在如此復雜的領域中,業(yè)務團隊和技術團隊之間的緊密結合對于成功至關重要。相比之下,DDD可能并不最適合簡單的應用程序或領域,在這些領域,可以采用更直接的方法。仔細評估領域的復雜性和項目的具體要求以確定最合適的方法非常重要。
結論
DDD是一種強大的軟件開發(fā)方法,旨在構建與復雜業(yè)務領域相匹配的軟件。然而,就像任何強大的工具一樣,必須明智地使用。通過避免這10個常見的陷阱,可以充分利用DDD的潛力,創(chuàng)建出準確反映并支持業(yè)務目標的軟件。需要記住,DDD不僅僅是關于模式和實踐;它關于促進協(xié)作、建立對領域的共同理解,以及構建能夠提供真正戰(zhàn)略價值的解決方案,這種價值正是團隊協(xié)同努力的重要貢獻。
通過專注于理解領域、避免過度設計、與業(yè)務戰(zhàn)略保持一致,以及保持清晰一致的語言,團隊可以創(chuàng)建不僅在技術上合理,而且與業(yè)務需求高度一致的模型。
原文標題:10 Things To Avoid in Domain-Driven Design (DDD),作者:Reza Ganji