[Architecture] 3-Layer基礎架構

摘要:[Architecture] 3-Layer基礎架構

[Architecture] 3-Layer基礎架構

三層式架構

三層式架構

只要是軟體從業人員,不管是不是本科系出身的,相信對於三層式架構一定都不陌生。在三層式架構中,將軟體開發所產出的程式碼,依照不同用途歸類為:系統展示層、領域邏輯層、資料存取層。其中:

  • 系統展示層 (Presentation Layer),用來歸類「提供操作介面」的相關程式碼。例如:提供Textbox接受使用者輸入地址資料、透過MessageBox通知使用者處理結果、甚至是提供Web API給遠端系統使用,這些程式碼都會被歸類在展示層之中。

  • 領域邏輯層 (Domain Layer),用來歸類「封裝系統邏輯」的相關程式碼。例如:商城系統的商品資料、購物車、對帳單,或者是出勤系統的上下班記錄、員工資料…等等,這些程式碼都會被歸類在領域邏輯層 之中。

  • 資料存取層 (Access Layer),用來歸類「實作資料存取」的相關程式碼。例如:將資料存放到SQL Server、或者是從遠端WebService取得資料…等等,這些程式碼都會被歸賴在存取層之中。

透過三層式架構的設計,讓開發人員能夠粗略的將系統拆解為三個不同面向的分類。透過套用這樣的架構設計,在開發過程中,能夠減少需要思考的設計內容,讓開發人員一次只需要思考某個面向的設計內容。而在後續的維護過程中,也讓開發人員能夠分門別類的去理解既有的程式內容。

基礎架構設計

基礎架構設計

雖然說,只要是軟體從業人員,對於三層式架構都不陌生。但是三層式架構畢竟是在比較早期的年代所提出,隨著物件導向語言的發明、後續DI與IoC概念的加入、以及DDD、TDD等技術的出現。讓開發人員在撰寫一個套用三層式架構的軟體系統,需要考慮的方方面面變得越來越多,一層堆一層的知識體系,已經慢慢榨乾開發人員的腦細胞活力。不過還好的是,現代的軟體業界出現了「軟體架構師」這一個職缺。在專案開發的過程中,透過軟體架構師的努力,來消化知識體系的堆積,產出為符合專案需求、團隊能力的軟體架構。後續團隊內的開發人員只要照著軟體架構去按圖施工,就能生產具有一定水準的系統軟體。

接下來的內容,介紹一個以三層式架構為核心所發展出來的基礎軟體架構。期望讓沒有軟體架構師加持的開發人員,能有一個基礎的軟體架構來按圖施工,除了增加軟體開發的速度之外,也讓專案產出的程式碼能夠滿足:進行單元測試、重用系統邏輯、抽換資料來源….等等非功能性需求。

領域邏輯層 (Domain Layer)

領域邏輯層

接著從三層式架構中的領域邏輯層來看看,領域邏輯層所包含的物件該如何設計。領域邏輯層主要用來歸類「封裝系統邏輯」的相關程式碼,而「系統邏輯」這個概念,可以拆解為幾個模式來分門別類的設計:

  • Entity:Entity主要用來將資料單元封裝成為物件。在設計系統的時候,一個一個系統要處理的資料單元可以封裝成為Entity物件,每個Entity物件的屬性則是用來提供資料單元所包含的資料內容,像是上圖中的Employee物件、Product物件用來代表系統所要處理的員工資料、商品資料。另外,Entity物件的方法,也用來封裝各種運算功能;例如一個判斷員工是否成年的功能,就可以選擇封裝成為Employee物件的方法來提供使用。

  • IRepository:IRepository主要用來定義Entity物件進出領域邏輯層的介面(系統邊界)。在設計系統的時候,當有Entity物件需要進出資料庫或是遠端服務,可以將進出功能封裝成為IRepository介面的方法,像是上圖中的IEmployeeRepository介面用來提供Employee物件進出系統資料庫的方法定義。另外,IEmployeeRepository介面的方法,也用來封裝各種查詢功能;例如一個查詢所有售價少於100元商品的功能,就可以選擇封裝成為IEmployeeRepository介面的方法來提供使用。

  • Service:Service主要用來封裝系統終難以歸類的系統功能。在設計系統的時候,當有一個系統功能分派給Entity物件不適合、分派給IRepository介面也不適合的時候,就可以考慮額外將這個系統功能封裝為Service物件。例如一個轉帳功能,可能牽扯好幾個帳戶、並且需要許多交易紀錄,這時分派給Entity物件、IRepository介面會讓這兩者的耦合度過高,這時就可以選擇封裝一個獨立的轉帳服務物件來提供使用。

  • Context:Context主要用來提供統一的進入點來使用系統功能。在設計系統的時候,系統功能會被分派到 Entity物件、IRepository介面、Service物件來提供使用,這時加入Context物件將原本四散的職責黏合,能夠簡化使用時的複雜度。另外一個進階的議題,是統一由Context物件來提供注入與保存IRepository介面實作,也是一個減少領域邏輯層與DI Framework相依的一種解決方案。

透過上列幾個模式來分門別類的設計,基本上就可以將領域邏輯層所要封裝的系統邏輯,都建立成為一個個的物件。而套用這樣的設計架構,因為透過IRepository介面來建構出系統邊界,所以讓單元測試得以進行;透過Context物件來簡化系統複雜度,讓重用系統邏輯、抽換資料來源變成可行。

系統展示層 (Presentation Layer)

系統展示層

談完最核心的領域邏輯層,接著看系統展示層就比較輕鬆一點了。系統展示層 (Presentation Layer),用來歸類「提供操作介面」的相關程式碼,這邊所定義的操作介面有一個很重要的概念是,操作介面包含:

  • 給人使用的UI介面:給人使用的UI介面,就是應用程式的使用者介面。透過應用程式的所提供的視覺化介面,系統就可以提供資訊給使用者,並且接收使用者所輸入的資料以及操作。

  • 給系統使用的API介面:給系統使用的API介面,就是服務程式的通訊介面。服務程式提供各種通訊介面來開放功能給外部系統使用,這些介面可能會是WCF、Web Service、甚至是最近很夯的SignalR,都會是系統所提供的API介面的其中一種可選擇方案。

回過頭綜觀整個系統展示層的設計,簡單說就是對上提供介面給其他人使用,對下依照介面操作去使用領域邏輯層所提供的功能。例如說:領域邏輯層提供了一個「查詢所有售價少於100元商品的功能」,當系統提供UI介面給人使用時,可能就會提供一個顯示頁面來條列所有從資料存取層查詢出來的商品;當系統提供API介面給系統使用時,可能就會建立一個Web API的方法來提供查詢,並且使用JSON格式來回傳所有從資料存取層查詢出來的商品。

當然,沒有好處的事,我們不要去做。系統中切割出系統展示層,在專案開發的過程中會得到一個很大的好處就是:系統展示層是使用者最會修改的設計。做專案時,使用者最會有意見的就是系統展示層,當開發人員將系統展示層獨立切割開來,就算畫面怎麼變化背後的邏輯還是不會變。這樣開發人員心理上,就能比較輕鬆去面對客戶的挑戰(反正也只是畫面調調而已),而實質上因為不會動到核心的領域邏輯層,也避免了改這邊壞那邊的窘境。

資料存取層 (Access Layer)

資料存取層

最後看看在三層式架構中最單純的資料存取層。資料存取層 (Access Layer),用來歸類「實作資料存取」的相關程式碼,這邊所定義的實作資料存取,就是很簡單的實作領域邏輯層中所定義的IRepository介面。但是雖然說是很簡單的實作IRepository介面,卻也是包含了許多的變化:

  • 資料存放到資料庫(遠端):一般的Web網站、應用程式,會選擇將資料存放到遠端的Sql Server。

  • 資料存放到資料庫(近端):在一些APP的開發專案中,會選擇將資料存放在本地端的SQLite。

  • 資料存放到系統(遠端):在一些APP的開發專案中,會選擇將資料透過Web Service存放在遠端的伺服器上。

  • 資料存放到系統(近端):在一些複雜的開發專案中,會選擇資料來源是另外一個領域邏輯層。例如:一個購物商城的客戶資料來源,有可能是由另外一個客戶管理系統來提供。

  • 依照運行狀態決定:在一些APP的開發專案中,會依照網路連線狀態來決定資料存放位置。例如:網路斷線時存取本地端的SQLite、網路連線時存取遠嘟的WebService。

  • ......

在上列這些可以選擇的解決方案中,比較有趣的是資料存放到系統、依照運行狀態決定這兩個變化樣式。其中資料存放到系統這個變化樣式,為系統加入了串接各種系統的可能性,讓系統能夠像堆積木一樣,一個串一個的互相結合,大幅增加系統的重用性。而依照運行狀態決定,則是一個重用程式碼的設計,只要額外加入一個IRepository實作來判斷運行狀態,並且分配該去呼叫哪個現有的Sql實作、Web實作,就可以重複使用既有程式。

同樣的,沒有好處的事,我們不要去做。系統中切割出資料存取層,在專案開發的過程中會得到一個很大的好處就是:資料存取層是開發過程中最會修改的設計。做專案的時候,系統開發的過程中很多資料欄位都要到專案中後期客戶才會發現(很神奇,但真實)。當開發人員將資料存取層獨立切割開來,並且在資料欄位定案之前,都先透過物件操作的方式來提供資料,並在最後的最後才去建立SQL資料表。這樣在開發的過程中,就不需要反覆的調整資料表欄位、檢查對應的SQL指令,大量減少開發人員花在這些瑣碎工作上的時間成本。

下載

範例程式碼:點此下載

期許自己
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。