1. 程式人生 > >領域驅動戰略設計實踐

領域驅動戰略設計實踐

課程介紹

國內關於領域驅動設計(Domain Driven Design,DDD)的原創書籍少之又少,甚至可以說沒有,作者結合十餘年實踐領域驅動設計的經驗與心得,並糅合了 DDD 社群最新發展的理論知識與最佳實踐,策劃了《領域驅動設計實踐》系列課程,可以稱得上是一個全面系統講解 DDD 的原創課程

本系列課程拆分為兩個課程,即《領域驅動戰略設計實踐》和《領域驅動戰術設計實踐》,分別對應領域驅動設計的戰略設計階段與戰術設計階段。

本課程全面覆蓋了領域建模分析與架構設計的戰略設計過程。從剖析軟體複雜度的根源開始,引入了領域場景分析與敏捷專案實踐,幫助需求分析人員與軟體設計人員分析軟體系統的問題域、提煉真實表達的領域知識、最終建立系統的統一語言。

本課程將主流架構設計思想、微服務架構設計原則與領域驅動設計中屬於戰略設計層面的限界上下文、上下文對映、分層架構結合起來,完成從需求到架構設計再到構建程式碼模型的架構全過程。

此外,本課程內容的每一個知識點都會結合專案實踐案例來講解,力求內容的深入淺出,並在講解過程中介紹了諸多架構設計原則與模式,豐富了知識內涵,但又不僅只限於對領域驅動設計的覆蓋。同時,本課程也可以作為軟體架構設計的參考書。

為了讓讀者更容易掌握整個戰略設計的全過程,最後還給出了一個真實的完整案例:EAS 系統,結合該案例來講解如何在專案實踐中進行領域建模分析、識別限界上下文,並最終構建整個系統的架構。

專家推薦

張逸不但擁有過硬的領域驅動設計實踐經驗,而且是一位能夠深入淺出的闡釋者。這兩項特質保證大家能夠收穫滿滿!

——肖然,ThoughtWorks 諮詢總監、精益敏捷專家

我做了多年大規模微服務架構,也見了許多微服務實施案例,其中做得好的無一例外對領域模型有了深入的分析,做得不好的往往只關注工具和框架而忽略了領域模型。張逸是國內 DDD 領域少有的專家,我向大家推薦他的《領域驅動設計實踐》系列課程。

——許曉斌,阿里巴巴高階技術專家

國內同仁寫的軟體需求設計方面的圖書,我都有收集,但能認真閱讀的不多。張逸寫的書是少數我認真閱讀過的,推薦給大家。

——潘加宇,UMLChina 首席專家

張逸兄有廣博的知識體系和強悍的動手實踐能力,是國內技術圈較早翻譯國外知識理論的先鋒之一,並對領域驅動設計有較深入的思考和不斷精進的乾貨總結,可以帶領讀者一窺 DDD 門徑。

——右軍,螞蟻金服資深技術專家

作者介紹

張逸,曾先後就職於中興通訊、惠普 GDCC、中軟國際、ThoughtWorks 等大型中外企業,任職角色為高階軟體工程師、架構師、技術總監、首席諮詢師。精通包括 Java、Scala、Python、C#、JavaScript、Ruby 等多種語言,熟練掌握面向物件思想、測試驅動開發與重構、領域驅動設計、函數語言程式設計、架構、大資料分析、敏捷與過程改進,並致力於大型軟體企業的面向服務系統架構設計、大資料平臺架構設計以及網際網路 Web 系統架構設計。

著譯作包括《軟體設計精要與模式》、《Java 設計模式》、《恰如其分的軟體架構》、《WCF 服務程式設計》、《人件》、《重構——改善既有程式碼設計》評註版、以及《架構之美(Beatiful Architecture)》評註版。個人微信公眾號為「逸言」、個人部落格

課程大綱

本課程大綱分為五大部分,共計 36 篇:

enter image description here

* 實際更新文章題目可能與框架略有出入
* 補充一篇 GitChat 平臺獨家訪談錄(7.26)

課程內容

訪談錄 | 聊聊領域驅動設計(文字版)

相信很多朋友對領域驅動設計會有這樣或那樣的困惑,比如領域驅動設計是什麼?它在工作中有什麼作用?為什麼國內關於這方面的書籍少之又少?…… 為了解決這些疑惑,有幸邀請到專家張逸老師來聊聊領域驅動設計,下面是 GitChat 獨家採訪記錄。

GitChat:領域驅動設計(Domain Driven Design,DDD)自誕生以來已有十幾年時間,這門本已步入老年的方法學卻因為微服務的興起而煥發了第二春。您說過這可能要歸功於 DDD 的“堅硬生長”,但不可否認微服務確實也是一個重要因素,能否請您解釋一下領域驅動設計微服務這種深層次的匹配關係?

張逸:領域驅動設計是由 Eric Evans 在一本《領域驅動設計》書中提出的,它是針對複雜系統設計的一套軟體工程方法;而微服務是一種架構風格,一個大型複雜軟體應用是由一個或多個微服務組成的,系統中的各個微服務可被獨立部署,各個微服務之間是鬆耦合的,每個微服務僅關注於完成一件任務並很好地完成該任務。

兩者之間更深入的關係,在我寫的課程中已有詳細講解。主要體現在領域驅動設計中限界上下文與微服務之間的對映關係。假如限界上下文之間需要跨程序通訊,並形成一種零共享架構,則每個限界上下文就成為了一個微服務。在微服務架構大行其道的當今,我們面臨的一個棘手問題是:如何識別和設計微服務?領域驅動的戰略設計恰好可以在一定程度上解決此問題。

GitChat:如果說輕量化處理、自動部署,以及容器技術的發展使得微服務的興起成為必然,那麼是否可以說領域驅動設計今日的再續輝煌也是一種必然(或者說 DDD 在其誕生之時過於超前)?您能否預測一下 DDD 未來可能會和什麼樣的新理念相結合?

張逸:好像領域驅動設計就從未真正“輝煌”過,所以談不上再續輝煌,但確實是因為微服務引起了社群對它的重燃熱情。推行領域驅動設計確乎有許多阻力,一方面要做到純粹的領域驅動設計,許多團隊成員的技能達不到;另一方面,似乎領域驅動設計帶來的價值不經過時間的推移無法彰顯其價值,這就缺乏足夠的說服力讓一家公司不遺餘力地去推廣領域驅動設計。微服務似乎給了我們一個推動領域驅動設計的理由!因為軟體系統的微服務化已經成為了一種潮流,領域驅動設計又能夠為微服務化保駕護航,還有什麼理由不推行呢?

我個人認為,未來 DDD 的發展可能會出現以下趨勢:

  • 以函數語言程式設計思想為基礎的領域建模理念與事件驅動架構和響應式程式設計的結合,可能在低延遲高併發的專案中發揮作用。這種領域驅動設計思想已經比較成熟,但目前還沒有看到太多成功的運用。
  • 以 DDD 設計方法為基礎的框架的出現,讓微服務設計與領域建模變得更加容易,降低領域驅動設計的門檻。

GitChat:能否儘可能地詳細(或舉例)說明您在閱讀並審校《實現領域驅動設計》一書時所認識到的領域驅動設計的本質—— 一個開放的設計方法體系 ——是什麼?

張逸:在《實現領域驅動設計》一書中,Vernon 不僅對整個領域驅動設計過程作了一番有益的梳理,還結合社群發展在書中引入了六邊形架構和領域事件等概念,這為當時的我打開了一扇全新的窗戶——原來領域驅動設計並不是一套死板的方法,而是一種設計思想、一種開放的設計方法體系,只要有利於領域驅動設計的實踐,都可以引入其中。於是,在我的書中我才敢於大膽地引入用例、敏捷實踐、整潔架構,以期為領域驅動設計提供補充。

Eric Evans 的《領域驅動設計》是以面向物件設計作為模型驅動設計的基礎,但時下被頻繁運用的函數語言程式設計思想也給模型驅動設計帶來了另一種視角。從開放的設計方法體系的角度講,我們完全可以把更多的程式設計正規化引入到領域驅動設計中。因為有了更多的選擇,針對不同的業務場景就可以選擇更適合的 DDD 實踐,而不僅僅限於 Eric Evans 最初提出的範疇。

點選瞭解《領域驅動戰略設計實踐》

GitChat:團隊內外成員之間的協作與溝通一直以來都是個難題,也是大家經常喜歡調侃的話題之一,能否舉例說明一下領域驅動設計是如何解決這一問題的?

張逸:我覺得這個問題問反了。領域驅動設計解決不了這個問題,它只是重視這個問題;相反,我們應該說只有解決了團隊內外成員之間的協作與溝通,才能更好地進行領域驅動設計。為此,我嘗試用一些敏捷實踐來解決這種協作問題。

GitChat:您在學習和實踐領域驅動設計的過程中是否有哪些(有趣的)故事可以和讀者們分享?

張逸:我在 ThoughtWorks 的時候,公司邀請《實現領域驅動設計》作者 Vaughn Vernon 到北京 Office 給我們做了一次 DDD 培訓。藉著這次親炙大師教誨的機會,我向他請教了一個一直纏繞在我心中困惑不解的問題:“如何正確地識別限界上下文?”結果他思考了一會兒,嚴肅地回答了我:“By experience!” 我唯有無言以對。

GitChat:有很多讀者對您即將在課程中給出全真案例“EAS 系統”很感興趣,能否簡單介紹一下這個案例以及它在實際應用中的意義?

張逸:EAS 系統是我之前做過的一個真實專案,之所以選擇這個專案來作為這個課程的全真案例,原因如下:

  • 學習 DDD 必須理論聯絡實際。雖然在我寫的課程內容中已經結合理論講解提供了較多的實際案例,但這些零散的案例無法給讀者提供一個整體的印象。
  • EAS 系統的業務知識門檻相對較低,不至於因為不熟悉領域知識而影響對 DDD 的學習。
  • EAS 系統具備一定的業務複雜度,既適合戰略設計階段,又適合戰術階段。

GitChat:您提到這次的 DDD 系列課程分為《領域驅動戰略設計實踐》和《領域驅動戰術設計實踐》兩部分,這兩個課程在內容設計上側重有什麼不同?很多讀者關心《領域驅動戰術設計實踐》何時釋出,可否透露一下?

張逸:這兩個課程對應於 DDD 的戰略設計階段與戰術設計階段,粗略地說,前者更偏向於架構,後者更偏向於設計與編碼。事實上,就我個人的規劃來說,計劃還有第三部分,是圍繞著函數語言程式設計講解與 DDD 有關的實踐,包括 EDA、CQRS、Domain Event 等知識。

目前,《領域驅動戰略設計實踐》還有最後幾個章節沒有完成。一旦完成後,就可以開始撰寫《領域驅動戰術設計實踐》內容了。當然,戰術設計的相關內容已有部分初稿,我爭取能夠在 11 月釋出這部分內容。

GitChat:您覺得這門課的學員/讀者應該是什麼樣的人?對於這些人,要想掌握領域驅動設計乃至在專業領域更上一層樓,您有哪些學習建議?

張逸:學習課程的學員/讀者最好要有一定的軟體設計能力,並對 DDD 學習抱有好奇心,希望能夠將 DDD 學以致用。

學習建議:

  • 積累領域知識,以提高溝通與協作能力;
  • 以 Eric Evans 的《領域驅動設計》為主體,廣泛涉獵與 DDD 相關的書籍與文章,並關注 DDD 社群的最新知識;
  • 要善於總結,理清 DDD 中各個概念之間的區別與應用場景。

GitChat:作為一位曾就職於中興、惠普、中軟、ThoughtWorks 等大型中外企業的架構師/技術總監/首席諮詢師,在職業發展方面,您對您的讀者們有哪些建議?

張逸:我之前在 ThoughtWorks 的同事鄭燁(校長)給我提過一個建議,就是打造自己的技術標籤。例如,現在 DDD 就成為了我其中的一個技術標籤了。這個說法的內在含義,就是要尋找和定位自己的技術發展方向,然後往更深的方向鑽研,最終成為這個方向的技術專家。因此,結合自己的能力特長、興趣點以及技術發展趨勢去規劃自己的技術發展方向,才是技術人員最應該思考並踐行的。

到這裡,訪談錄的內容就結束了,大家若對 DDD 的內容比較感興趣的話,歡迎訂閱本課程,有任何關於本課程內容的疑惑可在讀者圈留言給張逸老師,張老師會很積極的解答每一個問題~

點選瞭解《領域驅動戰略設計實踐》

開篇詞 | 領域驅動設計,重煥青春的設計經典

課程背景

領域驅動設計確實已不再青春,從 Eric Evans 出版的那本劃時代的著作《領域驅動設計》至今,已有將近十五年的時間,在軟體設計領域中,似乎可以稱得上是步入老年時代了。可惜的是,對於這樣一個在國外 IT 圈享有盛譽並行之有效的設計方法學,國內大多數的技術人員卻並不瞭解,也未曾運用到專案實踐中,真可以說是知音稀少。領域驅動設計似乎成了一門悄悄發展的隱學,它從來不曾大行其道,卻依舊頑強地發揮著出人意料的價值。

直到行業內吹起微服務的熱風,人們似乎才重新發現了領域驅動設計的價值,並不是微服務拯救了領域驅動設計,是因為領域驅動設計一直在堅硬的生長,然而看起來,確乎因為微服務,領域驅動設計才又煥發了青春。

我從 2006 年開始接觸領域驅動設計,一開始我就發現了它的魅力並沉迷其間。從閱讀 Eric Evans 的《領域驅動設計》入門,然後嘗試在軟體專案中運用它,也取得了一定成效。然而,我的學習與運用一直處於摸索之中,始終感覺不得其門而入,直到有機會拜讀 Vaughn Vernon 出版的《實現領域驅動設計》一書,並負責該書的審校工作,我才觸控到了領域驅動從戰略設計到戰術設計的整體脈絡,並瞭解其本質:領域驅動設計是一個開放的設計方法體系

即使如此,許多困惑與謎題仍然等待我去發現線索和答案。設計總是如此,雖然前人已經總結了許多原則與方法,卻不能像數學計算那樣,按照公式與公理進行推導就一定能得到準確無誤的結果。設計沒有唯一的真相。

即使如此,如果我們能夠走在邁向唯一真相的正確道路上,那麼每前進一步,就會離這個理想的唯一真相更近一步,這正是我推出這門課的初衷。也並不是說我貼近了唯一真相,更不是說我已經走在了正確道路上,但我可以自信地說,對於領域驅動設計,我走在了大多數開發人員的前面,在我發現了更多新奇風景的同時,亦走過太多荒蕪的分岔小徑,經歷過太多坎坷與陷阱。我嘗試著解答領域驅動設計的諸多謎題,期望能從我的思考與實踐中發現正確道路的蛛絲馬跡。我寫的這門課程正是我跌跌撞撞走過一路的風景拍攝與路徑引導,就好似你要去銀河系旅遊,最好能有一本《銀河系漫遊指南》在手一樣,不至於迷失在浩瀚的星空之中,我期待這門課程能給你帶來這樣的指導。

課程框架

本課程是我計劃撰寫的領域驅動設計實踐系列的第一部分內容(第二部分內容是領域驅動戰術設計實踐,後面陸續更新),其全面覆蓋了領域建模分析與架構設計的戰略設計過程,從剖析軟體複雜度的根源開始,引入了領域場景分析與敏捷專案實踐,幫助需求分析人員與軟體設計人員分析軟體系統的問題域,提煉真實表達的領域知識,最終建立系統的統一語言。同時,本課程將主流架構設計思想、微服務架構設計原則與領域驅動設計中屬於戰略設計層面的限界上下文、上下文對映、分層架構結合起來,完成從需求到架構設計再到構建程式碼模型的架構全過程。

本課程分為五部分,共計 34 篇。

開篇詞:領域驅動設計,重煥青春的設計經典

第一部分(第01~05課):軟體複雜度

  • 領域驅動設計的目的是應對軟體複雜度。本部分內容以簡練的筆觸勾勒出了領域驅動設計的全貌,然後深入剖析了軟體複雜度的本質,總結了控制軟體複雜度的原則,最終給出了領域驅動設計應對軟體複雜度的基本思想與方法。

第二部分(第06~10課):領域知識

  • 領域驅動設計的核心是“領域”,也是進行軟體設計的根本驅動力。因此,團隊在進行領域驅動設計時,尤其需要重視團隊內外成員之間的協作與溝通。本部分內容引入了敏捷開發思想中的諸多實踐,並以領域場景分析為主線講解了如何提煉領域知識的方法。

第三部分(第11~20課):限界上下文

  • 限界上下文是領域驅動設計最重要的設計要素,我們需要充分理解限界上下文的本質與價值,突出限界上下文對業務、團隊與技術的“控制”能力。
  • 提出了從業務邊界、工作邊界到應用邊界分階段分步驟迭代地識別限界上下文的過程方法,使得領域驅動設計的新手能夠有一個可以遵循的過程來幫助識別限界上下文。
  • 剖析上下文對映,確定限界上下文之間的協作關係,進一步幫助我們合理地設計限界上下文。

第四部分(第21~28課):架構與程式碼模型

  • 作為一個開放的設計方法體系,本部分引入了分層架構、整潔架構、六邊形架構與微服務架構等模式,全面剖析了領域驅動設計的架構思想與原則。
  • 結合限界上下文,並針對限界上下文的不同定義,對領域驅動的架構設計進行了深度探索,給出了滿足整潔架構思想的程式碼模型。

第五部分(第29~33課):EAS 系統的戰略設計實踐

  • 給出一個全真案例——EAS 系統,運用各篇介紹的設計原則、模式與方法對該系統進行全方位的戰略設計,並給出最終的設計方案。

本課程並非是對 Eric Evans《領域驅動設計》的蕭規曹隨,而是吸納了領域驅動設計社群的各位專家大師提出的先進知識,並結合我多年來運用領域驅動設計收穫的專案經驗,同時還總結了自己在領域驅動設計諮詢與培訓中對各種困惑與問題的思考與解答。本課程內容既遵循了領域驅動設計的根本思想,又有自己的獨到見解;既給出了權威的領域驅動知識闡釋,又解答了在實踐領域驅動設計中最讓人困惑的問題。

為什麼要學習領域驅動設計

如果你已經能設計出美麗優良的軟體架構,如果你只希望腳踏實地做一名高效編碼的程式設計師,如果你是一位注重使用者體驗的前端設計人員,如果你負責的軟體系統並不複雜,那麼,你確實不需要學習領域驅動設計!

領域驅動設計當然並非“銀彈”,自然也不是解決所有疑難雜症的“靈丹妙藥”,請事先降低對領域驅動設計的不合現實的期望。我以中肯地態度總結了領域驅動設計可能會給你帶來的收穫:

  • 領域驅動設計是一套完整而系統的設計方法,它能帶給你從戰略設計到戰術設計的規範過程,使得你的設計思路能夠更加清晰,設計過程更加規範。
  • 領域驅動設計尤其善於處理與領域相關的高複雜度業務的產品研發,通過它可以為你的產品建立一個核心而穩定的領域模型核心,有利於領域知識的傳遞與傳承。
  • 領域驅動設計強調團隊與領域專家的合作,能夠幫助團隊建立一個溝通良好的團隊組織,構建一致的架構體系。
  • 領域驅動設計強調對架構與模型的精心打磨,尤其善於處理系統架構的演進設計。
  • 領域驅動設計的思想、原則與模式有助於提高團隊成員的面向物件設計能力與架構設計能力。
  • 領域驅動設計與微服務架構天生匹配,無論是在新專案中設計微服務架構,還是將系統從單體架構演進到微服務設計,都可以遵循領域驅動設計的架構原則。

課程寄語

沒有誰能夠做到領域驅動設計的一蹴而就,一門課程也不可能窮盡領域驅動設計的方方面面,從知識的學習到知識的掌握,進而達到能力的提升,需要一個漫長的過程。所謂“理論聯絡實際”雖然是一句耳熟能詳的老話,但其中蘊含了顛撲不破的真理。我在進行領域驅動設計培訓時,總會有學員希望我能給出數學公式般的設計準則或規範,似乎軟體設計就像拼積木一般,只要遵照圖示中給出的拼搭過程,不經思考就能拼出期待的模型。——這是不切實際的幻想。

要掌握領域驅動設計,就不要被它給出的概念所迷惑,而要去思索這些概念背後蘊含的原理,多問一些為什麼。同時,要學會運用設計原則去解決問題,而非所謂的“設計規範”。例如:

  • 思考限界上下文邊界的劃分,實際上還是“高內聚、低耦合”原則的體現,只是我們需要考慮什麼內容才是高內聚的,如何抽象才能做到低耦合?
  • 是否需要提取單獨的限界上下文?是為了考慮職責的重用,還是為了它能夠獨立進化以應對未來的變化?
  • 在分層架構中,各層之間該如何協作?如果出現了依賴,該如何解耦?仍然需要從重用與變化的角度去思考設計決策。
  • 為什麼同樣遵循領域驅動設計,不同的系統會設計出不同的架構?這是因為不同的場景對架構質量的要求並不一樣,我們要學會對架構的關注點做優先順序排列,從而得出不同的架構決策。

我強烈建議讀者諸君要學會對設計的本質思考,不要只限於對設計概念的掌握,而要追求對設計原則與方法的融匯貫通。只有如此,才能針對不同的業務場景靈活地運用領域驅動設計,而非像一個牽線木偶般遵照著僵硬的過程進行死板地設計。

點選瞭解《領域驅動戰略設計實踐》

第01課:領域驅動設計概覽

領域驅動設計(Domain Driven Design,DDD)是由 Eric Evans 最早提出的綜合軟體系統分析和設計的面向物件建模方法,如今已經發展成為了一種針對大型複雜系統的領域建模與分析方法。它完全改變了傳統軟體開發工程師針對資料庫進行的建模方法,從而將要解決的業務概念和業務規則轉換為軟體系統中的型別以及型別的屬性與行為,通過合理運用面向物件的封裝、繼承和多型等設計要素,降低或隱藏整個系統的業務複雜性,並使得系統具有更好的擴充套件性,應對紛繁多變的現實業務問題。

領域驅動設計的開放性

領域驅動設計是一種方法論(Methodology),根據維基百科的定義,方法論是一套運用到某個研究領域的系統與理論分析方法。領域驅動設計就是針對軟體開發領域提出的一套系統與理論分析方法。Eric Evans 在創造性地提出領域驅動設計時,實則是針對當時專案中聚焦在以資料以及資料樣式為核心的系統建模方法的批判。面向資料的建模方法是關係資料庫理論的延續,關注的是資料表以及資料表之間關係的設計。這是典型的面向技術實現的建模方法,面對日漸複雜的業務邏輯,這種設計方法欠缺靈活性與可擴充套件性,也無法更好地利用面向物件設計思想及設計模式,建立可重用的、可擴充套件的程式碼單元。領域驅動設計的提出,是設計觀念的轉變,蘊含了全新的設計思想、設計原則與設計過程

由於領域驅動設計是一套方法論,它建立了以領域為核心驅動力的設計體系,因而具有一定的開放性。在這個體系中,你可以使用不限於領域驅動設計提出的任何一種方法來解決這些問題。例如,可以使用用例(Use Case)、測試驅動開發(TDD)、使用者故事(User Story)來幫助我們對領域建立模型;可以引入整潔架構思想及六邊形架構,以幫助我們建立一個層次分明、結構清晰的系統架構;還可以引入函數語言程式設計思想,利用純函式與抽象代數結構的不變性以及函式的組合性來表達領域模型。這些實踐方法與模型已經超越了 Eric Evans 最初提出的領域驅動設計範疇,但在體系上卻是一脈相承的。這也是為什麼在領域驅動設計社群,能夠不斷誕生新的概念諸如 CQRS 模式、事件溯源(Event Sourcing)模式與事件風暴(Event Storming);領域驅動設計也以開放的心態擁抱微服務(Micro Service),甚至能夠將它的設計思想與原則運用到微服務架構設計中。

領域驅動設計過程

領域驅動設計當然不是架構方法,也並非設計模式。準確地說,它其實是“一種思維方式,也是一組優先任務,它旨在加速那些必須處理複雜領域的軟體專案的開發”。領域驅動設計貫穿了整個軟體開發的生命週期,包括對需求的分析、建模、架構、設計,甚至最終的編碼實現,乃至對編碼的測試與重構。

領域驅動設計強調領域模型的重要性,並通過模型驅動設計來保障領域模型與程式設計的一致。從業務需求中提煉出統一語言(Ubiquitous Language),再基於統一語言建立領域模型;這個領域模型會指導著程式設計以及編碼實現;最後,又通過重構來發現隱式概念,並運用設計模式改進設計與開發質量。這個過程如下圖所示:

enter image description here

這個過程是一個覆蓋軟體全生命週期的設計閉環,每個環節的輸出都可以作為下一個環節的輸入,而在其中扮演重要指導作用的則是“領域模型”。這個設計閉環是一個螺旋式的迭代設計過程,領域模型會在這個迭代過程中逐漸演進,在保證模型完整性與正確性的同時,具有新鮮的活力,使得領域模型能夠始終如一的貫穿領域驅動設計過程、闡釋著領域邏輯、指導著程式設計、驗證著編碼質量。

如果仔細審視這個設計閉環,會發現在針對問題域和業務期望提煉統一語言,並通過統一語言進行領域建模時,可能會面臨高複雜度的挑戰。這是因為對於一個複雜的軟體系統而言,我們要處理的問題域實在太龐大了。在為問題域尋求解決方案時,需要從巨集觀層次劃分不同業務關注點的子領域,然後再深入到子領域中從微觀層次對領域進行建模。巨集觀層次是戰略的層面,微觀層次是戰術的層面,只有將戰略設計與戰術設計結合起來,才是完整的領域驅動設計。

戰略設計階段

領域驅動設計的戰略設計階段是從下面兩個方面來考量的:

  • 問題域方面:針對問題域,引入限界上下文(Bounded Context)上下文對映(Context Map)對問題域進行合理的分解,識別出核心領域(Core Domain)子領域(SubDomain),並確定領域的邊界以及它們之間的關係,維持模型的完整性。
  • 架構方面:通過分層架構來隔離關注點,尤其是將領域實現獨立出來,能夠更利於領域模型的單一性與穩定性;引入六邊形架構可以清晰地表達領域與技術基礎設施的邊界;CQRS 模式則分離了查詢場景和命令場景,針對不同場景選擇使用同步或非同步操作,來提高架構的低延遲性與高併發能力。

Eric Evans 提出戰略設計的初衷是要保持模型的完整性。限界上下文的邊界可以保護上下文內部和其他上下文之間的領域概念互不衝突。然而,如果我們將領域驅動設計的戰略設計模式引入到架構過程中,就會發現限界上下文不僅限於對領域模型的控制,而在於分離關注點之後,使得整個上下文可以成為獨立部署的設計單元,這就是“微服務”的概念,上下文對映的諸多模式則對應了微服務之間的協作。因此在戰略設計階段,微服務擴充套件了領域驅動設計的內容,反過來領域驅動設計又能夠保證良好的微服務設計。

一旦確立了限界上下文的邊界,尤其是作為物理邊界,則分層架構就不再針對整個軟體系統,而僅僅針對粒度更小的限界上下文。此時,限界上下文定義了技術實現的邊界,對當前上下文的領域與技術實現進行了封裝,我們只需要關心對外暴露的介面與整合方式,形成了在服務層次的設計單元重用。

邊界給了實現限界上下文內部的最大自由度,這也是戰略設計在分治上起到的效用,我們可以在不同的限界上下文選擇不同的架構模式。例如,針對訂單的查詢與處理,選擇 CQRS 模式來分別處理同步與非同步場景;還可以針對核心領域與子領域重要性的不同,分別選擇領域模型(Domain Model)和事務指令碼(Transaction Script)模式,靈活地平衡開發成本與開發質量。在巨集觀層面,面對整個軟體系統,我們可以採用前後端分離與基於 REST 的微服務架構,保證系統具有一致的架構風格。

戰術設計階段

整個軟體系統被分解為多個限界上下文(或領域)後,就可以分而治之,對每個限界上下文進行戰術設計。領域驅動設計並不牽涉到技術層面的實現細節,在戰術層面,它主要應對的是領域的複雜性。領域驅動設計用以表示模型的主要要素包括:

  • 值物件(Value Object)
  • 實體(Entity)
  • 領域服務(Domain Service)
  • 領域事件(Domain Event)
  • 資源庫(Repository)
  • 工廠(Factory)
  • 聚合(Aggregate)
  • 應用服務(Application Service)

Eric Evans 通過下圖勾勒出了戰術設計諸要素之間的關係:

enter image description here

領域驅動設計圍繞著領域模型進行設計,通過分層架構(Layered Architecture)將領域獨立出來。表示領域模型的物件包括:實體值物件領域服務領域邏輯都應該封裝在這些物件中。這一嚴格的設計原則可以避免業務邏輯滲透到領域層之外,導致技術實現與業務邏輯的混淆。在領域驅動設計的演進中,又引入了領域事件來豐富領域模型。

聚合是一種邊界,它可以封裝一到多個實體值物件,並維持該邊界範圍之內的業務完整性。在聚合中,至少包含一個實體,且只有實體才能作為聚合根(Aggregate Root)。注意,在領域驅動設計中,沒有任何一個類是單獨的聚合,因為聚合代表的是邊界概念,而非領域概念。在極端情況下,一個聚合可能有且只有一個實體。

工廠資源庫都是對領域物件生命週期的管理。前者負責領域物件的建立,往往用於封裝複雜或者可能變化的建立邏輯;後者則負責從存放資源的位置(資料庫、記憶體或者其他 Web 資源)獲取、新增、刪除或者修改領域物件。領域模型中的資源庫不應該暴露訪問領域物件的技術實現細節。

演進的領域驅動設計過程

戰略設計會控制和分解戰術設計的邊界與粒度,戰術設計則以實證角度驗證領域模型的有效性、完整性與一致性,進而以演進的方式對之前的戰略設計階段進行迭代,從而形成一種螺旋式上升的迭代設計過程,如下圖所示:

enter image description here

面對客戶的業務需求,由領域專家與開發團隊展開充分的交流,經過需求分析與知識提煉,以獲得清晰的問題域。通過對問題域進行分析和建模,識別限界上下文,利用它劃分相對獨立的領域,再通過上下文對映建立它們之間的關係,輔以分層架構與六邊形架構劃分系統的邏輯邊界與物理邊界,界定領域與技術之間的界限。之後,進入戰術設計階段,深入到限界上下文內對領域進行建模,並以領域模型指導程式設計與編碼實現。若在實現過程中,發現領域模型存在重複、錯位或缺失時,再進而對已有模型進行重構,甚至重新劃分限界上下文。

兩個不同階段的設計目標是保持一致的,它們是一個連貫的過程,彼此之間又相互指導與規範,並最終保證一個有效的領域模型和一個富有表達力的實現同時演進

點選瞭解《領域驅動戰略設計實踐》

第02課:深入分析軟體的複雜度

軟體複雜度的成因

Eric Evans 的經典著作《領域驅動設計》的副標題為“軟體核心複雜性應對之道”,這說明了 Eric 對領域驅動設計的定位就是應對軟體開發的複雜度。Eric 甚至認為:“領域驅動設計只有應用在大型專案上才能產生最大的收益”。他通過 Smart UI 反模式逆向地說明了在軟體設計與開發過程中如果出現瞭如下問題,就應該考慮運用領域驅動設計:

  • 沒有對行為的重用,也沒有對業務問題的抽象,每當操作用到業務規則時,都要重複這些業務規則。
  • 快速的原型建立和迭代很快會達到其極限,因為抽象的缺乏限制了重構的選擇。
  • 複雜的功能很快會讓你無所適從,所以程式的擴充套件只能是增加簡單的應用模組,沒有很好的辦法來實現更豐富的功能。

因此,選擇領域驅動設計,就是要與軟體系統的複雜作一番殊死拼搏,以降低軟體複雜度為己任。那麼,什麼才是複雜呢?

點選瞭解《領域驅動戰略設計實踐》

什麼是複雜?

即使是研究複雜系統的專家,如《複雜》一書的作者 Melanie Mitchell,都認為複雜沒有一個明確得到公認的定義。不過,Melanie Mitchell 在接受 Ubiquity 雜誌專訪時,還是“勉為其難”地給出了一個通俗的複雜系統定義:由大量相互作用的部分組成的系統,與整個系統比起來,這些組成部分相對簡單,沒有中央控制,組成部分之間也沒有全域性性的通訊,並且組成部分的相互作用導致了複雜行為。

這個定義庶幾可以表達軟體複雜度的特徵。定義中的組成部分對於軟體系統來說,就是我所謂的“設計單元”,基於粒度的不同可以是函式、物件、模組、元件和服務。這些設計單元相對簡單,然而彼此之間的相互作用卻導致了軟體系統的複雜行為。

Jurgen Appelo 從理解力與預測能力兩個維度分析了複雜系統理論,這兩個維度又各自分為不同的複雜層次,其中,理解力維度分為 Simple 與 Comlicated 兩個層次,預測能力維度則分為 Ordered、Complex 與 Chaotic 三個層次,如下圖所示:

enter image description here

參考複雜的含義,Complicated 與 Simple(簡單)相對,意指非常難以理解,而 Complex 則介於 Ordered(有序的)與 Chaotic(混沌的)之間,認為在某種程度上可以預測,但會有很多出乎意料的事情發生。顯然,對於大多數軟體系統而言,系統的功能都是難以理解的;在對未來需求變化的把控上,雖然我們可以遵循一些設計原則來應對可能的變化,但未來的不可預測性使得軟體系統的演進仍然存在不可預測的風險。因此,軟體系統的所謂“複雜”其實覆蓋了 Complicated 與 Complex 兩個方面。要理解軟體複雜度的成因,就應該結合理解力預測能力這兩個因素來幫助我們思考。

理解力

在軟體系統中,是什麼阻礙了開發人員對它的理解?想象團隊招入一位新人,就像一位遊客來到了一座陌生的城市,他是否會迷失在阡陌交錯的城市交通體系中,不辨方向?倘若這座城市實則是鄉野郊外的一座村落,不過只有房屋數間,一條街道連通城市的兩頭,還會疑生出迷失之感嗎?

因而,影響理解力的第一要素是規模

規模

軟體的需求決定了系統的規模。當需求呈現線性增長的趨勢時,為了實現這些功能,軟體規模也會以近似的速度增長。由於需求不可能做到完全獨立,導致出現相互影響相互依賴的關係,修改一處就會牽一髮而動全身。就好似城市的一條道路因為施工需要臨時關閉,此路不通,通行的車輛只能改道繞行,這又導致了其他原本已經飽和的道路,因為湧入更多車輛,超出道路的負載從而變得更加擁堵,這種擁堵現象又會順勢向這些道路的其他分叉道路蔓延,形成一種輻射效應的擁堵現象。

軟體開發的擁堵現象或許更嚴重:

  • 函式存在副作用,呼叫時可能對函式的結果作了隱含的假設;
  • 類的職責繁多,不敢輕易修改,因為不知這種變化會影響到哪些模組;
  • 熱點程式碼被頻繁變更,職責被包裹了一層又一層,沒有清晰的邊界;
  • 在系統某個角落,隱藏著伺機而動的 bug,當誘發條件具備時,則會讓整條呼叫鏈癱瘓;
  • 不同的業務場景包含了不同的例外場景,每種例外場景的處理方式都各不相同;
  • 同步處理與非同步處理程式碼糾纏在一起,不可預知程式執行的順序。

當需求增多時,軟體系統的規模也會增大,且這種增長趨勢並非線性增長,會更加陡峭。倘若需求還產生了事先未曾預料到的變化,我們又沒有足夠的風險應對措施,在時間緊迫的情況下,難免會對設計做出妥協,頭疼醫頭、腳疼醫腳,在系統的各個地方打上補丁,從而欠下技術債(Technical Debt)。當技術債務越欠越多,累計到某個臨界點時,就會由量變引起質變,整個軟體系統的複雜度達到巔峰,步入衰亡的老年期,成為“可怕”的遺留系統。正如飼養場的“奶牛規則”:奶牛逐漸衰老,最終無奶可擠;然而與此同時,飼養成本卻在上升。

結構

不知大家是否去過迷宮?相似而回旋繁複的結構使得本來封閉狹小的空間被魔法般地擴充套件為一個無限的空間,變得無窮大,彷彿這空間被安置了一個迴圈,倘若沒有找到正確的退出條件,迴圈就會無休無止,永遠無法退出。許多規模較小卻格外複雜的軟體系統,就好似這樣的一座迷宮。

此時,結構成了決定系統複雜度的關鍵因素。

結構之所以變得複雜,在多數情況下還是因為系統的質量屬性決定的。例如,我們需要滿足高效能、高併發的需求,就需要考慮在系統中引入快取、並行處理、CDN、非同步訊息以及支援分割槽的可伸縮結構。倘若我們需要支援對海量資料的高效分析,就得考慮這些海量資料該如何分佈儲存,並如何有效地利用各個節點的記憶體與 CPU 資源執行運算。

從系統結構的視角看,單體架構一定比微服務架構更簡單,更便於掌控,正如單細胞生物比人體的生理結構要簡單數百倍;那麼,為何還有這麼多軟體組織開始清算自己的軟體資產,花費大量人力物力對現有的單體架構進行重構,走向微服務化?究其主因,不還是系統的質量屬性在作祟嗎?

縱觀軟體設計的歷史,不是分久必合、合久必分,而是不斷拆分、繼續拆分、持續拆分的微型化過程。分解的軟體元素不可能單兵作戰,怎麼協同、怎麼通訊,就成為了系統分解後面臨的主要問題。如果沒有控制好,這些問題固有的複雜度甚至會在某些場景下超過因為分解給我們帶來的收益。

無論是優雅的設計,還是拙劣的設計,都可能因為某種設計權衡而導致系統結構變得複雜。唯一的區別在於前者是主動地控制結構的複雜度,而後者帶來的複雜度是偶發的,是錯誤的滋生,是一種技術債,它可能會隨著系統規模的增大而導致一種無序設計

在 Pete Goodliffe 講述的《兩個系統的故事:現代軟體神話》中詳細地羅列了無序設計系統的幾種警告訊號:

  • 程式碼沒有顯而易見的進入系統中的路徑;
  • 不存在一致性、不存在風格、也沒有統一的概念能夠將不同的部分組織在一起;
  • 系統中的控制流讓人覺得不舒服,無法預測;
  • 系統中有太多的“壞味道”,整個程式碼庫散發著腐爛的氣味兒,是在大熱天裡散發著刺激氣體的一個垃圾堆;
  • 資料很少放在使用它的地方,經常引入額外的巴羅克式快取層,目的是試圖讓資料停留在更方便的地方。

我們看一個無序設計的軟體系統,就好像隔著一層半透明的玻璃觀察事物一般,系統中的軟體元素都變得模糊不清,充斥著各種技術債。細節層面,程式碼汙濁不堪,違背了“高內聚、鬆耦合”的設計原則,導致許多程式碼要麼放錯了位置,要麼出現重複的程式碼塊;架構層面,缺乏清晰的邊界,各種通訊與呼叫依賴糾纏在一起,同一問題域的解決方案各式各樣,讓人眼花繚亂,彷彿進入了沒有規則的無序社會。

預測能力

當我們掌握了事物發展的客觀規律時,我們就具有了一定的對未來的預測能力。例如,我們洞察了萬有引力的本質,就可以對我們能夠觀察到的宇宙天體建立模型,較準確地推測出各個天體在未來一段時間的執行軌跡。然而,宇宙空間變化莫測,或許因為一個星球的死亡產生黑洞的吸噬能力,就可能導致那一片星域產生劇烈的動盪,這種動盪會傳遞到更遠的星空,從而干擾了我們的預測。坦白說,我們現在連自己居住的地球天氣都不能做一個準確的預測呢。之所以如此,正是因為未知的變化的產生。

變化

未來總會出現不可預測的變化,這種不可預測性帶來的複雜度,使得我們產生畏懼,因為我們不知道何時會發生變化,變化的方向又會走向哪裡,這就導致心理滋生一種仿若失重一般的感覺。變化讓事物失去控制,受到事物牽扯的我們會感到惶恐不安。

在設計軟體系統時,變化讓我們患得患失,不知道如何把握系統設計的度。若拒絕對變化做出理智的預測,系統的設計會變得僵化,一旦變化發生,修改的成本會非常的大;若過於看重變化產生的影響,渴望涵蓋一切變化的可能,一旦預期的變化不曾發生,我們之前為變化付出的成本就再也補償不回來了。這就是所謂的“過度設計”。

從需求的角度講,變化可能來自業務需求,也可能來自質量屬性。以對系統架構的影響而言,尤以後者為甚,因為它可能牽涉到整個基礎架構的變更。George Fairbanks在《恰如其分的軟體架構》一書中介紹了郵件託管服務公司 RackSpace 的日誌架構變遷,業務功能沒有任何變化,卻因為郵件數量的持續增長,為滿足效能需求,架構經歷了三個完全不同系統的變遷:從最初的本地日誌檔案,到中央資料庫,再到基於 HDFS 的分散式儲存,整個系統幾乎發生了顛覆性的變化。這並非 RackSpace 的設計師欠缺設計能力,而是在公司草創之初,他們沒有能夠高瞻遠矚地預見到客戶數量的增長,導致日誌資料增多,以至於超出了已有系統支援的能力範圍。俗話說:“事後諸葛亮”,當我們在對一個軟體系統的架構設計進行復盤時,總會發現許多設計決策是如此的愚昧。殊不知這並非愚昧,而是在設計當初,我們手中掌握的籌碼不足以讓自己贏下這場面對未來的戰爭罷了。

這就是變化之殤!

如果將軟體系統中我們自己開發的部分都劃歸為需求的範疇,那麼還有一種變化,則是因為我們依賴的第三方庫、框架或平臺、甚至語言版本的變化帶來的連鎖反應。例如,作為 Java 開發人員,一定更垂涎於 Lambda 表示式的簡潔與抽象,又或者 Jigsaw 提供的模組定義能力,然而現實是我們看到多數的企業軟體系統依舊在 Java 6 或者 Java 7 中裹足不前。

這還算是幸運的例子,因為我們儘可以滿足這種故步自封,由於情況並沒有到必須變化的境地。當我們依賴的第三方有讓我們不得不改變的理由時,難道我們還能拒絕變化嗎?

許多軟體在版本變遷過程中都儘量考慮到 API 變化對呼叫者帶來的影響,因而儘可能保持版本向後相容。我親自參與過系統從 Spring 2.0 到 4.0 的升級,Spark 從 1.3.1 到 1.5 再到 1.6 的升級,感謝這些框架或平臺設計人員對相容性的體貼照顧,使得我們的升級成本能夠被降到最低;但是在升級之後,倘若沒有對系統做全方位的迴歸測試,我們的內心始終是惴惴不安的。

對第三方的依賴看似簡單,殊不知我們所依賴的庫、平臺或者框架又可能依賴了若干對於它們而言又份屬第三方的更多庫、平臺和框架。每回初次構建軟體系統時,我都為漫長等待的依賴下載過程而感覺煩躁不安。多種版本共存時可能帶來的所謂依賴地獄,只要親身經歷過,就沒有不感到不寒而慄的。倘若你運氣欠佳,可能還會有各種古怪問題接踵而來,讓你應接不暇、疲於奔命。

如果變化是不可預測的,那麼軟體系統也會變得不可預測。一方面我們要儘可能地控制變化,至少要將變化產生的影響限制在較小的空間範圍內;另一方面又要保證系統不會因為滿足可擴充套件性而變得更加複雜,最後背上過度設計的壞名聲。軟體設計者們就像走在高空鋼纜的技巧挑戰者,驚險地調整重心以維持行動的平衡。故而,變化之難,在於如何平衡。

點選瞭解《領域驅動戰略設計實踐》

第03課:控制軟體複雜度的原則

雖然說認識到軟體系統的複雜本性,並不足以讓我們應對其複雜,並尋找到簡化系統的解決之道;然而,如果我們連導致軟體複雜度的本源都茫然不知,又怎麼談得上控制複雜呢?既然我們認為導致軟體系統變得複雜的成因是規模結構變化三要素,則控制複雜度的原則就需要對它們進行各個擊破。

點選瞭解《領域驅動戰略設計實踐》

分而治之、控制規模

針對規模帶來的複雜度,我們應注意剋制做大、做全的貪婪野心,盡力保證系統的小規模。簡單說來,就是分而治之的思想,遵循小即是美的設計美學。

丹尼斯·裡奇(Dennis MacAlistair Ritchie)從大型專案 Multics 的失敗中總結出 KISS(Keep it Simple Stupid)原則,基於此原則,他將 Unix 設計為由許多小程式組成的整體系統,每個小程式只能完成一個功能,任何複雜的操作都必須分解成一些基本步驟,由這些小程式逐一完成,再組合起來得到最終結果。從表面上看,執行一連串小程式很低效,但是事實證明,由於小程式之間可以像積木一樣自由組合,所以非常靈活,能夠輕易完成大量意想不到的任務。而且,計算機硬體的升級速度非常快,所以效能也不是一個問題;另一方面,當把大程式分解成單一目的的小程式,開發會變得很容易。

Unix 的這種設計哲學被 Doug McIlroy、Elliot Pinson 和 Berk Tague 總結為以下兩條:

  • Make each program do one thing well. To do a new job, build a fresh rather than complicate old programs by adding new “features.”
  • Expect the output of every program to become the input to another, as yet unknown, program.

這兩條原則是相輔相成的。第一條原則要求一個程式只做一件事情,符合“單一職責原則”,在應對新需求時,不會直接去修改一個複雜的舊系統,而是通過新增新特性,然後對這些特性進行組合。要滿足小程式之間的自由組合,就需要滿足第二條原則,即每個程式的輸入和輸出都是統一的,因而形成一個統一介面(Uniform Interface),以支援程式之間的自由組合(Composability)。利用統一介面,既能夠解耦每個程式,又能夠組合這些程式,還提高了這些小程式的重用性,這種“統一介面”,其實就是架構一致性的體現。

保持結構的清晰與一致

所有設計質量高的軟體系統都有相同的特徵,就是擁有清晰直觀且易於理解的結構。

Robert Martin 分析了這麼多年諸多設計大師提出的各種系統架構風格與模式,包括 Alistair Cockburn 提出的六邊形架構(Hexagonal Architecture),Jeffrey Palermo 提出的洋蔥架構(Onion Architecture),James Coplien 與 Trygve Reenskaug 提出的 DCI 架構,Ivar Jacobson 提出的 BCE 設計方法。結果,他認為這些方法的共同特徵都遵循了“關注點分離”架構原則,由此提出了整潔架構的思想。

整潔架構提出了一個可測試的模型,無需依賴於任何基礎設施就可以對它進行測試,只需通過邊界物件傳送和接收對應的資料結構即可。它們都遵循穩定依賴原則,不對變化或易於變化的事物形成依賴。整潔架構模型讓外部易變的部分依賴於更加穩定的領域模型,從而保證了核心的領域模型不會受到外部的影響。典型的整潔架構如下圖所示:

enter image description here

整潔架構的目的在於識別整個架構不同視角以及不同抽象層次的關注點,併為這些關注點劃分不同層次的邊界,從而使得整個架構變得更為清晰,以減少不必要的耦合。要做到這一點,則需要合理地進行職責分配,良好的封裝與抽象,並在約束的指導下為架構建立一致的風格,這是許多良好系統的設計特徵。

擁抱變化

變化對軟體系統帶來的影響可以說是無解,然而我們不能因此而消極頹廢,套用 Kent Beck 的話來說,我們必須“擁抱變化”。除了在開發過程中,我們應儘可能做到敏捷與快速迭代,以此來抵消變化帶來的影響;在架構設計層面,我們還可以分析哪些架構質量屬性與變化有關,這些質量屬性包括:

  • 可進化性(Evolvability)
  • 可擴充套件性(Extensibility)
  • 可定製性(Customizability)

要保證系統的可進化性,可以劃分設計單元的邊界,以確定每個設計單元應該履行的職責以及需要與其他設計單元協作的介面。這些設計單元具有不同的設計粒度,包括函式、物件、模組、元件及服務。由於每個設計單元都有自己的邊界,邊界內的實現細節不會影響到外部的其他設計單元,我們就可以非常容易地替換單元內部的實現細節,保證了它們的可進化性。

要滿足系統的可擴充套件性,首先要學會識別軟體系統中的變化點(熱點),常見的變化點包括業務規則、演算法策略、外部服務、硬體支援、命令請求、協議標準、資料格式、業務流程、系統配置、介面表現等。處理這些變化點的核心就是“封裝”,通過隱藏細節、引入間接等方式來隔離變化、降低耦合。一些常見的架構風格,如基於事件的整合、管道—過濾器等的引入,都可以在一定程度上提高系統可擴充套件性。

可定製性意味著可以提供特別的功能與服務。Fielding 在《架構風格與基於網路的軟體架構設計》提到:“支援可定製性的風格也可能會提高簡單性和可擴充套件性”。在 SaaS 風格的系統架構中,我們常常通過引入元資料(Metadata)來支援系統的可定製。外掛模式也是滿足可定製性的常見做法,它通過提供統一的外掛介面,使得使用者可以在系統之外按照指定介面編寫外掛來擴充套件定製化的功能。

點選瞭解《領域驅動戰略設計實踐》

第04課:領域驅動設計對軟體複雜度的應對(上)
第05課:領域驅動設計對軟體複雜度的應對(下)
第06課:軟體開發團隊的溝通與協作
第07課:【案例】版本升級系統的先啟階段
第08課:運用領域場景分析提煉領域知識(上)
第09課:運用領域場景分析提煉領域知識(下)
第10課:建立統一語言
第11課:理解限界上下文
第12課:限界上下文的控制力(上)
第13課:限界上下文的控制力(下)
第14課:識別限界上下文(上)
第15課:識別限界上下文(下)
第16課:理解上下文對映
第17課:上下文對映的團隊協作模式
第18課:上下文對映的通訊整合模式
第19課:辨別限界上下文的協作關係(上)
第20課:辨別限界上下文的協作關係(下)

相關推薦

no