首頁  >  文章  >  科技週邊  >  電話機器人團隊DDD實踐

電話機器人團隊DDD實踐

王林
王林轉載
2023-05-10 22:37:041265瀏覽

簡介 

DDD是一套方法論,一套想法。種類繁多的元模型和名詞概念。其本質都是指導思想對應的解決方案“之一”,初學者容易被表象所困。應始終清醒保持認知「DDD各種元模型都是為解決實際開發中某類問題而起」。在接觸各類元模型時應結合自身業務面臨問題來求證,這樣有助於避免被概念表象所困,回歸解決問題的本質。

 背景 

資料架構團隊從18年開始,受業務需求驅動開發電話機器人,轉眼已近5年。目前,在該平台下已搭建100 不同類型機器人,為公司經銷商、二手車、主機廠、金融等多個BU業務提供外撥能力,日外呼量數十萬通。電話機器人專案已初具規模,但過程中也遇到不少挑戰。為了應對這些挑戰,我們團隊最終採用DDD思想進行重構和開發。

在應用DDD的過程中,資料架構團隊落地了一些自己的開發規格。這裡就把一些經驗和想法分享給大家,希望能起到拋磚引玉作用。這裡解釋一下,篇幅中很多元模型沒有展開講,也沒有給具體案例。一是考慮篇幅長度問題。二是了解DDD思想,結合各自業務來實現就好了,給我業務的例子意義不大。另外這類案例很容易找的到。同時,覺得給我們團隊遇到的問題、解決方案,落地過程和我們形成的開發規範對大家來說更有價值。對DDD有興趣,想了解更多或對本文有疑問的同學,歡迎找我交流討論。

下面,我從這幾個部分來進行分享:機器人專案中遇到的挑戰、為什麼是DDD、DDD落地步驟、對團隊帶來的提升、理論到實戰遇到的衝突以及未來在DDD應用方面的改進與總結。

 1.遇到的挑戰 

挑戰一:業務邏輯複雜度高。隨著各類業務的接入,為因應不同場景下的特定業務,不斷追加新邏輯。

如:流程中的意圖辨識邏輯。

意圖識別需要依賴AI的多個模型識別,多個模型識別出來的意圖有可能是衝突的,需要對衝突的意圖配置規則做取捨。同時,對一些冷啟動或緊急優化的場景,需要支援透過配置規則即時生效的方式來意圖識別。並且在規則的意圖識別中需要支援匹配詞槽。詞槽的類型又有多種,從優先順序上區分有場景的全域詞槽、流程上的詞槽。從資料辨識來源區分,可以分為AI辨識出來的,字典規則配對出來的,也可能是由業務方傳遞進來的。業務開展一段時間後,不同類型的詞槽又增加不同屬性,如車系的詞槽有本品、經營範圍、非經營等等;

 挑戰二:程式碼架構結構不清晰。隨著業務需求功能的追加,伴隨著程式碼規模增加。加之邏輯複雜和團隊開發人員程式碼迥異,逐漸導致各種邏輯邊界變得混亂。

如:我們通常的開發方式,依功能模組拆解,業務流程串聯協調各個模組,共同完成業務需求。但是處理這類業務複雜的邏輯,這種方案設計有很大的弊端,模組邊界很容易被穿透。

各模組關係相互調用,原本作為模組的隔離設計,實際在實現過程被完全完全的打破了。使原本理想中垂直拆分的模組,變成網狀的結構。

模組負責人中間環節發展出來的屬性或方法,被外部其它模組外依賴導致功能發散出去。導致後期需求變動時風險增加,又或是發現被依賴了原本可以隨意更改的方法不能變動,不得不增加額外邏輯程式碼來實現。造成了本來就複雜的程式碼更加複雜。

對業務需求拆解不合理,需求功能在實現時就近開發,未嚴格按照模組拆解,缺少統一思想作為指導。

挑戰三:產品需求多,難以辨別是否有真實價值。

挑戰四:邏輯變化快,不少需求導致需要程式碼邏輯重新設計。

挑戰五:業務多,各業務表達不一致,溝通成本高。

垂直邊界被打破,程式碼複雜度增加,加上業務流程頻繁調整。這些多重維度相互疊加,使得開發和維護難度指數增加。電話機器人這個一級應用系統的穩定性難以保障。即便技術同學都是資深的工程師,已經按照所能理解的微服務思想設計、按照模組拆解項目,即便代碼邏輯中已經也引用不少設計模式來構建與擴展,即便已經是接入了公司各個平台品質工具、寫了不少單元測試。但是在專案新需求迭代時,依舊出現不少“驚喜”,使整個團隊很頭疼。

2.為什麼是DDD

為什麼是DDD?每天那麼多技術棧,那麼多思想,為什麼就是DDD來應對呢?首先DDD修飾的很好“軟體核心複雜性應對之道”,使得不少人想一探究竟。所以來看看DDD是怎麼來解決專案中遇到的挑戰。

首先,我們來看看DDD對複雜度的歸類,弄清楚DDD要處理的複雜度是否是我面臨的挑戰。 DDD相關資料中,從理解能力和預測能力兩個維度來探討剖析複雜度的成因。

理解能力(就是軟體系統對開發人員來說複雜難以理解):

第一規模:影響理解能力的第一要素。幾百上千萬行的程式碼,各需求點的關係相互影響。修改一處就會牽一發動全身。

第二個結構:不合理甚至混亂的結構,導致開發人員難以維護功能。

預測能力(就是業務的發展難以預測):

當需求改變時,難以預測軟體實現的走向,會出現過度設計和設計不足問題。過度設計,預留了很多接口,構造了很多模式增加了代碼的實現複雜度,但後來發現用不到。設計不足,需求的實現沒考慮到後期的發展,當變化來臨時需要推翻現有設計重新開發,被產品抱怨設計能力差。

DDD對複雜度的成因歸結為:規模、結構、變化;規模和結構製造了理解能力障礙,變化製造了預測能力障礙,兩者相加形成了複雜度問題。

 其次,DDD並非只是程式設計階段的理論,而是還包含從需求分析、架構映射和建模及實現的全流程設計指導。

需求分析階段,透過相關指導思想提前準確獲知業務價值,捕捉未來變化方向。架構映射階段,給予從需求到架構過程的指導思想,增加了設計權重和規範。透過子領域拆分、系統分層和限界上下文業務歸類,給予指導規範,保障了系統架構的清晰,並且降低系統複雜度。建模及實現階段,給出來領域驅動設計相關元模型,使各部分職能分工明確,快速回應業務需求及未來功能變化。

再,來看DDD給予的指導思想:

規模問題:拆邊界。以子領域、限界上下文對拆解分治。

針對分治思想,DDD給出兩個重要的設計元模型:限界上下文和上下文映射。

結構問題:分層架構 限界隔離。

分層起到了隔離業務邏輯和技術實作複雜度問題。 DDD引進的分層架構,將業務邏輯封裝到領域層,支撐業務邏輯的技術實作放到基礎設施層。在領域層之上的應用層封裝應用服務,黏合二者進行協作。

變化問題:主動設計變化。

變化無法控制,只能擁抱變化。需求分析階段運用5W思維辨識變化規律,把控業務變化。 DDD透過模型驅動設計元模型對限界上下文進行領域建模,形成結合分析、設計和實現一體的領域模型。

最後,來看DDD給的解決方案。其引入了一套提煉為模式的設計元模型,對業務軟體做到了對規模的控制、結構的拆分以及變化的主動響應。

電話機器人團隊DDD實踐

 簡單介紹下這張圖,整體分成兩個大部分。第一部分是下面虛線圈出來的部分,不涉及具體技術實現。在需求分析階段進行的,應對問題空間的一些元模型方案。另外部分,在第一部分的基礎上,做具體係統架構分層、物件抽離聚合、服務拆解環節,這個階段做對應的設計落地。

我的理解是這樣,這套設計元模型給出了從需求分析、設計和實現一體整套解決方案。需求分析階段的系統拆解(對應圖中子領域元模型)。再拆到更新粒度的限界上下文。並給出各限界的協同關係方案(對應圖中上下文映射元模型)。設計實現階段給出模型驅動設計的設計元方案,透過系統的分層架構、領域服務、聚合等粒度的設計。給出一套完善的、有理論支撐的、可落地有標準的解決方案。

上述DDD對問題複雜度的剖析定位,完全就是電話機器人系統中的痛點。給出的解決方案,也完美解決業務面臨的各類挑戰。在認識到其價值後,團隊很快就達成共識在後續的專案中進行落地。

3. DDD落地步驟 

元模型細節、業務限界的拆解不展開講了,直接給出我們團隊實戰中的步驟和產物。

3.1第一步預研階段

這部分我們的經驗是團隊中有人充當先行者,先花費精力做深入學習DDD相關理念,然後同步到整個團隊。就我們團隊來講,研究階段時間比較零碎不好評估用時多久,團隊科普階段前後4次用8小時。之後,團隊內同學在有概念指導的基礎上,已具備快速深入學習能力。並組織團隊成內相互探討印證理解。

3.2第二步引入指導思想與落地規範

 3.2.1 需求分析階段引入5W模型理論支撐,有助於辨識出真實需求,主動把控變化方向和排除無意義需求。

這部分就是5W理論作為跟產品分析需求的理論的支撐,非常有助於辨識出真實的需求,更好的分析出業務的發展方向。也能從源頭縮減無效需求,直接上圖;

電話機器人團隊DDD實踐

#3.2.2 引入服務規約,以文件型對照程式碼業務功能實現。有助於開發及後續需求梳理,同時也能作為單元測試覆蓋度的考量。

  • 3.2.2.1 團隊成員共識,需求先寫服務規約,再做開發。寫服務規約的時間,其實就是科技對需求理解的梳理,理清了思路,後續寫程式碼時把這部分時間賺回來。
  • 3.2.2.2 服務規約及需求,服務規約即對應單測。順帶解決了先前單測沒有標準(我理解的程式碼、方法覆蓋率這類,不能稱作為標準)的問題。

這裡給出我們團隊採用的服務規約範本:

編號:標記業務服務的唯一編號。

名稱:動詞片語形式的業務服務名稱。

描述:

         作為

         我想要

         

角色主動觸發的該業務服務事件,可以是點選UI的控制項、具體的策略或伴生系統所傳送的訊息等。

基本流程:

用於表現業務服務的主流程,即執行成功的業務場景。也可以稱為「主成功場景」。

替代流程:

用於表現業務服務的擴充流程,即執行失敗的業務場景。

驗收標準:

一系列可以接受的條件或業務規則,以要點形式列舉。

3.3第三步驟決定架構方案

學習DDD中模型驅動設計元模型的方案。主要是劃分職責邊界,也就是限界上下文,達到從傳統網狀結構關係變成垂直切分關係,減少彼此依賴。整體採用限界上線文拆解加菱形驅動設計,形成整體思想指導。系統採用分層架構COLA 4.0

3.4第四步驟共識命名標準形成團隊編碼規格電話機器人團隊DDD實踐

 團隊內共識包命名、類別命名、出參入參的訊息契約等規範。這裡想說的是參考標準就是沒有標準。希望大家先能理解DDD思想,然後參考學習業內一致的命名方案。同時需要兼顧團隊內成員程式設計風格喜好,最後來制定自己團隊的程式設計規格。

就依我們入參、出參訊息命名來舉例。綜合各方考量,並沒有採用上圖粒度特別細的命名方式。而是團隊內簡單共識為入參*request,出參*reponse命名標準。 電話機器人團隊DDD實踐

3.5第五步結合業務特徵識別出限界上下文

 基於DDD思想,對業務進行事件風暴,在統一語言的指導下做全局需求分析、架構映射設計,識別出業務的限界上下文。

技術同學結合自身業務來設計,參考Demo資料還是比較容易找的到,這裡不再贅述。這裡給出識別限界上下文的一個指導過程,V型映射過程。

3.6最後進入建模的實作階段電話機器人團隊DDD實踐

建議採測試驅動開發的方式進行編碼,即以紅綠黃驅動;

該方式遵循其三定律,這樣能改善對需求的設計不足和過度設計問題。 電話機器人團隊DDD實踐

定律一

一次只寫一個剛好失敗的測試,作為新加功能的描述。

定律二

#不寫任何產品程式碼,除非它剛好能讓失敗的測試通過。

定律三

#只在測試全部通過的前提下做程式碼重構,或開始新加功能。

#

4.對團隊帶來的提升

4.1被動接收需求到主動因應

 需求分析階段,運用5W原則。剖析需求的合理性,能主動把控項目的變化方向。解決「挑戰三」對需求價值辨別並改善了「挑戰四」的把控業務​​發展變化方向。

4.2降低溝通成本

運用統一語言思想溝通,降低「挑戰五」的各個環節的協作成本。

4.3架構設計提升

透過設計元模型的子領域模型、限界上下文合理拆解程式碼規模。透過DDD的分層思想,隔離業務邏輯與技術維度複雜度,清楚程式碼結構。同時專案採用菱形對稱結構,透過南北向網關與外部交互,避免了模組的網狀情況滋生。解決了「挑戰二」問題和降低了「挑戰一」複雜度問題。

4.4技術實現提升

團隊在開發業務功能時,會考慮需求放到那個限界合理。實現過程會考慮放到領域層還是業務服務層,功能的實現上採用貧血模型還是充血。

4.5 文件規格提升

文件規格上,引入服務規約機制。既能作為梳理需求的工具,又能作為單測的依據。同時也為後期提供了服務說明的文件。

4.6程式碼實作提升

程式碼實作上,從架構到編碼實作、命名,形成了一套有標註的規格。

總的來說,在該模式下,團隊的思維方式發生了轉變。透過應用各類元模型,來因應從需求分析到系統架構、程式碼實現不同環節所帶來的挑戰。

 5.理論到實戰遇到的衝突 

5.1貧血模型PK 充血模型

 貧血模型:通俗來說,就是domain object只有屬性的getter/setter方法的純資料類,業務邏輯和應用邏輯都放到服務層中,這種模型下的domain object被Martin Fowler稱之為「貧血的domain object」。

充血模型:反之,充血模型中不僅包含了物件的屬性,也包含了物件的行為,包括業務邏輯。

從物件導向角度分析,物件是包含屬性和行為的,理應是使用充血模型,並且DDD原則上也是建議採用充血模型。但落地到具體開發現狀,即便是貧血模型有很多問題,但業界存在這麼多年、運用這麼普遍,總歸是有其存在的價值。加上JAVA應用大部分採用Mybatis技術棧,許多物件是插件自動產生的貧血實體。所以問題來了,採用充血模型意味著一部分便利工具的廢棄。這個問題團隊內分歧比較大。最終我們的方式是這部分不做硬性標準,但建議使用充血模式。

5.2嚴格遵守資料轉換限制  

PK 精簡提效的外部資料直接使用

在DDD的想法中,為了確保領域服務的可靠性。要求領域服務依賴的數據為領域內的實體、聚合數據,不允許直接使用外部的消息鍥約數據。對應到菱形對稱架構的南北向網關取得資料的轉換,會帶來額外的工作量。有團隊同學建議某些相對穩定的結構可以不遵守該原則,理由是能提高開發速度,且認為可能90%的資料都是如資料庫這類結構較為穩定的資源。但最終團隊內還是嚴格要求遵守該指導思想。

5.3快取處理允許共享 PK 限界隔離

同一系統不同限界中快取處理:允許共享 PK 各限界隔離。

就當時場景來看,允許共享短期內能減少部分工作量、節約資源等優勢。但之所以要劃分限界,就是為了拆解關係防止過大。這裡給到的建議是,首先考慮共用資料的服務是不是合併為一個限界比較合理。如果不能合併,必須隔離資料。

5.4服務規則對照需求的前端 PK 後端

 指導理論想法很美好,需求分析時要求屏蔽技術實現思考。但終歸是要落地到技術棧的,落地到技術實現時就會受技術實現的干擾。當時比較突出的一個問題,功能的實作可以放到前端,也可以後端服務實作。

舉例一:需求要求「id 名字」組合展示,但是後端介面返回的id、名字兩個字段,實際前端技術棧來組合,那面向前端與後端的服務規約不一致。

範例二:需求要求驗證參數非空。在一些內部系統中,我們團隊技術都是前後端全端工程師,分工依需求模組開發。往往不會特別嚴謹到兩端都做驗證。也導致服務規約面向哪端有衝突。

我們最終的取捨:團隊採用面向後端服務層面。但同時做一些改進,如驗證這類功能轉移到介面層面來實現。

5.5誰來確保服務規約編寫是否正確產品PK 技術

 最開始階段理想狀態是由需求面產品來核驗,本著誰的需求誰確認原則。但由於4.4的差異問題,我們實際落地是由技術負責人來審核。

6.未來在DDD應用方面的改進和總結

DDD的應用,團隊目前做到了從架構和規範上面進行落地。但有些細節如:聚合類別、實體、值物件這些設計,並沒有特別精細。後期會進一步推進在這些細粒度上面的改進。同時,對一些在用的老項目,依照DDD思想進行改造重構。

有人認為應用DDD會降低開發效率,這也是很多團隊的一個顧慮。我們是這麼看待這個問題的,應用DDD的場景是解決複雜性業務問題的,確實是會增加程式碼量。但不等於降低開發效率。清晰的架構結構、聚合的領域服務和規範的標準,對後期需求升級、程式碼維護、複雜度控制帶來的效益,遠大於投入。並且,軟體產業給出的數據,80%的時間是在需求分析設計,開發時間只佔20%。因此這部分損耗不是重點。

最後,陳述一下使用DDD的感受。 DDD各種元模型種類繁多,大家可以根據業務面臨的痛點有目的來學習和採用。在實際的業務環境中,我們的領域模型或多或少的都有一定的“特殊性”,如果100%的要符合DDD規範可能成本會比較高,所以最主要的是理解DDD思想,最終選擇合適自身業務的方案。

作者簡介

電話機器人團隊DDD實踐

李曉華 

  • 經銷商事業部-經銷商技術部。
  • 2016年加入汽車之家,目前任職於經銷商資料架構小組團隊,負責電話機器人專案。

以上是電話機器人團隊DDD實踐的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:51cto.com。如有侵權,請聯絡admin@php.cn刪除