DDD 在京東 DevOps 項目協做領域的落地實戰

image.png

DDD 即領域驅動設計(Domain-Driven Design)。它來源於著名建模專家 Eric Evans 發表的很是具備影響力的書籍:《domain-driven design –tackling complexity in the heart of software》(中文:領域驅動設計—軟件核心複雜性應對之道)。其最先普遍應用於傳統軟件架構設計中。前端

今年4月,InfoQ 發佈了軟件架構與設計的趨勢報告。在報告中能夠看出,微服務、領域驅動設計等已成爲目前軟件開發行業的主流趨勢,筆者也瞭解到,DDD 已成爲大部分企業微服務落地、中臺建設的指導思想。web

image.png

(圖片來源:infoQ)spring

隔離變化和沉澱複用數據庫

在互聯網時代,業務系統構建初期,場景一般簡單清晰,基於數據庫表設計+CRUD 就能支撐業務的敏捷迭代。隨着時間的推移,場景和業務邏輯變得複雜、定製,模塊之間彼此耦合,系統變得愈來愈臃腫,每每牽一髮而動全身。即便加一個字段這樣看似簡單的邏輯,光梳理對其餘功能點和模塊的影響,就至少須要一個對業務和代碼都很熟悉的團隊老成員才能穩妥敲定。相信一個實現1年以上的業務系統,其架構和代碼就有可能正在經歷着以上這些,開始慢慢腐化。後端

一個最經典的例子——電商系統裏面諸如如下 product 類的設計(現實中字段數可能幾百個),它是不符合高內聚低耦合這個架構設計原則的:restful

  • product 類一應俱全,什麼領域的知識都知道;其職責不清晰,在沉澱複用上,團隊成員的指望都不一致,實現姿式可能千奇百怪;
  • 採購、倉儲、配送業務領域的邏輯變更可能都要修改 product ,一個高內聚的系統設計,是須要儘量隔離變化,使之產生的影響最小且控制在必定邊界內。

image.png

DDD 經過劃分限界上下文,拆分子領域,實現解耦和複用:網絡

image.png

如下圖片來自軟件開發教父:Martin Fowler。誠然,爲應付愈來愈複雜的業務邏輯,以自頂向下設計的領域聚合模型替代數據表模型,才能真正實現以業務實體爲核心的靈活拓展:架構

  • 面向過程的腳本,不能很好地被擴展;
  • 面向數據表的設計,過分關注數據忽略行爲,不能很好地被複用。

image.png

以上,讓經歷互聯網泡沫存活下來的系統弄潮兒逐漸重燃對 DDD 的熱情,但願藉助 DDD 能重拾建造更合理軟件架構的信心。但在落地上,荊棘環生,困境各異。下面咱們來介紹一下 DDD 在京東 DevOps 項目協做領域的落地實踐。app

將 DDD 應用到組件化
image.png框架

在京東內部,項目協做領域有兩個用戶羣體覆蓋特別廣(總用戶數 8W+)的系統:PMP 和行雲。
image.png

PMP是一個更面向項目經理的項目管理軟件,包含項目流程管理、需求管理、里程碑管理、任務管理、工時管理、成本管理、OKR 管理、ROI 驗證和滿意度評分等。在架構設計上,PMP 是一個很是龐大的單體應用,其先後端不分離,全部業務邏輯糅雜在一塊兒,項目表單字段數達到了 100+。通過時間和組織的變遷,在可擴展性和可維護性上,簡直是場災難。

行雲起初的定位是面向研發的敏捷協同軟件,包含跨部門需求管理、敏捷迭代和任務管理等。隨着行雲的普遍使用,將 PMP 功能融合到行雲的呼聲愈來愈高。

同時,行雲對公司外部提供 ToB 服務。內外部存在着大量差別化的場景和業務,單純靠以往的不斷添加 if else 揉泥球的方式,已經徹底行不通。新的定位和背景下,要求咱們必須將業務邏輯拆分爲一個個靈活的組件,作到複用與邏輯沉澱;另外一方面,差別化的邏輯能夠靈活擴展。這其中有着巨大的挑戰:

上圖中間圓弧描述的是咱們在對組件拆分時參考的原則(業務可獨立運營、高內聚低耦合、數據完整性、漸進性),以此爲基礎,在應對業務和技術視角上的挑戰時,咱們採起的相關 DDD 戰略和戰術。

業務的挑戰

PMP 和行雲中都有需求管理、任務管理。這其中需求、任務是否是一個概念?項目、需求、迭代、任務等之間是什麼關係?如何對內和對外沉澱一套清晰可複用的業務組件?

DDD 中概念比較多,包含限界上下文、聚合、聚合根、實體、值對象等,本文先不關注這些細節,直接聚焦如下問題:

一、 劃分邊界,識別領域對象或者領域類,保證其職責清晰純粹;

二、 明確領域類之間的關聯、依賴,界定調用關係和方式。

經過領域分析建模,造成統一語言,最終將項目協做管理這個總體,拆分爲一個個功能完整、業務邏輯明確的業務域,如項目域、任務域、工時域等等。每個業務域對外提供明確的領域服務,一個業務領域能夠管理多個業務實體。

image.png
x_lazy=1&wx_co=1)

技術的挑戰

在劃分完領域後,理想的狀況是各領域高度自治,減小依賴,甚至各領域能夠由不一樣的團隊來實現,各團隊聚焦沉澱該領域核心能力。

最終,咱們造成了一個組件化方案:根據劃分出來的領域,將系統拆分紅業務組件(核心子領域)和基礎組件(通用和支撐子領域),各組件先後端分離。即會有如下前端應用:需求管理、項目管理、缺陷管理、用例管理等;後端應用相應提供不一樣的領域服務,領域服務採用分層架構(interface, application, domain, infrastructure)。權限管理、網關服務、消息服務等基礎組件下沉,實現最大化組件複用。

image.png

按照領域拆分紅業務組件,對系統來講,最終提供給終端用戶還需是一個總體。但組件化意味着分離,那對於業務組件的先後端應用又面臨怎樣的協同挑戰呢?**

業務組件前端應用的挑戰

爲了實現各業務組件能並行、獨立演進,理想狀況下,前端子應用需知足獨立編譯、打包、部署,並最終集成到一個平臺上呈現統一的 UI 風格和一致的交互體驗。

以上業界將此歸結爲微前端架構:實現一種架構風格,能夠將衆多獨立交付的前端應用組合成一個大型總體,對客戶表現爲一件單一完整的產品。

最終,咱們行雲團隊落地了一個 Jmodule 微前端組件框架。

前端應用經過微前端架構和前端組件框架註冊到平臺,系統層實現組件元數據管理、運行時熱加載靜態資源和組件間通訊,對用戶側提供徹底可插拔可配置的組件。具體原理和實現等將在後續另外一篇章節中展開。

業務組件後端應用的挑戰

行雲在設計之初,後端服務採用的是微服務的架構(利用spring cloud gateway、Eureka 等實現服務註冊、網關調用等),這和 DDD 相得益彰。在覈心業務組件內,領域服務按照經典分層架構(interface, application, domain, infrastructure)來組織。

  • interface-用戶界面層:Controller、restful接口調用,或者web端UI界面、移動端UI界面、第三方服務等;
  • apllication-應用層:對外爲展示層提供各類應用功能,對內調用領域層(領域服務),應用層更像是實現某個特定場景的策略,或者流程上的編排等。其協同多個領域的服務,實現場景和業務的隔離
  • domain-領域層:負責表達業務概念,業務行爲,業務狀態以及業務規則,領域模型處於這一層,是業務軟件的核心。其提供的是一系列原子服務,在這一層提供豐富的OPEN API,是實現組件化相當重要的一步
  • infrastructure-基礎層實現業務和技術的隔離層。通常包含:網絡通信、數據庫持久化、異步消息服務、南向網關服務等。這一層在落地的時候,能夠實現多種適配器adaptor 來兼容對內、對外、多雲異構中間件環境。

除了界定組件內部分層的邊界,還須要明確組件間的調用和依賴關係,進一步明確組件的職責。在 DDD 中相應地定義了限界上下文之間的映射關係:

  • 合做關係:兩個上下文緊密合做的關係;
  • 客戶方-供應方:上下文之間有組織的上下游依賴;
  • 遵奉者:下游上下文只能盲目依賴上游上下文;
  • 分離方式:兩個徹底沒有任何聯繫的上下文;
  • 共享內核:兩個上下文依賴部分共享的模型;
  • 防腐層:一個上下文經過一些適配和轉換與另外一個上下文交互;
  • 開放主機服務:定義一種協議來讓其餘上下文來對本上下文進行訪問;
  • 事件發佈訂閱:一般用於定義開放主機的協議。

在組件的調用和依賴關係上,咱們能夠借鑑以上映射關係的理念來落地。

舉個例子,咱們已經沉澱了項目組件和任務組件。假設須要實現的業務場景:當刪除某個項目時,須要檢查項目中是否已有進行的任務,無則刪之,有則提示不能刪。根據 DDD 的映射關係,任務被項目依賴,任務處在上游的位置,理想狀況下它不須要知道項目業務領域刪除的具體邏輯規則,同時儘可能減小項目業務規則的變化所帶來的影響。

因而,咱們在落地的時候,淘汰了下圖左側的實現方式——合做關係(項目和任務網狀式相互調用,我中有你,你中有我),而是在下游項目領域加了一層適配層,來隔離業務的變化對上游的影響。同時,也確保任務這層邏輯乾淨、清晰,以供更多其餘組件複用。

總結

總結一下,本文大致給出了 DDD 思潮在如下方面落地上的指導意義:

  • 如何沉澱清晰可複用的業務組件?
  • 如何隔離組件間的變化對其餘組件的影響?

敬請期待

以後會在後續章節中分享 DDD 在插件落地的實踐,解決以下問題:

如何快速響應五花八門的定製化需求,同時保持自身不腐化?

相關文章
相關標籤/搜索