DDD與TDD比較之 DDD

2021-09-01 07:24:51 字數 4230 閱讀 1312

最近承諾要寫一篇

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之領域服務與領域事件

領域中的服務表示乙個無狀態的操作,它用於實現特定於某個領域的任務。這裡我們要搞清楚什麼樣的操作需要實體,值物件,什麼樣的操作需要採用領域服務。另外,領域服務不是應用服務,在應用服務中我們不需要處理業務邏輯,業務邏輯都落在領域服務中。領域服務發現 領域事件通常是用來與其他聚合解耦的,採用觀察者模式,乙...