1、寫在前面
應用分層這件事情看起來很簡單,但每一個程序員都有本身的一套,哪怕是初學者。如何讓一家公司的幾百個應用採用統一的分層結構,並獲得大部分程序員的認同呢?這可不是件簡單的事情,接下來以咱們真實案例與你們一塊兒探討,先問你們兩個技術問題:css
服務的調用代碼你以爲放到哪一層好呢?前端
- A 表現層
- B 業務邏輯層
- C 數據層
- D 公共層
如何組織好 VO(View Object 視圖對象)、BO(Business Object 業務對象)、DO(Data Object 數據對象)、DTO(Data Transfer Object 數據傳輸對象) 呢?git
不一樣的人會有不一樣的答案,因此要統一公司應用分層,以減小開發維護學習成本。統一應用分層要可大可小、簡單易用、支持多種場景,咱們採用 IPO 方式:I 是 Input、O 是 Output、P 是 Process,一進一出一處理。應用系統的本質是機器,是處理設備,一進一出一處理。程序員
IPO 原理圖github
2、統一邏輯架構
統一應用分層的邏輯架構圖redis
職責說明:數據庫
- 文件夾分層法:應用分層採用文件夾方式的優勢是可大可小、簡單易用、統一規範,能夠包括 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 項目命名規則:{產品線英文名全稱}.{子系統英文名全稱 + 應用名}.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 規範
規範說明:
- 一、VO 項目命名規則:{產品線英文名全稱}.{子系統英文名全稱 + 應用名}.ViewModel,如上圖的 Trip.Seller.ViewModel。
- 二、各 VO 實體類,咱們用 Controller 名做爲文件夾名進行分開,如上圖的 Order 文件夾。
- 三、VO 實體類名的命名建議:
- a、請求參數 VO 實體類以 Input/Form/Query 結尾,如上圖的 SearchOrderInput.cs。
- b、響應 VO 實體類以 Output/List/Result 結尾,如上圖的 SearchOrderOutput.cs。
業務對象 BO 規範(可選)
BO 實體類名以 Model 爲結尾:
規範說明:
- 一、BO 項目命名規則:{產品線英文名全稱}.{子系統英文名全稱 + 應用名}.BO,如上圖的 Trip.Order.BO;
- 二、以 Model 結尾,如上圖的 OrderModel.cs;
- 三、爲了簡化設計,BO 項目爲可選,可在 DO 項目裏建文件夾。
數據對象 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 下載
LayerDemo 下載地址:https://github.com/das2017/LayerDemo
本系列文章涉及內容清單以下(並不按這順序發佈),其中有感興趣的,歡迎關注:
做者介紹
張輝清,10 多年的 IT 老兵,前後擔任攜程架構師、古大集團首席架構、中青易遊 CTO 等職務,主導過兩家公司的技術架構升級改造工做。現關注架構與工程效率,技術與業務的匹配與融合,技術價值與創新。
轉載:http://www.infoq.com/cn/articles/architecture-practice-12-application-layer?utm_source=infoq&utm_campaign=user_page&utm_medium=link