1、寫在前面
應用分層這件事情看起來很簡單,但每一個程序員都有本身的一套,哪怕是初學者。如何讓一家公司的幾百個應用採用統一的分層結構,並獲得大部分程序員的認同呢?這可不是件簡單的事情,接下來以咱們真實案例與你們一塊兒探討,先問你們兩個技術問題:
- 服務的調用代碼你以爲放到哪一層好呢?A表現層;B業務邏輯層;C數據層;D公共層。
- 如何組織好VO(View Object視圖對象)、BO(Business Object業務對象)、DO(Data Object數據對象)、DTO(Data Transfer Object數據傳輸對象)呢?
不一樣的人會有不一樣的答案,因此要統一公司應用分層,以減小開發維護學習成本。統一應用分層要可大可小、簡單易用、支持多種場景,咱們採用IPO方式:I是Input、O是Output、P是Process,一進一出一處理。應用系統的本質是機器,是處理設備,一進一出一處理。
IPO原理圖
2、統一邏輯架構
統一應用分層的邏輯架構圖
職責說明:
層英文名 |
中文名 |
說明 |
|
PresentationLayer |
表現層文件夾 |
上層向用戶提供服務,負責視圖展現。項目類型包括WebSite、WebForm、MVC、WCF、WebService等。 |
|
BusinessLayer |
業務邏輯層文件夾 |
中間邏輯處理,負責應用系統的業務邏輯的處理。 |
|
DataLayer |
數據訪問層文件夾 |
下層調用服務,負責數據資源提供方如數據庫、SOA、OpenAPI的交互。 |
|
EntityLayer |
實體層文件夾 |
VO:View Object視圖對象; DTO:Data Transfer Object數據傳輸對象; BO:Business Object業務對象; DO:Data Object數據對象; 在實際項目中,爲簡化設計可進行裁剪,BO和DO爲可選,DTO屬於服務項目類型,VO屬於網站項目類型,也不會同時存在。 |
|
CommonLayer |
公共層文件夾 |
工具類庫,負責提供應用系統中經常使用的操做。 |
|
TestLayer |
測試層文件夾 |
單元測試(可選),負責對其它類庫的自動化單元測試。 |
|
|
|
|
|
- 文件夾分層法:應用分層採用文件夾方式的優勢是可大可小、簡單易用、統一規範,能夠包括5個項目,也能夠包括50個項目,以知足全部業務應用的多種不一樣場景;
- 調用規約:在開發過程當中,須要遵循分層架構的約束,禁止跨層次的調用;
- 下層爲上層服務:以用戶爲中心,以目標爲導向。上層(業務邏輯層)須要什麼,下層(數據訪問層)提供什麼,而不是下層(數據訪問層)有什麼,就向上層(業務邏輯層)提供什麼;
- 實體層規約:DO是數據表對象,不是數據訪問層對象,不是隻能給數據訪問層使用;DTO是網絡傳輸對象,不是表現層對象,不是隻能給表現層使用;BO是內存計算邏輯對象,不是業務邏輯層對象,不是隻能給業務邏輯層使用 。若是僅限定在本層訪問,則致使單個應用內大量沒有價值的對象轉換。以用戶爲中心來設計實體類,能夠減小無價值重複對象和無用轉換;
- U型訪問:下行時表現層是Input,業務邏輯層是Process,數據訪問層是Output。上行時數據訪問層是Input,業務邏輯層是Process, 表現層就Output。
3、咱們的具體規範
此規範咱們用了四年,牽涉幾百個應用,200多個研發人員,是一個成功的實踐。接下來就借用本文提供下載的TripOrderService、TripSellerMVCSite這兩個Demo來進行具體規範的說明,如下是截圖:
3.一、項目命名規則
項目命名規則:{產品線英文名全稱}.{子系統英文名全稱+應用名}.{項目職責英文名全稱},如:Trip.Seller.DTO。
3.二、業務邏輯層的項目規範
規範說明:
一、項目名的命名規則:{產品線英文名全稱}.{子系統英文名全稱+應用名}.xxxBusiness,如上圖的Trip.Order.Business。
二、類名以Logic結尾,如上圖的OrderLogic.cs。
3.三、數據操做項目規範
規範說明:
一、各數據操做項目名根據使用什麼數據庫進行分類,而後以DB爲結尾,具體命名規則是:{產品線英文名全稱}.{子系統英文名全稱+應用名}.{使用什麼數據庫}DB,如上圖的Trip.Seller.MSSQLDB。
二、若是涉及到多個數據庫訪問的,那麼數據操做項目下的類文件須要按數據庫名稱(以DB爲結尾)建立文件夾分開,如上圖的TripOrderDB文件夾。
三、建議在應用中使用SQL語句,不使用存儲過程。在數據庫中不新增存儲過程,但舊的存儲過程能夠繼續使用和修改。
四、分頁建議使用數據庫(如SQLServer)的最新特性進行分頁,並將每一個分頁SQL直接寫到應用中。
3.四、實體類項目規範
規範說明:
一、DTO項目命名規則:{產品線英文名全稱}.{子系統英文名全稱+應用名}.DTO,如上圖的Trip.Order.DTO。
二、請求參數DTO實體類、響應DTO實體類存放規範以及其命名規則:
a、請求參數DTO實體類放在Request文件夾下,且命名規則爲:以Request結尾,如上圖的SearchOrderRequest.cs。
b、響應DTO實體類放在Response文件夾下,且命名規則爲:以Response結尾,如上圖的SearchOrderResponse.cs。
c、若是請求參數DTO實體類或響應DTO實體類的屬性中有對象或枚舉,那麼這些對象所屬的類、枚舉放在DTO項目的Common文件夾下。
三、若是請求參數DTO實體類、響應DTO實體類有基類要繼承,那麼建議爲基類取名爲RequestBase.cs、ResponseBase.cs。且這些基類直接放在DTO項目的Common文件夾下。
規範說明:
一、VO項目命名規則:{產品線英文名全稱}.{子系統英文名全稱+應用名}.ViewModel,如上圖的Trip.Seller.ViewModel。
二、各VO實體類,咱們用Controller名做爲文件夾名進行分開,如上圖的Order文件夾。
三、VO實體類名的命名建議:
a、請求參數VO實體類以Input/Form/Query結尾,如上圖的SearchOrderInput.cs。
b、響應VO實體類以Output/List/Result結尾,如上圖的SearchOrderOutput.cs。
BO實體類名以Model爲結尾:
規範說明:
一、BO項目命名規則:{產品線英文名全稱}.{子系統英文名全稱+應用名}.BO,如上圖的Trip.Order.BO;
二、以Model結尾,如上圖的OrderModel.cs;
三、爲了簡化設計,BO項目爲可選,可在DO項目裏建文件夾。
規範說明:
一、DO項目命名規則:{產品線英文名全稱}.{子系統英文名全稱+應用名}.Entity,如上圖的Trip.Seller.Entity;
二、若是涉及到多個數據庫訪問的,那麼須要按數據庫名稱(以DB爲結尾)建立文件夾分開,如上圖的TripOrderDB文件夾;
三、表名+Entity結尾,如上圖的OrderEntity.cs;
四、DO是數據表對象,供單表CURD操做。對於多表查詢請求對象和返回對象,可定義新對象或使用現有對象(DTO/BO)來完成。
3.五、數據庫鏈接配置規範
規範說明:
一、數據庫鏈接的配置必須讀寫分離。
二、數據庫鏈接字符串建議加密處理。
三、數據庫鏈接配置名的命名規則:{以DB爲結尾的數據庫名稱}_讀寫類型,如:
TripOrderDB_SELECT、TripOrderDB_INSERT。
3.六、配置文件方面的規範
規範說明:
一、全部配置文件(除Web.config文件外)都必須放到Config文件夾下。
二、全部配置文件(除Web.config文件外)按不一樣環境區分開,具體命名規則是:{功能模塊英文名}.{環境英文簡稱名}.config,其中本地環境的英文簡稱名是Dev,測試環境的英文簡稱名是Test,正式環境的英文簡稱名是Prod,如上圖的AppSetting.Dev.config。
三、保持Web.config配置文件的乾淨,只留環境設置節點。
3.七、靜態資源文件方面的規範
規範說明:
一、公共的靜態資源文件(css、js、image等)放在另外的靜態站點中,統一由前端進行開發和維護。通常,css文件放在css文件夾下,js文件放在js文件夾下,image圖片文件放在img文件夾下。
二、與某項業務有關的js文件能夠放到各自業務項目的表現層PresentationLayer下,以方便開發人員調試,js文件可放在項目的js文件夾下。
三、靜態資源文件必須使用版本號管理,以防更新後因爲客戶端瀏覽器緩存而致使站點使用的依然是舊版本的靜態資源文件:
<script src="~/js/order.js?v=@AppSetting.StaticFileVersion"></script>
4、寫在最後
4.一、問題回答
問:服務的調用代碼應該放到哪一層呢?
A表現層、B業務邏輯層 、C數據層、D公共層。
答:咱們的規範是統一放到數據資源訪問層即C。上層提供服務,下層調用服務,中間處理業務邏輯。
問:如何組織好VO(View Object視圖對象)、BO(Business Object業務對象)、DO(Data Object數據對象)、DTO(Data Transfer Object數據傳輸對象)呢?
答:一般有兩種作法,限定訪問範圍和不限定訪問範圍,實際項目中可根據須要選擇、折中或裁剪。咱們使用後者,將EntityLayer做爲通用對象放到左側,具體可參考實體層規約:「DO是數據表對象,不是數據訪問層對象,不是隻能給數據訪問層使用;DTO是網絡傳輸對象,不是表現層對象,不是隻能給表現層使用;BO是內存計算邏輯對象,不是業務邏輯層對象,不是隻能給業務邏輯層使用 。若是僅限定在本層訪問,則致使單個應用內大量沒有價值的對象轉換。以用戶爲中心來設計實體類,能夠減小無價值重複對象和無用轉換。」
問:應用分層範例代碼的編寫須要注意些什麼?
答:應用分層範例的代碼要想寫好,很是不容易,很容易引發爭議,很難讓全部人滿意。咱們在具體實踐時遵循如下幾點:
- 應用分層範例的主要價值是明確層的職責和交互,每一個層的職責是什麼,哪些要幹,哪些不要幹,以及層與層之間依賴和交互;
- 私人定製:減小通用幫助類的編寫,若是每個應用中有大量相同的幫助類,這在架構層面上是有問題。在咱們的幾百個線上應用中,儘管減小通用的代碼,包括分頁幫助類、數據庫幫助類、緩存幫助類、MQ幫助類、日誌幫助類、AOP幫助類、線程幫助類。業務應用的重點是爲業務服務,每個應用都是特別的,都須要私人定製,極少有通用的代碼,若是有,那麼應該由框架或組件專門解決;
- 少便是多:應用的場景多,參考人員多,每一個人想法不一樣,牽涉的時間長,因此儘可能只作你們都認同的規範、正確的事情,要自底向上、要減小有爭議的代碼範例,不然一個錯誤將會放大百倍、一個有爭議的規範將會很難推行。
- 追求簡單:代碼編寫可分爲三個層次,簡單、複雜、簡單。第一簡單是不知道的簡單,第二個複雜是知道後的複雜,第三個簡單是知道後有取捨的簡單。範例代碼要追求簡單,既可輕鬆擴展支持複雜場景,又要簡單到初級程序員也能操做。
- 內聚大於解耦:內聚是什麼,內聚是部門內有共同的目標,而後你們緊密合做。解耦是什麼,解耦是部門間各自職責明確,而後減小沒必要要的鏈接。一個應用如同一個部門,應有一個共同的目標和職責,而後你們緊密合做。換句話說,應用內部應減小沒必要要契約接口(如同公司間才簽約合同),減小沒必要要的依賴注入實現,減小沒必要要且代價過大的解耦。一切以簡單實用爲主,以應用價值輸出、應用的目標(接口或界面)爲導向。
4.二、Demo下載