天天看點

怎麼說服上司,能讓我用DDD架構肝項目

怎麼說服上司,能讓我用DDD架構肝項目

作者:小傅哥​

沉澱、分享、成長,讓自己和他人都能有所收獲!????

一、前言

​上司:為什麼要使用DDD?​

我也苦思冥想,怎麼跟上司說咱們從 MVC 更新到 DDD 吧,因為 DDD 代碼結構更加清晰、領域驅動比測試驅動開發更加先進、研發的兄弟們也更想用用新架構等。

不過這麼聊被噴一頓不說,還得說你是過度設計瞎折騰,咋回事呢?因為沒聊到重點呀,你MVC更新DDD;​

​給業務帶來了什麼​

​​、​

​提升了傳遞效率嗎​

​​、​

​降低了公司研發成本嗎​

​,都沒有?不僅沒有,你還說為了後期的疊代維護,前期會需要更多的設計和開發時間。咋?你是想這一個Q就把我送走嗎,我剛來咱們部門KPI在那懸着,壓的我頭發都白了!别瞎搞,求穩!

那就不搞了嗎?搞哇,不讓搞換上司!但搞之前,要考慮清楚,DDD 不是 Silver Bullet,你有一腔熱血雖好,可是也得知曉 DDD 的設計原則是什麼、它更适合的場景是什麼、與 MVC 對比有什麼雲泥之别。

二、開發成本

使用 DDD 模式開發代碼的成本到底在哪?是因為使用 ​

​DDD 四層分層結構​

​​就比​

​MVC 三層分層結構​

​ 更浪費時間嗎?其實并不是,因為四層結構相對于三層結構,反而更好的區分了代碼所屬職責,在熟悉子產品功能職責後,開發起來也會更加順暢。

那這裡的 DDD 領域驅動設計開發的成本在哪呢?這個成本在于對于一個複雜系統又尚未在開發前期就有非常充足的經驗來​

​拆分職責邊界​

​​、​

​劃分功能領域​

​​、​

​明确編排邏輯​

​​和​

​對未知流程擴充的把控上​

​,所帶來的風暴模型設計成本。

而通常使用的 MVC 結構基本不會出現這樣的問題,因為在實際的代碼中,DAO、PO、VO等都是共用的,大家在開發代碼的時候,像​

​堆泥球​

​​一樣​

​面向過程寫代碼​

​,直接串聯出産品的PRD功能節點即可,不用過多的思考解耦和内聚。

那不是可以設計模式嗎,這就需要看你是站在哪個次元去思考問題。設計模式在這裡是戰術問題的,DDD和MVC是确定戰略問題的,有點像是說:“方向不對,努力白費一樣”

那麼現在我們再來看這條開發成本曲線:

怎麼說服上司,能讓我用DDD架構肝項目
  • 與其他兩種分層結構相對比,使用 DDD 的時候,需要在前期投入較多的時間成本來設計領域模組化,是以前期成本會更高一些。
  • 但随着業務不斷疊代後的邏輯的複雜性增加,DDD 系統架構所開發的代碼穩定性會更好,也就說明 DDD 更容易擴容和維護。
  • 是以架構結構的更換,不是最終增加開發成本的地方,如果你不做領域模組化也不做更多的設計思考,那麼即使是 DDD 的四層架構,也能讓你寫出 MVC 的效果。而那些對業務場景經驗豐富的架構師或者研發人員,已經非常明确了各個業務功能的職責邊界,要實作一個系統需求需要完成哪些核心領域服務,再這樣的情況用 DDD 也不會帶來多少開發成本,反而更加遊刃有餘了!這就是為什麼說,需要領域專家,因為專家已經積累了很多的戰略設計經驗
  • 此外使用 DDD 領域驅動設計的模式進行開發,除了解決需求的疊代成本,更多的時候是要面對公司戰略調整後,系統的交接、人員的更替和新增,都要在原有的工程架構下繼續疊代開發,否則就要推翻重新做,那樣所面臨的更替成本将更大,同時又是開發了一個與人員綁定不易于交接維護的工程代碼。

三、架構對比

在了解和掌握 DDD 領域驅動設計的路上,你一定會碰到兩個抽象的釘子 —— “貧血模型”、“充血模型”:

  • 貧血模型:事務腳本模式,最早起源于 EJB2,到 Spring 進入開“春”盛世。
  • 充血模型:領域模型模式,2003年提出,一直到​

    ​《實作領域驅動設計》​

    ​的問世,才開啟了 DDD 的大門。但國内直到微服務、低代碼的興起,才開始 DDD 熱

1. MVC

MVC 分層結構将:“狀态”(資料,成員對象)、“行為“(邏輯、過程),分離到不同的對象中,隻有狀态的對象(VO -> Value Object) 被稱為貧血模型,隻有行為的對象,就是架構分層中常見的Logic/Service/Manager層(對應到EJB2中的Stateless Session Bean)

怎麼說服上司,能讓我用DDD架構肝項目
  • 以應用層 Service 使用 DAO、PO 基礎設施包裝業務邏輯的開發方式,乍一看以為應用層是在對領域模組化的實作,”領域層“有着豐富的對象連結,和真正的領域模型也非常類似,但當我們代碼随着業務功能邏輯的逐漸實作中會慢慢發現,我們寫了一堆的​

    ​get/set​

    ​ 對象,而他們被反複交叉使用,沒有與任何領域聚合,也就是不具有任何的行為動作,隻是一堆貧血模型對象。
  • 這種反模式的設計,其實完全與​

    ​面向對象​

    ​的設計是背道而馳的,面向對象的設計更希望行為和資料綁定在一起,與之對比的貧血模型更像是面向過程設計。
  • 在 MVC 分層結構下,所有的行為都被寫入到 Service 對象中,最終你會得到一組事務處理的過程腳本,進而完美的避開了領域模型設計所帶來的好處(清晰的職責邊界、聚合的功能服務、清晰的面向對象)。

2. DDD

DDD 的分層結構也是面向對象程式設計的本質:”一個對象擁有行為和資料“,在領域層包括了:對象、聚合對象、倉儲和Service實作。

怎麼說服上司,能讓我用DDD架構肝項目
  • DDD 的分層結構更注重 Domain 領域層的實作,由很薄的應用層定義接口和編排接口,由領域層做具體的實作。
  • 所有的業務邏輯都按照各自的職責邊界拆分成一塊塊的功能領域,每一個功能領域都是充血模型的結構的具體實作。
  • 那麼這樣的代碼最終實作以後,無論在疊代、維護、人員更替,都能很好按照領域設計文檔找到對應的代碼實作進行開發。

四、設計原則

首先 DDD 的設計分為戰略和戰術;

  • 戰略設計:從業務視角出發,建立業務領域模型、劃分職責邊界,建立通用語言的界限上下文。頂層戰略設計建構的領域模型結構,是整個服務後期編排的重點,它确定了功能的職責邊界、聚合、對象等,也就絕對了後期服務戰術實作的開發和傳遞品質。重視戰略,才能落地好戰術!
  • 戰術設計:從技術視角出發,側重于領域模型的技術實作,完成功能開發和傳遞落地。領域設計的重點包括:實體、聚合對象、值對象、領域服務、倉儲,還有一個非常重點的​

    ​設計模式​

    ​。任何一個較為複雜的領域模型實作都需要考慮設計模式的使用,否則即使戰略優秀,戰術也能幹回 MVC 去。

在以DDD領域驅動設計落地的過程中,要依靠領域驅動設計的設計思想,通過事件風暴建立領域模型,合理劃分領域邏輯和實體邊界,建立領域對象及服務矩陣和服務架構圖,定義符合DDD分層架構思想的代碼結構模型,保證業務模型與代碼模型的一緻性。通過上述設計思想、方法和過程,指導團隊按照DDD設計思想完成微服務設計和開發。

  1. 拒絕泥球小單體、拒絕污染功能與服務、拒絕加功能排期一個月
  2. 架構出高可用極易符合網際網路高速疊代的應用服務
  3. 物料化、組裝化、可編排的服務,提高人效
  4. 要領域驅動設計,而不是資料驅動設計,也不是界面驅動設計
  5. 要職能清晰的分層,而不是什麼都放的大籮筐

DDD 的領域模型設計,界限内的上下文,可以拆分為獨立的微服務。但不僅要從業務視角看問題,也要考慮非業務的技術因素,包括:高性能、安全、團隊、技術異構等,這些非業務的技術因素,也會決定領域模型落地的具體落地。

五、舉個例子

你說我 MVC 不好,你說我 MVC 貧血模型,PO 類不斷的膨脹,但讓我用 DDD 又都是理論,程式員更喜歡看的是已經落地的代碼,告訴我怎麼幹。

為什麼這麼難落地呢?因為從 MVC 過度到 DDD 描述對比​

​隻是積累了 MVC 失敗的教訓,但沒有 DDD 成功的經驗​

​,是以更多的時候想落地 DDD 除了有理論支撐,更需要一份案例擺在面前。

1. 工程結構

是以為了讓更多的碼農看到在 DDD 上一條能走的路,專門折騰了個 ​

​DDD 分布式抽獎系統​

​,來告訴大家怎麼使用 DDD 開發業務需求;

怎麼說服上司,能讓我用DDD架構肝項目

整體系統架構設計包含了6個工程:

  1. Lottery:分布式部署的抽獎服務系統,提供抽獎業務領域功能,以分布式部署的方式提供 RPC 服務。
  2. Lottery-API:網關API服務,提供;H5 頁面抽獎、公衆号開發回複消息抽獎。
  3. Lottery-Front:C端使用者系統,vue H5 lucky-canvas 大轉盤抽獎界面,講解 vue 工程建立、引入子產品、開發接口、跨域通路和功能實作
  4. Lottery-ERP:B端營運系統,滿足營運人員對于活動的查詢、配置、修改、稽核等操作。
  5. DB-Router:分庫分表路由元件,開發一個基于 HashMap 核心設計原理,使用哈希散列+擾動函數的方式,把資料散列到多個庫表中的元件,并驗證使用。
  6. Lottery-Test:測試驗證系統,用于測試驗證RPC服務、系統功能調用的測試系統。

2. 流程拆解

當我們拿到産品的 RPD 以後,并不是直接上手開發,而是需要從流程中拆解出一份面向對象設計的領域服務,舉例;

怎麼說服上司,能讓我用DDD架構肝項目
  • 拆解功能流程,提煉領域服務,一步步教會你把一個業務功能流程如何拆解為各個職責邊界下的領域子產品,在通過把開發好的領域服務在應用層進行串聯,提供整個服務鍊路。
  • 通過這樣的設計和落地思想,以及在把流程化的功能按照面向對象的思路使用設計模式進行設計,讓每一步代碼都變得清晰易懂,這樣實作出來的代碼也就更加易于維護和擴充了。
  • 是以,你在這個過程中學會的不隻是代碼開發,還有更多的落地思想實踐在這裡面展現出來。也能為你以後開發這樣的一個項目或者在面試過程中,一些實際複雜場景問題的設計思路,打下不錯的基礎。

3. 一起實踐

  • 具備 Java 程式設計基礎的研發人員,想提升自己的技術能力
  • 希望提升編碼思維,剔除到代碼中的壞味道
  • 有意願成為架構師,但還處在一定瓶頸期
  • 想加入大廠做碼農,但總感覺找不到門路

六、總結

  • DDD 并不是 Silver Bullet,你并不能指望換個了個架構結構,就能改變堆屎山⛰似的開發代碼,所帶來壞味道問題。MVC 結構一樣可以開發出好的代碼,隻是它的穩定性更差,不利于長期維護和疊代。
  • DDD 的複雜性是因為缺少領域模組化的經驗,如果同一個需求你已經在 MVC 的中嚯嚯的吸收了足夠的邊界上下文總結,現在換 DDD 可以讓你更快的開發代碼。
  • DDD 也并不是所有工程模型結構都複雜,DDD 是指導思想,你可以在 DDD 四層架構中因為引入 RPC 拆解各個子產品的分層,也可以因業務規模在中等及複雜度時不引入 RPC 架構,這樣的 DDD 會更加短小精幹,與 MVC 相比隻是在領域層定義接口,把代碼放到 domain 層做實作,資料放到倉儲層處理。參考代碼:​​https://github.com/fuzhengwei/CodeGuide​​

繼續閱讀