[toc] 運用領域模型 消化知識 非原創,感謝《領域驅動設計》這本書 有效建模的要素 (1) 模型和實現的綁定。最初的原型雖然簡陋,但它在模型與實現之間建立了早期鏈接,而且在所有後續的迭代中我們一直在維護該鏈接。 (2) 建立了一種基於模型的語言。隨著項目的進展,雙方都能夠直接使用模型中的術語,並 ...
目錄
運用領域模型-消化知識
非原創,感謝《領域驅動設計》這本書
有效建模的要素
(1) 模型和實現的綁定。最初的原型雖然簡陋,但它在模型與實現之間建立了早期鏈接,而且在所有後續的迭代中我們一直在維護該鏈接。
(2) 建立了一種基於模型的語言。隨著項目的進展,雙方都能夠直接使用模型中的術語,並將它們組織為符合模型結構的語句,而且無需翻譯即可理解互相要表達的意思。
個人理解:定義專業詞語的字典解釋,保證每個人對每個術語的理解都是一樣的
(3) 開發一個蘊含豐富知識的模型。對象具有行為和強制性規則。模型並不僅僅是一種數據模式,它還是解決複雜問題不可或缺的部分。模型包含各種類型的知識。
(4) 提煉模型。在模型日趨完整的過程中,重要的概念不斷被添加到模型中,但同樣重要的是,不再使用的或不重要的概念則從模型中被移除。當一個不需要的概念與一個需要的概念有關聯時,則把重要的概念提取到一個新模型中,其他那些不要的概念就可以丟棄了。
(5) 頭腦風暴和實驗。語言和草圖,再加上頭腦風暴活動,將我們的討論變成“模型實驗室”,在這些討論中可以演示、嘗試和判斷上百種變化。當團隊走查場景時,口頭表達本身就可以作為所提議的模型的可行性測試,因為人們聽到口頭表達後,就能立即分辨出它是表達得清楚、簡捷,還是表達得很笨拙。
正是頭腦風暴和大量實驗的創造力才使我們找到了一個富含知識的模型並對它進行提煉,在這個過程中,基於模型的語言提供了很大幫助,而且貫穿整個實現過程中的反饋閉環也對模型起到了“訓練”作用。這種知識消化將團隊的知識轉化為有價值的模型。
知識消化
金融分析師要消化理解的內容是數字。他們篩選大量的詳細數字,對其進行組合和重組以便尋求潛在的意義,查找可以產生重要影響的簡單表示方式——一種可用作金融決策基礎的理解。
高效的領域建模人員是知識的消化者。他們在大量信息中探尋有用的部分。他們不斷嘗試各種信息組織方式,努力尋找對大量信息有意義的簡單視圖。很多模型在嘗試後被放棄或改造。只有找到一組適用於所有細節的抽象概念後,工作才算成功。這一精華嚴謹地表示了所發現的最為相關的知識。
知識消化並非一項孤立的活動,它一般是在開發人員的領導下,由開發人員與領域專家組成的團隊來共同協作。他們共同收集信息,並通過消化而將它組織為有用的形式。信息的原始資料來自領域專家頭腦中的知識、現有系統的用戶,以及技術團隊以前在相關遺留系統或同領域的其他項目中積累的經驗。信息的形式也多種多樣,有可能是為項目編寫的文檔,有可能是業務中使用的文件,也有可能來自大量的討論。早期版本或原型將經驗反饋給團隊,然後團隊對一些解釋做出修改。
在傳統的瀑布方法中,業務專家與分析員進行討論,分析員消化理解這些知識後,對其進行抽象並將結果傳遞給程式員,再由程式員編寫軟體代碼。由於這種方法完全沒有反饋,因此總是失敗。分析員全權負責創建模型,但他們創建的模型只是基於業務專家的意見。他們既沒有向程式員學習的機會,也得不到早期軟體版本的經驗。知識只是朝一個方向流動,而且不會累積。
個人理解:現在依然有公司在這樣做,業務需求人員定義需求,再由架構師或者組長進行翻譯,之後直接分配給程式員任務,最後做出的程式往往和需求偏差較遠,大部分會議是組行和業務參加,真正實現功能的程式員沒有參與到會議討論中來。
有些項目使用了迭代過程,但由於沒有對知識進行抽象而無法建立起知識體系。開發人員聽專家們描述某項所需的特性,然後開始構建它。他們將結果展示給專家,並詢問接下來做什麼。如果程式員願意進行重構,則能夠保持軟體足夠整潔,以便繼續擴展它;但如果程式員對領域不感興趣,則他們只會瞭解程式應該執行的功能,而不去瞭解它背後的原理。雖然這樣也能開發出可用的軟體,但項目永遠也不會從原有特性中自然地擴展出強大的新特性。
好的程式員會自然而然地抽象並開發出一個可以完成更多工作的模型。但如果在建模時只是技術人員唱獨角戲,而沒有領域專家的協作,那麼得到的概念將是很幼稚的。使用這些膚淺知識開發出來的軟體只能做基本工作,而無法充分反映出領域專家的思考方式。
在團隊所有成員一起消化理解模型的過程中,他們之間的交互也會發生變化。領域模型的不斷精化迫使開發人員學習重要的業務原理,而不是機械地進行功能開發。領域專家被迫提煉自己已知道的重要知識的過程往往也是完善其自身理解的過程,而且他們會漸漸理解軟體項目所必需的概念嚴謹性。
有這些因素都促使團隊成員成為更合格的知識消化者。他們對知識去粗取精。他們將模型重塑為更有用的形式。由於分析員和程式員將自己的知識輸入到了模型中,因此模型的組織更嚴密,抽象也更為整潔,從而為實現提供了更大支持。同時,由於領域專家也將他們的知識輸入到了模型中,因此模型反映了業務的深層次知識,而且真正的業務原則得以抽象。
模型在不斷改進的同時,也成為組織項目信息流的工具。模型聚焦於需求分析。它與編程和設計緊密交互。它通過良性迴圈加深團隊成員對領域的理解,使他們更透徹地理解模型,並對其進一步精化。模型永遠都不會是完美的,因為它是一個不斷演化完善的過程。模型對理解領域必須是切實可用的。它們必須非常精確,以便使應用程式易於實現和理解。
個人理解:對於業務和開發來說,最大的問題是思維想法的同步,同步最大的問題是交流溝通,程式員大部分相對內向沉默,業務有時候也會厭煩重覆的表述,造成理解偏差。建立模型並共同改進精化可以很好的解決這個問題,既然開發人員的思維方式(機器思維)和業務人員的思維方式(功能結果導向思維)不同,那麼就使用一個中間翻譯的語言,這個語言就叫做模型,也是抽象的模型。是大家一起來制定的一種抽象表達方式,每個人都要參與其中,並且不斷進行更新。模型也充當了業務轉化為開發邏輯的一種中間過程表示。
持續學習
當開始編寫軟體時,其實我們所知甚少。項目知識零散地分散在很多人和文檔中,其中夾雜著其他一些無關信息,因此我們甚至不知道哪些知識是真正需要的知識。看起來沒什麼技術難度的領域很可能是一種錯覺——我們並沒意識到不知道的東西究竟有多少。這種無知往往會導致我們做出錯誤的假設。
同時,所有項目都會丟失知識。已經學到了一些知識的人可能幹別的事去了。團隊可能由於重組而被拆散,這導致知識又重新分散開。被外包出去的關鍵子系統可能只交回了代碼,而不會將知識傳遞迴來。而且當使用典型的設計方法時,代碼和文檔不會以一種有用的形式表示出這些來之不易的知識,因此一旦由於某種原因人們沒有口頭傳遞知識,那麼知識就丟失了。
個人理解:團隊的解散,人員的離職或變更,文檔的丟失和散亂,都會使項目組丟失知識,有時候代碼寫完了但是沒有文檔或者註釋(程式員黑話:先開發產品功能,後寫文檔,其實就是懶得寫),別人接手需要經歷非常大的痛苦,然後瘋狂吐槽以前的開發人員。這些都可以歸於知識的丟失。
高效率的團隊需要有意識地積累知識,並持續學習。對於開發人員來說,這意味著既要完善技術知識,也要培養一般的領域建模技巧。但這也包括認真學習他們正在從事的特定領域的知識。那些善於自學的團隊成員會成為團隊的中堅力量,涉及最關鍵領域的開發任務要靠他們來攻剋,這個核心團隊頭腦中積累的知識使他們成為更高效的知識消化者。
關鍵的模型元素被保留下來,早期工作啟動了知識消化的過程,這使得所有後續工作更加高效:團隊成員、開發人員和領域專家等都學到了知識,他們開始使用一種公共的語言,而且形成了貫穿整個實現過程的反饋閉環。
個人理解:所有人都參與,制定模型,學習知識(業務邏輯或者開發思維或者處理流程等等都是知識),後期團隊效率會非常高,就算人員變更,只需要理解開發過程中一起制定的模型就可以了。
知識豐富的設計
當我們的建模不再局限於尋找實體和值對象時,我們才能充分吸取知識,因為業務規則之間可能會存在不一致。領域專家在反覆研究所有規則、解決規則之間的矛盾以及以常識來彌補規則的不足等一系列工作中,往往不會意識到他們的思考過程有多麼複雜。軟體是無法完成這一工作的。正是通過與軟體專家緊密協作來消化知識的過程才使得規則得以澄清和充實,並消除規則之間的矛盾以及刪除一些無用規則。
個人理解:業務或者產品如果不懂開發,會提出一些天馬行空的功能,不會意識到他們的想法實現起來由多複雜。比如:產品經理要程式要開發一個功能,要求app根據手機殼的顏色而改變主題顏色(新聞有報道,產品經理被打了,哈哈哈)。大家一起緊密協作來消化知識,可以消除這些矛盾或者無用的想法。
示例
我們從一個非常簡單的領域模型開始學習,基於此模型的應用程式用來預訂一艘船在一次航程中要運載的貨物
們規定這個應用程式的任務是將每件貨物(Cargo)與一次航程(Voyage)關聯起來,記錄並跟蹤這種關係。現在看來一切都還算簡單。應用程式代碼中可能會有一個像下麵這樣的方法
由於總會有人在最後一刻取消訂單,因此航運業的一般做法是接受比其運載能力多一些的貨物。這稱為“超訂”。有時使用一個簡單的容量百分比來表示,如預訂110%的載貨量。有時則採用複雜的規則——主要客戶或特定種類的貨物優先。這是航運領域的一個基本策略,從事航運業的業務人員都知道它,但在軟體團隊中可能不是所有技術人員都知道這條規則。需求文檔中包含下麵這句話:允許10%的超訂。(這個時候由問題了哈)
現在,一條重要的業務規則被隱藏在上面這段方法代碼內,非常容易誤解,我們主要考慮如何把這條規則更清楚地表達出來,並讓項目中的每個人都能瞭解到它。這將使我們得到一個類似的解決方案。
(1) 如果業務規則如上述代碼所寫,不可能有業務專家會通過閱讀這段代碼來檢驗規則,即使在開發人員的幫助下也無法完成。
(2) 非業務的技術人員很難將需求文本與代碼聯繫起來。如果規則更複雜,情況將更糟。
修改成下麵這樣:
現在所有人都清楚超訂是一個獨特的策略,而且超訂規則的實現即明確又獨立。
現在,我並不建議將這樣的精細設計應用到領域的每個細節中。第15章將深入闡述如何關註重點以及如何隔離其他問題或使這些問題最小化。這個例子的目的是說明領域模型和相應的設計可用來保護和共用知識。更明確的設計具有以下優點:
(1) 為了實現更明確的設計,程式員和其他各位相關人員都必須理解超訂的本質,明白它是一個明確且重要的業務規則,而不只是一個不起眼的計算。
(2) 程式員可以向業務專家展示技術工件,甚至是代碼,但應該是領域專家(在程式員指導下)可以理解的,以便形成反饋閉環。
個人理解:模型要把重要的細節表達出來,不能隱藏的自己知道的認知中(就不告訴別人,說你這樣做就行了,這樣不好),要體現出為什麼是這樣的,是什麼導致必須要加入這個,要讓模型在成為溝通的橋梁時更加明確易懂。
深層模型
有用的模型很少停留在錶面。隨著對領域和應用程式需求的理解逐步加深,我們往往會丟棄那些最初看起來很重要的錶面元素,或者切換它們的角度。這時,一些開始時不可能發現的巧妙抽象就會漸漸浮出水面,而它們恰恰切中問題的要害。
前面的例子大體上是基於一個集裝箱航運項目,這是本書列舉的幾個項目之一,本書還有幾個示例會引用這個項目。本書所舉的示例都很簡單,即使不是航運專家也能理解它們。但在一個需要團隊成員持續學習的真實項目中,要想建立實用且清晰的模型則要求團隊成員既精通領域知識,也要精通建模技術。
在這個項目中,由於航運從預訂貨運開始,因此我們開發了一個能夠描述貨物和運貨航線等事物的模型。這是必要且有用的,但領域專家卻不買賬。他們有自己的考慮業務的方式,這種方式是我們沒有考慮到的。
最後,在經過幾個月的知識消化後,我們知道貨物的處理主要是由轉包商或公司中的操作人員完成的,這包括實際的裝貨、卸貨和運貨。航運專家的觀點是,各部分之間存在一系列的責任傳遞。法律責任和執行責任的傳遞由一個過程式控制制—從托運人傳遞到某個本地運輸商,再從這家運輸商傳遞到另一家運輸商,最後到達收貨人。通常,在一些重要的步驟中,貨物停放在倉庫里。在其他時間里,貨物則是通過複雜的物理步驟來運輸,而這些與航運公司的業務決策無關。在處理航線的物流之前,必須先確定諸如提單等法律文件以及支付流程。
對航運業務有了更深刻的認識後,我們並沒有刪除Itinerary(航線)對象,但模型發生了巨大改變。我們對航運業務的認識從“集裝箱在各個地點之間的運輸”轉變為“運貨責任在各個實體之間的傳遞”。處理這些責任傳遞的特性不再是一些附屬於裝貨作業的次要特性,而是由一個獨立的模型來提供支持,這個模型正是在理解了作業與責任之間的重要關係之後開發出來的。
知識消化是一種探索,它永無止境。
個人理解:隨著對業務的理解更加深刻以後,模型同時也要進行更新,會變得複雜,怎麼辦?開發容易理解的一種形式是:就相當於sql中做子查詢,java開發中就小模塊封裝,大模塊調用函數。模型也是一樣,再做一個新模型,對某一部分功能做抽象,由大模型鏈接過去。例如:a-b-c原來是一個模型,後來增加到a-b-c-c1-c2-c3,c的功能原來越多,這個時候可以做成這樣:模型1是a-b-C,模型C(獨立小模型):c1-c2-c3。這就是深層模型的理解。