Web Application Architecture (Repository Pattern)
2022-12-16
筆記關於網頁應用系統的分層架構設計。
說明
在剛學 ASP.NET MVC 的時候,習慣把所有的程式碼包含資料處理與商業邏輯,通通都寫在 Controller。雖然開發起來很方便,但隨著開發規模擴大,有維護或者變動需求的時候,要尋找著手的修改點就痛到不行,通常都是改天比改 Code 更多。
後來開始依照情境,把商業邏輯都放在 Model,有時候橫空又創出一個 Service 資料夾或者 Business 資料夾,沒有太多分類邏輯的就把檔案散置其中,於是從混亂的 Controller 變成了混亂的檔案分類。
隨著 Entity Framework 的學習,發現許多的分層討論都伴隨著 Entity Framework 的發生,甚至慢慢引領開發人員走向 Domain Drive Developement 的方向,這篇筆記沒有太大的野心,就是先將網路上、課程中以及各式來源的 Web Application 分層方式做一個綜整筆記,在加上一點自己的心得 😉
Presentation Layer
接收使用者請求與進行回應,以 ASP.NET MVC 與 Web API 就是以 Controller 作為代表進行請求的處理 (Route, Query String, Form body 等)。
收到的請求會在透過 Service Layer 進行商業邏輯的處理,並且在依照前端的類型回應 ViewModel, View 或者是 Json 資料。
Controller 不適合出現商業邏輯,會造成程式維護的困難以及無法測試。
一個設計 Presentation Layer 的方式就是判斷如果今天專案不是 MVC 的時候,在 Presentation Layer 的程式碼仍想被重複使用該怎麼辦?在設計上就應開發在可被共用的 Service Layer。
Service Layer
將商業邏輯進行封裝提供 Presentation Layer 使用,而關於資料 CRUD 的工作則交由 Repository Layer 進行。
Service Layer 下可以再分出 Business Layer,但部分時候兩者被當稱別稱互相替代。
Service Layer 一派的認為包含處理 Logging, Exception, Authorization,但另一派則將此類分層在 Common 進行處理。
如果選擇分出 Business Layer,在 Service Layer 會扮演輕量的介面,設計上可以是 Web API 或者是 POCOs。
Business Layer
別名為 Domain Model, Domain Layer。
在 Business Layer 可以採用的技術包含 Transaction Script, Table Module, Active Record 或 Domain Model。
而如果採用 Table Module 或 Active Record,則會與 Data Access Layer 混合在一起,
例如直接使用 Entity Framework 而不使用 Repository 的情況。
而使用 Transaction Script 則會搭配 Data Access Layer 進行資料庫 CRUD 控制;
如果使用 Domain Model 則會需搭配 Repository Layer 由資料操作轉為物件操作的方式,以符合領域以及商業知識的開發維護。
Repository Layer
負責料的存取操作資,包含如何取得資料以及取得多少資料,但不包含商業邏輯,僅只限於資料存取本身。
如果要對存取到的資料再去做篩選,適合在 Service Layer 以商業邏輯進行。
Repository 下可以再分出 Data Access Layer,但部分時候兩者被當成別稱互相替代。
Repository 相關的名詞
- Domain Driven Development
- Bounded Context
- Unit of Work
Data Access Layer
Data Access 的技術可以選擇的包含 ADO.NET, Entity Framework 或者是 Dapper。
在這一層要負責項目包含與資料庫的 CRUD, Transaction 以及 Concurrency,
而如果在 Business Layer 使用的是 Active Record 或者是 Table Module,Data Access Layer 與 Business Layer 不會有明顯的分界。
DTO / ViewModel
全名為 Data Transfer Model,在 Presentation Layer, Service Layer 以及 Repository Layer 之間溝通進行傳遞的物件。
通常與 Domain Model 的類別物件有所區別,會因應 View 或者商業邏輯的需求,增減不同的 Property,
而純粹的 DTO 只有 Property 不會具有方法,但在其他的使用情境也是有在 ViewModel 當中加入方法組合 Property 的技巧。
DTO 背後可以代表的是 Controller 所需要的 ViewModel 或者來自使用者的 Parameter 或者是要傳入 Repository 的 Condition,
藉由 DTO 可以隱藏參數的複雜性,並且減少分層之間的耦合關係。
Common Layer
將各層會使用到的共用類別,包含 Enum 以及 Extension Methods 分離為獨立的層別。
Common Layer / Infrastructure
Folders vs Projects
Visual Studio 在專案上可以透過「資料夾分層」或「專案分層」的方式進行分層。
用途
分層所帶來的明確好處包含:
- 關注點分離:讓程式碼依照功能分門別類專責工作,在維護或擴充時能夠快速定位進行修改
- 合作開發:基於關注點分離,要合作開發可以分從不同的層去進行、避免程式碼的衝突
- 程式碼的重複使用:因為分層與分類,程式碼邏輯可以被重複使用,避免維護上需要逐一修改所有地方
- 面對需求的彈性:當需求變化時,例如資料庫底層或者是使用者介面層的調整,只需要在對應的層調整,其他地方可以沿用
心得
分層依照不同的開發團隊有不同的使用方式與定義,必須知道的是不必為分層而分層,在開發初期的分層會有額外的成本,但在程式規模的成長之後則能帶來維護與擴充的成本降低。
而該如何進行分層?可以從思考這項功能是否專屬於目前的環境平台或者是否有重複使用的必要性,如果有就不應該放在 Presentation 而是往 Service、Business 去安插,
因此在沒有複雜的分層前提下,可以做到的會是先分出 Presentation 與 Service (Business),至於 Data Access 或者是 Repository 則明顯區隔,
先藉由 Entity Framework 扮演 Data Access 的方式,同時採 Active Record 的方式直接由 DbContext 透過 DBSet 與資料表的對應進行資料的 CRUD。
此外如果近乎沒有成本的分層預備動作可以先完成,例如將專案的命名加入 .Web
,方便日後的其他專案加入 .Service
、.DAL
等對應。
Sample Codes
分層但不使用 Repositoroy 的範例,搭配文章 博客園的大牛們,被你們害慘了,Entity Framework從來都不需要去寫Repository設計模式 服用。
ASP.NET MVC 專案分層架構 Part.1 初學者的起手式
參考資料
從 Pluralsight 挖出來的珍貴課程 Architecting Applications for the Real World in .NET 已經被歸類為 Retired,但充滿參考價值的課程,從時間成本的觀點來看待分層架構的必要性以及各層應扮演怎麼樣的角色。課程的內容和 Martin Fowler 的企業級軟體架構模式:軟體重構教父傳授 51個模式,活用設計思考與架構決策 有許多概念關聯,也為更進階的學習提供了方向。
用Repository Pattern抽離對Entity Framework的依賴 | Alan Tsai 的學習筆記
隨手 Design Pattern (2) - 軟體分層設計模式 (Software Layered Architecture Pattern) | Ray's Notes
隨手 Design Pattern (4) - Repository 模式 (Repository Pattern) | Ray's Notes
菜雞新訓記 (5): 使用 三層式架構 來切分服務的關注點和職責吧 | 伊果的沒人看筆記本