在領域驅動下使用 Clean Achitecture 實現高可用軟體架構

圖(一)、Bounded Context

前言

先前筆者撰寫許多關於軟體架構相關文章,有敏捷的軟體架構、也談過 Clean Architecture、包括我自行設計的跨平台的 Web API Framework 框架 Easy Architect Framework 等等,不管談論哪一種都圍繞在軟體本身的高可維護性、擴充性等議題,但常言道,能力(技術)要在更往上一步就得忘掉現在所有所學的東西,不要被現有學習的東西所牽絆才能更上一層樓,金庸裡的張無忌也是忘掉九陽神功與乾坤大挪移後也才瞬間學會的張三丰的太極拳法,因為長久以來你都使用瀑布開發方法,專案也都能成功結案,看似當然也無問題,因為剛好都在你熟悉的產業即便設計完才做開發也不致有你非預期情況會發生,因為你已經非常熟悉改產業、但當遇到其他產業時,專案實作過程中便會遇到需求認知錯誤、錯估範圍、部分打掉重練、時間浪費、人力不足、現有架構無法發揮功用、時間到最後便不足而最後導致專案失敗的窘境,這就是熟悉一種開發方法時,久了就會無視其他的開發方法,就像 OOAD 非常熟悉,解決各種軟體開發大小問題都會迎刃而解,系統開發 90% 都可以在經驗種解決,最後也會無視訪間流行的它種開發方法像是 DDD 等等,但是當你遇到 cloud 環境、Microservices、或者 Serverless 環境的時候,你不再是以單就以物件的角度來思考、在分散式環境裡,有些是違背物件導向思考方式的,你可能是使用流程角度來思考,領域驅動開發的概念也應蘊而生。

DDD, Domain Driven Devlopment 領域驅動開發

近幾年來、DDD 領域驅動概念不斷的蓬勃發展起來,這是因為 Cloud/Microservices 議題不斷的是重視,傳統的 SOA 已經慢慢不敷使用了,如果要應付更大量的服務需求吞吐量、不太可能像傳統架設單一伺服器來解決,在領域驅動裡使用 Bounded Context 的概念來分界模型 Domain Modeling 的應用範圍,讓團隊成員在進行合作時什麼該保持一致?Bounded Context 與其他的 Bounded Context 該如何構通?以及『上下文如何關聯』有一個明確且共通的術語 Ubiquitous Language,這共通的語言可以是某一段程式碼、或者是團隊的組織、軟體系統機的介接用法、或者是該 Context 的 Domain Modeling 都可以是 Ubiquitous Language。在每一個 Bounded Context 之間都要嚴格地保持模型的一致性,不要受到外界的問題的干擾與混淆。

使用領域驅動開發有幾個好處:

  • 使用通用語言讓領域專家與技術人員緊密連結在一起。
  • 減少溝通的障礙。
  • 幫助你在系統建置時以『領域』為主體的思考方式。
  • 它非常適合用在敏捷的環境下、迭代的環境下搭配 TDD/BDD 等開發方法。
  • 每一個 Bounded Context 都是一個鬆散的耦合關係的存在,每一個 Bounded Context 的上下文都明確定義其溝通的方式,所以彼此的技術也完全獨立。
  • 呈上、所以領域驅動開發非常適合用在 Microservices 環境中使用。

與傳統 OOAD 思維的異同

有人好奇、甚至並不清楚領域驅動與傳統 OOAD 開發到底有什麼顯著的差異?又或者使用領域驅動開發就不需要 OOAD 了嗎?但事實上領域驅動開發也是基於 OOAD 再做一個擴展,但是你不能完全用 OOAD 的角度來思考,因為領域驅動開發有一部分是違背 OO 的,舉個例子:傳統系統開發我們是系統分析完、接著進行系統設計,但我們會在系統分析階段定義好資料結構、可能是 ER-Model 或者是資料擺放的架構,直到系統設計、甚至系統運行時的功能都是以『資料』導向的在進行處裡,想的都是資料最後會存到哪裡去,但是領域驅動想的是物件流怎麼流?考量的是領域內的流程與事件如何處哩,並不考量資料存到哪裡去,而傳統系統設計的思維則是圍繞在如何處理資料、像是典型 CRUD 等操作都使用 Database/Table/column 結構的資料來識別處裡資料。

但是領域驅動則不然,因為它將軟體架構又拆解為下面幾種:

  • Bounded Context
  • Context Maps
  • Entities
  • Value Object
  • Aggregates
  • Services
  • Domain Events
  • Architecture

其中領域模型的精隨就是你的 Domain Modeling,一個 Bounded Context 也許會對應一到多個 Domain Modeling,在領域驅動裡面商業邏輯在建模 Entities 的時候產生,這裡的 Entities 可以是 Domain Modeling,您可以使用 UML 還繪製或其他工具皆可沒有限定,容易理解即可,重點是 Entites 與我們在 MVC 裡探討的 Model 是不太一樣的,這裡的 Entities 是有自己的生命週期,也就是狀態會隨的業務的進行、與其內部屬性變更而有所改變,而且必須在分散式環境中可以被識別 (Runtime) ,這也是領域的核心點,它關心的是整個『作業流程』,也就是整個 Process 怎麼跑,它是一個 Process Base Thinking 的思考模式,而不是去想說資料最終會被塞到哪一個 Database 裡,那不是它關心的重點。

簡單的說,其實在做物件導向的系統分析 Domain Modelgin Design 時,思維可能需要改變,你要改成從流程角度來看待系統的設計、不是像傳統物件導向是以資料流為 Base 的處裡,在領域驅動裡是以物件流 (Object Base) 的角度來看待系統,而且裡面的每一個物件我都要可以去 Identity 他,也就是識別唯一性。所以在領域驅動角度下的物件 Class 關注的是它的責任是什麼?也就是它要能夠提供外界什麼服務?而當然,它還是標準物件導向底下的一個類別,有許多屬性的集合。

有一個與傳統物件導向相違背的地方就是 Services 的部分,在領域驅動裡物件裡的 Method/Operation 是透過 Services 來提供對外界需要的操作,不是傳統物件導向你密不可分的,他因為責任而切割在不同的地方。

領域透過一個 Aggregate Root 封裝了業務邏輯與狀態,因此裡面包含所有與聚合相關的業務操作 (Bounded Contet),並確保業務邏輯的一致性 (上下文)。

無處不在的通用語言 Ubiquitous Language

當我們進行專案開發,不管是不是敏捷的專案開發,最重要的就是『溝通』,在一般情況下,一個大專案就是數十個 Bounded Context 同時得再進行、不同的 Bounded Context 之間可能有(不同的領域專家/甚至不同的團隊)可能又涉及到專案經理、系統分析師、系統設計師、開發人員、QA人員 等等..在進行著,每個 Bounded Context 內也許又有一到多個 Domain Modeling 因此每一個領域專家要理解其他領域並相互溝通是一件相當困難的事情,更不用說不同角色又有自己的術語,也因此造成溝通式的困難。

在領域驅動裡面希望透過 Bounded Context 與其內部的 Domain Modeling 幫助團隊定義出一種可乎相交流的『模型』語言,這就是通用語言 Ubiquitous Language,另外一個重要的觀念是,通用語言並不局限於只能使用像是 UML 類型的模型來表示,您可使用各種圖形表示法 BPMN (Bbusiness Process)、DFD、Flow Cahrt、Others... 或者甚至是手繪,對你沒看錯,手繪的也可以、為什麼呢?因為重點在於『交流』、『溝通』,在每個 Bounded Context 下的團隊下與其他團隊 & 角色間溝通 + 認知沒有障礙、誤差越小越好,記得我在『決戰 OOAD 系列』課程裡也提到,不要為了畫製 UML 而繪製 UML,如果您有一些現有圖形在您現有團隊裡面溝通非常不錯用、非常容易溝通的,沒有障礙的,那你就繼續用,新的圖形不見得會增加團隊的共識,但是通用語言希望團隊理出一種可以互相交流理解的一種『模型語言』。

圖(二)、使用 BPMN 作為建模的依據

基於敏捷

領域驅動開發非常適合在敏捷的環境中進行,再迭代的環境中、在Sprint Planning Meeting 中釐清需求,討論 Domain Modeling 甚至是技術細節如何實作,也同時理出一個概括的通用語言,雖然在這個階段還不是那麼明確,因此專案進行中最重要的還是 Refinement Meeting,因為除了些修正方向外,也會同步修正通用語言。

近代的軟體專案開發敏捷幾乎是最佳解法了,在迭代的環境中 (短周期)、討論並正視目前遭遇到困難,並且需要開發人員與領域專家一起通力合作,利用協作的方式,先聚焦我們所要解決的問題,只要釐清了想要解決的問題後,再透過所有人腦力激盪的方式在會議中初步產生潛在可行的解決方案後,才被切分為 Tasks,並預估完成的時間。

高可用架構(插件式架構)Clean Architecture

Clean Architecture 是最適合在迭代環境中,以領域為核心、由外而內,透過聚合根(Aggregate Root)來封裝業務邏輯與狀態,確保業務邏輯一致性,這邊我們利用 .NET Core 內建的 DI 來做由外而內的相依與反轉。

這邊我實作了一個 Clean Architecture 的 C# Project Tempaltes 範本來幫助產生一個支援 CQRS 的 Application 層與 Domain 層。

圖(三)、使用自行開發的 Project Templates 範本建立 Clean Architecture (CQRS) 框架

待續...

下一篇、我們真的試著來實作一個高可用的軟體架構,也再來看看這個 [Clean Architecture (CQRS)] 的 Project Templates 可以幫我們做什麼?

我們下次見~

留言

這個網誌中的熱門文章

軟體架構設計:API 設計準則(二)、API Design-First 原則、策略與開發流程

常見的程式碼壞味道(Code Smell or Bad Smell)

什麼是 gRPC ?