當人們要作一個軟件系統時,通常老是由於遇到了什麼問題,而後但願經過一個軟件系統來解決。html
好比,我是一家企業,而後我以爲我如今線下銷售本身的產品還不夠,我但願可以在線上也能銷售本身的產品。因此,天然而然就想到要作一個普通電商系統,用於實如今線銷售本身企業產品的目的。數據庫
再好比,我是一家互聯網公司,公司有不少系統對外提供服務,面向不少客戶端設備。可是最近因爲各類緣由,致使服務常常出故障。因此,咱們但願經過各類措施提升服務的質量和穩定性。其中的一個措施就是但願能作一個灰度發佈的平臺,這個平臺能夠提供灰度發佈的服務。而後,當某個業務系統作了一些修改並須要發佈時,可使用咱們的灰度發佈平臺來很是方便的實現灰度發佈的功能。好比在灰度發佈平臺上方便的定製容許哪些特定的客戶端纔會訪問新服務,哪些客戶端繼續使用老服務。灰度發佈平臺能夠提供各類灰度的策略。有了這樣的灰度發佈機制,那即使系統的新邏輯有什麼問題,受影響的面也不會很大,在可控範圍內。因此,若是公司裏的全部對外提供服務的系統都接入了灰度平臺,那這些系統的發佈環節就能夠更加有保障了。緩存
總之,咱們作任何一個軟件系統,都是有緣由的,不然就不必作這個系統,而這個緣由就是咱們遇到的問題。因此,經過問題,咱們就知道了咱們須要一個什麼樣的系統,這個系統解決什麼樣的問題。最後,咱們就很天然的得出了一個目標,即知道了本身要什麼。好比我要作一個論壇、一個博客系統、一個電商平臺、一個灰度發佈系統、一個IDE、一個分佈式消息隊列、一個通訊框架,等等。數據結構
DDD的全稱爲Domain-driven Design,即領域驅動設計。下面我從領域、問題域、領域模型、設計、驅動這幾個詞語的含義和聯繫的角度去闡述DDD是如何融入到咱們平時的軟件開發初期階段的。要理解什麼是領域驅動設計,首先要理解什麼是領域,什麼是設計,還有驅動是什麼意思,什麼驅動什麼。架構
前面咱們已經清楚的知道咱們如今要作一個什麼樣的系統,這個系統須要解決什麼問題。我認爲任何一個系統都會屬於某個特定的領域,好比論壇是一個領域,只要你想作一個論壇,那這個論壇的核心業務是肯定的,好比都有用戶發帖、回帖等核心基本功能。好比電商平臺、普通電商系統,這種都屬於網上電商領域,只要是這個領域的系統,那都有商品瀏覽、購物車、下單、減庫存、付款交易等核心環節。因此,同一個領域的系統都具備相同的核心業務,由於他們要解決的問題的本質是相似的。併發
所以,咱們能夠推斷出,一個領域本質上能夠理解爲就是一個問題域,只要是同一個領域,那問題域就相同。因此,只要咱們肯定了系統所屬的領域,那這個系統的核心業務,即要解決的關鍵問題、問題的範圍邊界就基本肯定了。一般咱們說,要成爲一個領域的專家,必需要在這個領域深刻研究不少年才行。由於只有你研究了不少年,你纔會遇到很是多的該領域的問題,同時你解決這個領域中的問題的經驗也很是豐富。不少時候,領域專家比技術專家更加吃香,好比金融領域的專家。框架
DDD中的設計主要指領域模型的設計。爲何是領域模型的設計而不是架構設計或其餘的什麼設計呢?由於DDD是一種基於模型驅動開發的軟件開發思想,強調領域模型是整個系統的核心,領域模型也是整個系統的核心價值所在。每個領域,都有一個對應的領域模型,領域模型可以很好的幫咱們解決複雜的業務問題。dom
從領域和代碼實現的角度來理解,領域模型綁定了領域和代碼實現,確保了最終的代碼實現就必定是解決了領域中的核心問題的。由於:1)領域驅動領域模型設計;2)領域模型驅動代碼實現。咱們只要保證領域模型的設計是正確的,就能肯定領域模型能夠解決領域中的核心問題;同理,咱們只要保證代碼實現是嚴格按照領域模型的意圖來落地的,那就能保證最後出來的代碼可以解決領域的核心問題的。這個思路,和傳統的分析、設計、編碼這幾個階段被割裂(而且每一個階段的產物也不一樣)的軟件開發方法學造成鮮明的對比。數據庫設計
上面其實已經提到了,就是:1)領域驅動領域模型設計;2)領域模型驅動代碼實現。這個就和咱們傳統的數據庫驅動開發的思路造成對比了。DDD中,咱們老是以領域爲邊界,分析領域中的核心問題(核心關注點),而後設計對應的領域模型,再經過領域模型驅動代碼實現。而像數據庫設計、持久化技術等這些都不是DDD的核心,而是外圍的東西。分佈式
領域驅動設計(DDD)告訴咱們的最大價值我以爲是:當咱們要開發一個系統時,應該儘可能先把領域模型想清楚,而後再開始動手編碼,這樣的系統後期纔會很好維護。可是,不少項目(尤爲是互聯網項目,爲了趕工)都是一開始模型沒想清楚,一上來就開始建表寫代碼,代碼寫的很是冗餘,徹底是過程是的思考方式,最後致使系統很是難以維護。並且更糟糕的是,出來混老是要還的,前期的領域模型設計的很差,不夠抽象,若是你的系統會長期須要維護和適應業務變化,那後面你必定會遇到各類問題維護上的困難,好比數據結構設計不合理,代碼處處冗餘,改BUG處處引入新的BUG,新人對這種代碼上手困難,等。而那時若是你再想重構模型,那要付出的代價會比一開始從新開發還要大,由於你還要考慮兼容歷史的數據,數據遷移,如何平滑發佈等各類頭疼的問題。因此,就致使咱們最後每天加班。
雖然,咱們都知道這個道理,可是我也明白,人的習慣很難改變的,大部分人都很難從面向過程式的想到哪裏寫到哪裏的思想轉變爲基於系統化的模型驅動的思惟。我想,這或許是DDD很難在中國或國外流行起來的緣由吧。可是,我想這不該該成爲咱們放棄學習DDD的緣由,對吧!
上面咱們經過第一步,雖然咱們明確了要作一個什麼樣的系統,該系統主要解決什麼問題,可是就這樣咱們還沒法開始進行實際的需求分析和模型設計,咱們還必須將咱們的問題進行拆分,需求進行細化。有些時候,需求方,即提出問題的人,極可能本身不清楚具體想要什麼。他只知道一個概念,一個大的目標。好比他只知道要作一個股票交易系統,一個灰度發佈系統,一個電商平臺,一個開發工具,等。可是他不清楚這些系統應該具體作成什麼樣子。這個時候,我認爲領域專家就很是重要了,DDD也很是強調領域專家的重要性。由於領域專家對這個領域很是瞭解,對領域內的各類業務場景和各類業務規則也很是清楚,總之,對這個領域內的一切業務相關的知識都很是瞭解。因此,他們天然就有能力表達出系統該作成什麼樣子。因此,要知道一個系統到底該作成什麼樣子,到底哪些是核心業務關注點,只能靠沉澱領域內的各類知識,別無他法。所以,假設你如今打算作一個電商平臺,可是你對這個領域沒什麼瞭解,那你必定得先去了解下該領域內主流的電商平臺,好比淘寶、天貓、京東、亞馬遜等。這個瞭解的過程就是你沉澱領域知識的過程。若是你不瞭解,就算你領域建模的能力再強,各類技術架構能力再強也是使不上力。領域專家不是某個固定的角色,而是某一類人,這類人對這個領域很是瞭解。好比,一個開發人員也能夠是一個領域專家。假設你在一個公司開發和維護一個系統已經好幾年了,可是這個系統的產品經理(PD)可能已經換過好幾任了,這種狀況下,我相信這幾任產品經理都沒有比你更熟悉這個領域。
上面咱們明白了,領域建模的基礎是要先理解領域,讓本身成爲領域專家。若是作到了這點,咱們就打好了堅實的基礎了。可是,有時一個領域每每太複雜,涉及到的領域概念、業務規則、交互流程太多,致使咱們沒辦法直接針對這個大的領域進行領域建模。因此,咱們須要將領域進行拆分,本質上就是把大問題拆分爲小問題,而後各個擊破的思路。而後既然把一個大的領域劃分爲了多個小的領域(子域),那最關鍵的就是要理清每一個子域的邊界;而後要搞清楚哪些子域是核心子域,哪些是非核心子域,哪些是公共支撐子域;而後,還要思考子域之間的聯繫是什麼。那麼,咱們該如何劃分子域呢?個人我的見解是從業務相關性的角度去思考,也就是咱們平時說的按業務功能爲出發點進行劃分。仍是拿經典的電商系統來分析,一般一個電商系統都會包含好幾個大塊,好比:
上面這些中心看起來很天然,由於你們對電子商務的這個領域都已經很是熟悉了,因此都沒什麼疑問,好像很天然的樣子。因此,領域劃分是否是就是沒什麼挑戰了呢?顯然不是。之因此咱們以爲子域劃分很簡單,是由於咱們對整個大領域很是瞭解了。若是咱們遇到一個冷門的領域,就沒辦法這麼容易的去劃分子域了。這就須要咱們先去努力理解領域內的知識。因此,我我的歷來不相信什麼子域劃分的技巧什麼的東西,由於我以爲這個工做沒有任何訣竅可使用。當咱們不瞭解一個東西的時候,如何去拆解它?當咱們對整個領域有必定的熟悉了,瞭解了領域內的相關業務的本質和關係,咱們就天然而然的能劃分出合理的子域了。不過並非全部的系統都須要劃分子域的,有些系統只是解決一個小問題,這個問題不復雜,可能只有一兩個核心概念。因此,這種系統徹底不須要再劃分子域。但不是絕對的,當一個領域,咱們的關注點愈來愈多,每一個關注點咱們關注的信息愈來愈多的時候,咱們會情不自禁的去進一步的劃分子域。好比,也許咱們一開始將商品和商品的庫存都放在商品中內心,可是後來因爲庫存的維護愈來愈複雜,致使揉在一塊兒對咱們的系統維護帶來必定的困難時,咱們就會考慮將二者進行拆分,這個就是所謂的業務垂直分割。
經過上面的兩步,咱們瞭解了領域裏的知識,也對領域進行了子域劃分。但這樣還不夠,憑這些咱們還沒法進行後續的領域模型設計。咱們還必須再進一步細化每一個子域,進一步明確每一個子域的核心關注點,即需求細化。我以爲咱們須要細化的方面有如下幾點:
從上面這4個方面,咱們從領域概念、業務規則、交互場景、業務流程等維度梳理了咱們到底要什麼,整理了整個系統應該具有的功能。這個工做我以爲是一個很是具備創造性和有難度的工做。咱們一方面會主觀的定義咱們想要什麼;另外一方面,咱們還會思考咱們要的東西的合理性。我認爲這個就是產品經理的工做,產品經理必需要負起職責,把他的產品充分設計好,從各個方面去考慮,如何設計一個產品,才能更好的解決用戶的核心訴求,即領域內的核心問題。若是對領域不夠了解,若是想不清楚用戶到底要什麼,若是思考問題不夠全面,談何設計出一個合理的產品呢?
關於領域概念的梳理,我以爲能夠採用四色原型分析法,這個分析法經過系統的方法,將概念劃分爲不一樣的種類,爲不一樣種類的概念標註不一樣的顏色。而後將這些概念有機的組合起來,從而讓咱們能夠清晰的分析出概念和概念之間的關係。有興趣的同窗能夠在網上搜索下四色原型。
注意:上面我說的這四點,重點是梳理出咱們要什麼功能,而不是思考如何實現這些功能,如何實現是軟件設計人員的職責。
這部份內容,我想學習DDD的人都很熟悉了。DDD原著中提出了不少實用的建模工具:聚合、實體、值對象、工廠、倉儲、領域服務、領域事件。咱們可使用這些工具,來設計每個子域的領域模型。最終經過領域模型圖將設計沉澱下來。要使用這些工具,首先就要理解每一個工具的含義和使用場景。不要覺得很簡單哦,好比聚合的劃分就是一個很是具備藝術的活。同一個系統,不一樣的人設計出來的聚合是徹底不一樣的。並且頗有可能高手之間的最後設計出來的差異反而更大,實際上我認爲是世界觀的相互碰撞,呵呵。因此,要領域建模,我以爲每一個人都應該去學學哲學知識,這有助於咱們更好的認識世界,更好的理解事物的本質。
關於這些建模工具的概念和如何運用我就很少展開了,我博客裏也有不少這方面的介紹。下面我再講一下我認爲比較重要的東西,好比到底該如何領域建模?步驟應該是怎麼樣的?
經過上面我介紹的細化子域的內容,如今再來談該如何領域建模,我以爲就方便不少了。個人主要方法是:
下圖是我最近作個一個普通電商系統的商品中心的領域模型圖,給你們參考:
須要特別注意的是,領域模型設計只是整個軟件設計中的很小一部分。除了領域模型設計以外,要落地一個系統,咱們還有很是多的其餘設計要作,好比:
等等。上面這些都須要咱們平時的大量學習和積累。做爲一個合格的開發人員或架構師,我以爲除了要會DDD領域驅動設計,還要會上面這麼多的技術能力,確實是很是不容易的。因此,千萬不要覺得會DDD了就覺得本身很牛逼,實際上你會的只是軟件設計中的冰山一角而已。
本文的重點是基於我我的對DDD的一些理解,但願能整理出一些本身總結出來的一些感悟和經驗,並分享給你們。我相信不少人已經看過太多DDD書上的東西,我老是感受書上的東西看似都太」正規「,不少時候咱們讀了以後很難消化,就算理解了書裏的內容,當咱們想要運用到實踐中時,老是感受無從下手。本文但願經過通俗易懂的文字,介紹了一部分我對DDD的學習感悟和實踐心得,但願能給你們一些啓發和幫助。