最近承諾要寫一篇
tdd和ddd
區別的文章,在比較之前,我這裡會先分別給出乙個ddd的開發例項和tdd的開發例項。這篇文章主要講解ddd。
幾年前,曾接手了別人寫了一半的乙個專案,新加一些功能,然而模型不是很清晰,雖然反映了外部的業務邏輯,但是為了一些新的功能或者特殊案例,我們需要加一些特殊處理。由於模型不夠清晰,原本1天能做的的東西,往往需要4-7天才能做完。
我們需要簡單清晰的模型,這樣往往能夠清晰的表達業務,可能聰明的程式設計師往往不在乎這個,總能夠想出解決特殊的邏輯處理這些問題,然而隨著業務的日漸複雜,特殊邏輯的往往不能完全的表達業務,特殊邏輯越來越多,特殊邏輯之間也產生了很多矛盾,為了解決乙個很簡單的需求,我們要絞盡腦汁,花費大量的精力和資源,大家忙忙碌碌,甚至非常充實,但是鮮有人能夠體會到程式設計的樂趣。
如何建立簡單有效的模型呢?簡單的模型不是簡單的思考,簡單的拍拍大腦就做決定,因為,「simplicity is ultimate sophistication」。簡單清晰的模型,需要乙個智者「慢慢」摸索才能完成(汲取和消化領域知識,挖掘隱含概念),哪怕你是mf或者是eric。
我給出乙個真實的故事,詳細講述實踐domain-driven design過程的所發生的事情。
我們首先大致進行了如下對話:
開發人員:我們就需要做個簡簡單單的對映,根據需求專家的意思。
我:對映?
開發人員:根據系統a的發過來的事故(incident)的資訊,在系統b生成乙個新的事故(incident)的記錄。
我:這是在系統b建立一條記錄,是這樣嗎?
開發人員:是的, 現在的問題是我們系統b的事故(incident)新增了新的屬性,這些屬性是必填項,而傳送的過來的資訊不全,導致一些新的必填資訊為空。
我:如果b系統記錄的屬性發生了變化,a系統需要整合,應該在a系統修改和新增這些屬性。
……經過接近半個小時討論,我得出了以下結論:現在是要發布新版本的系統b,b系統新加了一些特性,導致一些屬性發生了變化,包括增加,刪除和修改,客戶要求發布的版本能夠和系統a能夠整合,但前提是不能修改系統a**。
現在的問題也就是如何決定這些必填項資訊的內容,而並非對映的問題。幾分鐘後,我們繼續了我們的討論:
開發人員:事故(incident)記錄裡還有3個屬性是需要特殊處理的,assignment屬性,urgent屬性和priority屬性要根據事故(incident)所關聯的另外一條記錄資源(ci)的屬性來判斷。
我:怎樣決定這三個屬性值確定了嗎?
開發人員:
我:也就是只有這三個屬性需要一些邏輯判斷來賦值,其他的如果沒有值的話,就是使用配置的預設值了。
開發人員:這3個字段可以由關聯的資源(ci)的任何3個屬性值來決定。
我:ci的3個屬性的值如何決定incident這3個字段。
開發人員:這個還要繼續和需求專家討論。
我:只是用3個ci屬性夠用嗎?
開發人員:目前就是這樣要求的.
目前看來,我能從開發人員那裡得到的資訊差不多就是這些了,然而問題還沒解決,似乎這位開發人員對於某些需求細節還不太清楚,而他已經動手寫完了一部分**,這部分**並未反映這些需求的細節。
為了對需求有更好全面的認識,我和需求專家預定好了時間,展開了討論。
我:新生成的incident有三個字段需要特殊處理,對嗎?
專家:可以是多個。
我發現前面對需求認識開始出現問題了,我開始繼續往下問。
我:能不能給我乙個場景?
專家:如果印表機壞了,a會生成一條資訊傳送給b,b會生成一條incident記錄,這條記錄的ci就是printer,如果不知道應該交由誰處理,即assignment是空,那麼此時,我們就需要找個預設值賦給它。
我:那麼我們需要ci的三個屬性來做什麼邏輯?
專家:目前我們最多提供3個條件來判斷是否使用這些預設值,如果不符合條件,我們就不使用這些預設值。我們還能提供乙個如果不匹配時使用另外一些預設值?
我:當然可以。
專家:整合時,不僅可以建立一條incident記錄,還可以更新或者刪除(這裡指使該條資料狀態為closed,是一種特殊的更新)一條incident記錄。
我們進一步討論的3個條件邏輯:目前使用最簡單的相等來判斷。我也了解到這個版本目前只是實驗性質的,並且這個整合方案由於種種原因,是b軟體單方面的做出的,這個方案最終在以後版本遭否決的程度非常大。了解這些對該功能的開發非常重要。至此,我還沒有畫出來一張模型圖出來和他討論,我承認我在這裡犯了乙個嚴重錯誤,由於未及時畫出模型圖來,也差點導致我接下來的工作重做。
此時雖然我沒有畫出來一張模型圖出來,但是我頭腦已經有一副,如下所示:
incident和configuration之間的關係是一對多:可以建立,更新和刪除時使用這個配置來。
正當我準備編寫**之際,我意識到,模型圖還未來得及和領域專家進一步深究,於是我又找到他做最終的**:
我把我之前腦中的模型圖首先展示給了他,和別的領域專家一樣,一開始他並不了解這些符號的意思,我用2分鐘簡單地講給他多對多的關係和關聯關係,他已經明白這張圖的意思了。
然後,他迅速指出其中乙個細節來:
專家:
我:這個……,為什麼?
看來理解是有出入的。
專家:
我:恩,確實不錯,更加靈活了。
於是我立即修改了模型圖:
別看這個小細節的修改,這可關係到使用者的體驗度和滿意度。我們都知道盲人摸象的故事,有的盲人認為它是蘿蔔,有的卻認為它是柱子……,每個盲人對大象的認識是不同的,片面的,要對大象有個全面的認識,需要摸清大象的每個部位。我們認識領域問題要一步一步地深入挖掘,否則會管中窺豹,時見一斑。
記得前不久,遇到幾位著名公司的「資深」的開發人員,自認為對軟體開發了解獨到,甚至對「面向切面的程式設計」及其不滿。我們討論到乙個實際問題:
他們問道:我這裡有一系統,使用到了workflow,需要通知,當一條記錄發生變化時,需要什麼模式?
就這麼幾句,我努力嘗試更深一步的交流,然而都是徒勞地,他們認為,你懂得設計模式,那麼就不需要了解需求,或者給你及其模糊甚至錯誤的需求,都應該立馬給出令人驚奇的設計,並結合令人驚奇的模式。
我們在上世紀60年代就提出了,軟體必須重視需求,80年代末期,我們意識到,軟體問題已經和開發所使用的語言關係並不緊密了,而要解決了實際問題,我們應該關注與問題域(problem domain),於是為這些領域建模逐漸興起。
雖然這幾位「資深」人士,有的甚至有10年的開發經驗,然而並未了解軟體的核心,雖然,我不懷疑他是否做過軟體設計,但是至少,我想,他們沒有真正設計出oo系統,和讓使用者非常滿意的系統。
末了,上述系統從需求到設計,以及最終的**交付,我花了4天時間,而之前,已經過去2個多月仍未有結果,因為他有興趣的是「兩個系統整合的技術」。
我希望大家能夠明白,軟體的核心是模型,不是演算法,也不是資料結構,也不是技術。儘管這三個方面及其重要,但它們都稱不上是軟體的核心。我們需要智慧型的程式開發人員,需要腳踏實際,一步乙個腳印地去做每一件事,而不是空想自己10分鐘可以做別人10年的工作。
作者簡介:
我是乙個agile和ddd(domain-driven design
我非常推薦eric evans的domain-driven design: tackling complexity in the heart of software
一書,其中**了非常全面的關於領域建模藝術的技術,很多關於ddd的文章和書籍都是基於此書展開的。這本書讓我對軟體設計有了新的認識,很值得細細回味其中某些重要章節。
eric evans的關於folding together ddd into agile
講述了如何把他們結合起來,讀了之後,我獲益甚多。
本人著有書籍《漫談設計模式》
DDD與數字轉型
大平台 把公共能力和核心能力分開建設,解決公共模組重複投入和重複建設的問題。中臺 關鍵字 共享,聯通,融合,創新聯通是前台和中颱之間的聯通。融合是前台流程和資料的融合。然後以共享的方式,支援前端一線業務的發展和創新。它解決了什麼問題?1 核心業務鏈路的聯通和不同渠道服務的共享問題 2 解決系統微服務...
DDD 領域物件與領域服務
什麼是領域物件 什麼是領域服務 領域物件的行為,與領域服務的行為區別 為什麼把這麼小的點拿出來講,最開始在討論中領域物件與領域服務時,覺得行為放在service entity中區別不大,只是乙個放置位置的問題,並不影響到 的抽象和復用,所以沒有實行。但是最近在推動產品進行ddd業務建模,發現這個問題...
DDD之領域服務與領域事件
領域中的服務表示乙個無狀態的操作,它用於實現特定於某個領域的任務。這裡我們要搞清楚什麼樣的操作需要實體,值物件,什麼樣的操作需要採用領域服務。另外,領域服務不是應用服務,在應用服務中我們不需要處理業務邏輯,業務邏輯都落在領域服務中。領域服務發現 領域事件通常是用來與其他聚合解耦的,採用觀察者模式,乙...