1. 程式人生 > >領域驅動設計,讓程式設計師心中有碼(四)

領域驅動設計,讓程式設計師心中有碼(四)

#領域驅動設計,讓程式設計師心中有碼(四)

----------------------追憶有關分層的古老往事

         我一直認為,程式設計師也是藝術家,他們撰寫的每一行程式碼,是獻給這大好世界的優美詩篇。不同的人,寫的程式碼也許風格迥異。有的,如春風化雨潤物無聲,有的,如高山流水,曲高和寡,還有的如旱日春雷,先聲奪人。而如果說,程式碼是詩篇,那麼程式碼的分層藝術絕對是最先映入讀者眼簾的序幕了。

         分層,一直以來是一個非常經典的軟體工程學問題,提到分層,無論是資深或者新入門的開發者,或多或少都有自己的理解。    

         在8年前,我剛參加工作時,有幸參與了比較多專案的研發和維護過程,這些專案的開發者,大多是比我年長几歲的軟體開發者。在他們的開發習慣中,往往會傾向於直接在程式碼中寫入使用者介面、資料庫訪問等支援程式碼,甚至有相當一部分情況下,會把程式碼寫入到使用者介面中,這意味著在使用者介面層,往往會寫入大量的程式碼,說不定會超過上萬行程式碼。我覺得可以將這種設計,理解為“單層架構“。

        再後來的專案開始有了一點點改變,這個時候的架構,被成為“三層架構“。在.NET開發史上,三層架構成為一種歷史悠久的框架,從十年前開始,一直到今天,依然是.NET開發者最為熟練的技術框架。如圖所示,三層架構在客戶端和資料庫之間增加了一箇中間層,將有效的業務規則、資料訪問等放在業務層中進行處理。介面層主要使用對資料的繫結渲染,再通過資料層實現資料的提交處理。有的開發者說,三層架構通吃一切專案,似乎所有的專案都可以用三層架構來套用。然而在實際工作中,往往會忽略了業務邏輯層,業務邏輯往往會放在介面層或資料層中,最終導致介面層和資料層充斥著臃腫的程式碼,令人難以維護。

 

    

       MVC架構也是一種非常主流的技術架構,這種架構是一種非常優秀的架構,他將使用者介面層通過模型層最早來源於上世紀七十年代,為Smalltalk語言所設計的一種模式,許多基於使用者介面的架構也受到了他的啟發。MVC架構,通過將邏輯、資料、介面顯示分離的形式,實現程式碼的組織,廣泛適用於桌面端或網頁程式的開發過程。這種架構的特點是耦合性低、重用度高、生產週期短、部署快。但是同樣由於缺乏明確的定義,以及程式碼過於集中,導致程式碼腐化問題非常嚴重。

 

    

      MVP架構是從MVC架構中演進出來的典型代表,這種架構通過Presenter來處理邏輯,Model提供資料,View負責顯示。當然,他和MVC的區別在於,資料的顯示往往是通過Presenter來進行的,所有的介面操作也都是在Presenter中實現,這意味著View層,只是單薄的一層。

 

         

    與此同時,開發者們也善於使用儲存過程或檢視等不同的方式寫入複雜的業務邏輯,期待的往往是如果是程式碼發生變更時,只需對資料庫進行修改即可,而無需去修改已經部署在使用者端的大量的程式碼。  使用儲存過程、觸發器或檢視等方式,時至今日,依然是備受關注的一種實現技術,尤其是面向傳統產業開發的專案,例如面向製造業的工業控制系統,要進行程式的部署仍然需要非常繁瑣的流程,這意味著使用者層的部署相對來說不方便,而資料庫的變動反而更方便。          

  不同型別的架構或設計的理念迄今仍深刻的影響著開發者的思維模式和工作方法,並最終或多或少的影響著軟體工程的實現。          

  從高內聚,低耦合的軟體工程學基本原則來說,模組與模組之間的關係,稱為耦合,而模組內部的關係稱為內聚。而分層的目的,正是為了在滿足這個基本原則的前提下,提高程式碼的可用性和穩定性。過少的分層,意味著程式碼可讀性必然很糟糕,甚至不利於軟體的編譯分發,而過多的分層,則同樣意味著模組的維護將對整體過程程式碼不便。          

      領域驅動設計認為,如果程式碼中,與領域相關的內容分散在不同的部分,那麼要進行業務和程式碼的分析將變得難以下手。對使用者介面的簡單調整都可能意味著程式碼邏輯的變化,而想要調整業務規則,可能需要開發者們去排查與之相關的所有部分,例如介面層,資料層,甚至是儲存過程和檢視,這種過程實際上已經沒辦法建立可用的業務模型,甚至沒辦法建立測試用例和單元測試的開展,只能靠開發者憑經驗去處理不同的情況。為了保證程式碼的可用性,應當儘可能的分析理清所使用的技術和手段,程式層次設計應當簡單明瞭,易於理解。          

  在複雜系統設計中,分層是一種非常不錯的理念,其目的是為了更好的實現關注度分離,使設計的每個部分,既能得到單獨的關注,也能維護系統內部複雜的互動關係。領域設計認為,上述提到的幾種設計模式,往往是下面四種概念的某種變體。

  •     使用者介面層(或者表示層),負責向用戶顯示資訊和解釋使用者指令。這裡的使用者,既可以是使用使用者介面的人,也可以是另外一個計算機系統。
  •     應用層:定義軟體要完成的任務,並且只會表達領域概念的物件來解決問題。這一層實際上負責的是系統與應用層進行互動的必要渠道。
  •     領域層(或模型層)負責表達業務概念、業務狀態資訊以及業務規則。儘管技術細節由基礎設施層實現,但業務情況狀態的反映則需要有領域層進行控制。領域層是業務軟體的核心。
  •     基礎設施層:為上面各層提供通用的技術能力:為應用層傳遞訊息,為領域層提供持久化機制,為使用者介面層繪製螢幕元件等等。基礎設施層還能夠通過架構框架來支援4個層次減的互動模式。

        在傳統專案中,往往不見得會如此鮮明的劃分層次,但是在進行模型驅動設計的關鍵,正是需要將領域層從複雜的業務程式碼中抽離出來。在設計過程中,應當採取以下操作:

    1、給複雜的應用層次劃分層次;

    2、對每個層次進行獨立的設計,使其具有內聚性並且只依賴於它的下層;

    3、採用標準的架構模式,只與上層進行鬆散的耦合。

    4、將所有與領域模型有關的程式碼放在一個層中,並讓它與使用者介面層、應用層和基礎設施層的程式碼分開。

    5、領域物件應當把重點放在如何表達領域模型上,而不需要考慮自己的顯示和儲存問題,也無需管理應用任務等內容。

    6、模型設計的目的是達到含義豐富、結構清晰、業務鮮明。

       適當的分層,往往會通過架構框架的形式予以體現。在專案開發過程中,我們通常會使用一些框架,這些框架往往來源於平時專案的積累或者網際網路大佬的知識分享。但是這些框架往往不見得完全符合我們的專案需求。領域驅動設計認為,好的架構框架既能解決複雜技術問題,也能讓領域開發者集中精力去表達模型,而無需考慮其他問題。然而使用框架很容易為專案製造障礙,最終同樣會給人造成錯誤的理解,即,我們這個專案很簡單,並不需要複雜的框架。然而,筆者認為,大部分情形所認為的不需框架的原因,往往是專案確實非常簡單,或者開發者低估了專案的複雜度,或者由於公司短視的觀點,而忽略了程式碼的架構設計和分層與建模工作,這最終導致專案容易陷入泥潭。

  當然,也同樣要剋制慾望,貿然選擇難以駕馭的框架,反而讓專案開發過程變得不可收拾。因此,要選擇性的運用框架來解決問題,明智和審慎的應用框架的價值,讓開發者專注於核心業務問題的建模工作,才是提高開發效率和程式質量的手段。