故事背景
2023年中,我們的Java後端團隊為了落地DDD,全面引入了dotnet技術棧,具體過程和成果,可以看我的B站頻道《Java8 到 .NET8,團隊升級報告 - 第二彈》,關注公眾號(老肖想當外語大佬)獲取信息:
- 最新文章更新;
- DDD框架源碼(.NET、Java雙平台);
- 加羣暢聊,建模分析、技術實現交流;
- 視頻和直播在B站。
https://www.bilibili.com/video/BV14YgYedE1f
在近半年的時間,我將自己落地DDD的實踐經驗進行提煉和總結,以公眾號文章和B站視頻的方式分享出來,與更多的網友建立鏈接和交流,得到了很多肯定反饋,也因為大家提供的視角,使得我自己對DDD的認知有了更深層次的迭代。
目前我們藉助dotnet強大的生態以及csharp優良的語言設計,已經可以非常絲滑地用代碼表達模型和業務,整個軟件交付的體驗和效率,獲得了前所未有的進步。我們netcorepal-cloud-framework框架在這個過程中也得到了進化和可用性驗證,我們堅信找到了一套更加務實的軟件設計認知和方法論。
Javaer太難了
由於我們團隊實際上還是Java和csharp雙技術棧,於是我們萌生了一個想法,是否可以讓我們的Java項目交付過程也如此地絲滑?帶着這個想法,我們開始在Java生態中尋找可以幫助我們構建出類似csharp框架效果的組件:
- Web框架:aspnetcore vs springboot
- ORM:EntityFrameworkCore vs JPA
- 中介者模式:MediatR vs ?
- 事件的最終一致性實現:CAP vs ?
其中“中介者模式”和“事件的最終一致性”實現我們沒有找到合適的替代品,經過分析,“中介者模式”並不是必須的,雖然最終實現起來,沒有csharp那麼優雅,但並不影響對建模設計的實現,但“事件的最終一致性”這個組件,我們認為是必不可少的,我們建模最底層的模型就是“命令-事件”模型,沒有事件處理的健壯性,意味着最終系統的健壯性無法保障,最終無法滿足業務對可用性的要求。
事件的最終一致性
在我們的建模模型中,是在命令處理邏輯中,由領域模型發出事件,而事件如果要在微服務間傳遞,我們期望達到的效果如下:
- 如果命令處理邏輯成功,即對應的數據庫事務提交成功,則確保事件一定能夠發出;
- 如果命令處理邏輯失敗,即對應的數據庫事務回滾,則確保事件一定不發出;
在需求層面,我們並不要求系統確保事件“確定只發一次”,我們知道,這個要求的技術實現難度遠遠大於前面的兩個要求,而且業務可以做冪等處理解決重發的問題。
下圖展示了我們csharp版本中關於“命令-事件”的建模實現,以及事務的具體實現:
在我們csharp的版本,我們使用了比較流行的CAP組件,https://github.com/dotnetcore/CAP,這個組件本質上是實現了outbox模式,通常也叫“發件箱模式”,藉助這個組件,我們很輕易就實現了對於事件的最終一致性。
下圖來自CAP組件的介紹頁面,展示了發件箱模式的具體工作原理:
從原理上看,發件箱模式並不是一個複雜的能力,我們認為一向以生態好為優點的Java生態,也一定有類似且流行的組件,很不幸的是,我們在互聯網以及能夠觸達的Java圈子裏調研一番之後,得出瞭如下結論:
- Java生態有關於分佈式事務的實現,例如:JEE,JBoss等,但目前基本沒有團隊在用了;
- Java生態沒有現成的類似CAP這樣的組件可以開箱即用;
上述結論僅表示我們目前的認知和信息渠道,如果有大佬能夠給指個路,不甚感激!
cap4j
基於前面的結論,為了實現Java項目的DDD代碼體驗實踐,我們開源了一個cap4j項目,期望能將CAP項目的能力移植到Java生態,項目地址:https://github.com/netcorepal/cap4j
該項目目前實現了JPA+RocketMQ的組合,我們規劃在未來支持更多的ORM和MQ中間件,同時也會支持與CAP組件的協議兼容,以實現Java、dotnet異構架構的進一步融合。也歡迎大家為項目貢獻代碼和想法。
最後
關於技術生態這件事,可以説Java的生態好,但其它語言的生態我認為也都不差,在各自的領域都有非常多的優點。我在各個評論區,總是能看到各種不切實際的偏激言論,感受到種種的惡意。期望各個語言的技術棧從業者,能夠更友好地交流,大家都是軟件工程師,滿足業務需求,實現商業價值,才是大家的更應該關注的。