成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

你的分層架構還好嗎?

開發 架構
當我們開始一個新的項目,我們就開始創建一個個折文件夾。哦,不對,那我們在做分層架構設計。架構最后落到現有的計算機操作系統上,其的展示形式是分層架構。畢竟,硅基不如碳基。

 分層架構,不就是建文件夾的藝術嗎?

[[285132]]

注:本文更適用于中大型項目,小項目開心就好了。因為時代的原因,對部分詞匯描述可能不是那么準確,歡迎指正。

當我們開始一個新的項目,我們就開始創建一個個折文件夾。哦,不對,那我們在做分層架構設計。架構最后落到現有的計算機操作系統上,其的展示形式是分層架構。畢竟,硅基不如碳基。

可是呢,為什么我們要做分層架構設計呢?通過層(Layer)來隔離不同的關注點。

So,我要開始瞎扯了。

基本思想:關注點分離,劃分邊界

注:三層架構(controller-service-model)并非等于于 MVC 架構模式。對于其的錯誤等同,導致了架構上的一系列錯誤。

 

問題:落后的三層架構

過去,我總以為對于大部分項目來說,三層分層架構之外的部分是大泥球,即隨意化的代碼組織方式。然而,我發現對于大部分的項目來說,三層分層架構的 service 也是個大泥球,我忘記了三層分層架構的 model 層也是一堆大泥球。Controller 相對好一點,但是對于某些項目來說也是個小泥球。

大泥球是指一個隨意化的雜亂的結構化系統,只是代碼的堆砌和拼湊,往往會導致很多錯誤或者缺陷。

在今天 DDD + 整潔架構流行的今天, 三層分層架構已經完全不能滿足現有應用的需求,甚至看上去一團糟糕。它存在這么一些問題:

  1. 統一管理是魔鬼,如 controller 文件夾下一堆的代碼,到處亂放的 model。
  2. 缺乏明確的職責劃分,如 controller 承擔了 service 的職責
  3. 臃腫的 service,和貧血的 model
  4. 三層分層之后的隨意文件組織方式,如 kafka 等到處亂放的代碼
  5. ……

可是,為什么會這樣呢?

  1. 職責(or 限界上下文)沒有劃分明確和清晰
  2. model 層存在大量的二義性
  3. 技術導向架構模式
  4. ……

于是,我們有了一些基本的解決方案,或者說是套路。

重新定義:消除二義性

 

當我們談論 service 的時候,我們談論的是同一個 service 嗎?

當我們談論 model 的時候,我們談論的是同一種 model 嗎?

若對于一個文法的某一句子存在兩棵不同的語法樹,則該文法是二義性文法。

如果有多種不同類型的類,都被放置在 model 包下。那么,你應該消除 model 這個包,改為更表意的名稱,如 Entity、* Request、* Response 等等。同理,一旦你們展開對某個名稱的討論時,是時候好好考慮其中的二義性。

最后,你還需要有一個相關領域的名詞表。

劃分邊界:業務導向架構

開始之前不得不說的是:

  • 微服務是一種業務導向架構。
  • 微服務是一種業務導向架構。
  • 微服務是一種業務導向架構。

所以,如果你的微服務劃分出現了不同的幾個技術維度的服務,那么你需要好好反思一下。

So,為了迎接業務導向架構,我們需要以采用水平 + 垂直架構的方式來重新劃分架構,將各業務模板的代碼聚合到各自的業務模板中,順便把大量地 util 和 common 內聚到服務中。而它們都基于其它低層模板。

隨后,我們還可以嘗試將單體應用拆分到微服務。

但是,我們都不應該依賴于低層模塊,于是就有了……。

關注點分離:針對接口編程

我們看到了整潔架構:

 

在其中有一個非常重要的原則:

依賴倒置原則:高層模塊不應該依賴于低層模塊,二者都應該依賴于抽象。

這一點在大部分的項目中,已經實踐得相關的好。畢竟,有各種各樣的 * Service + * ServiceImpl。

除此,為了實現這樣的目標,對于采用 DDD 架構的應用來說,在我們的 domain 層的限界上下文,除了包含自身的 entity、vo 等,它應該還帶有 repository 的抽象。這樣一來,我們的 domain 層便不依賴

應用分層:DDD 與整潔架構

 

所以,讓我們來看個問題。這是一個在 GitHub 上 star 數接近 15K 的 Java 語言編寫的開源 CMS 中,某個模塊的代碼目錄:

  1. ├── cms-admin/ 
  2. ├── cms-common/ 
  3. ├── cms-dao/ 
  4. ├── cms-job/ 
  5. ├── cms-rpc-api/ 
  6. ├── cms-rpc-service/ 
  7. ├── cms-search/ 
  8. └── cms-web/ 

這是一個技術導向的應用架構。所以,當我要新加一個功能的時候,我需要:

  1. 在 cms-dao 模塊中加一個 model 和一個 mapper
  2. 在 cms-rpc-service 模塊中加一個 service
  3. 在 cms-web 模塊中中加一個 controller

“完美”,沒有什么問題啊。

而隨著時間的推移,你現在已經有一個巨大無比的 model 層,修改代碼時需要在不同的模塊跳轉。而不能快速修改相關的代碼。甚至于,你無法采用微服務架構,你是一個巨大的單體應用。

為了挽救這樣的一個項目,我們不得不嘗試做一些事情。

切割基礎設施

 

你的基礎設施自開發完成之后,基本不變,而你的業務代碼一直在發生變化。

引起技術實現發生變化的原因與引起領域邏輯發生變化的原因顯然不同,這就導致基礎設施和領域邏輯問題會以不同速率發生變化。——《領域驅動設計模式、原理與實踐》

當你來到一個項目一眼看到這么多基礎設施相關的目錄結構時:

  1. ├── controller 
  2. ├── interceptor 
  3. ├── jms 
  4. ├── rocketmq 
  5. ├── schedule 
  6. └── task 

有一天,我們又加了一個 Kafka,我們又不新加一個文件夾,而這樣的分層設計看上去沒有一點組織。然后呢,我們打開目錄的時候,無法快速定位到我們的代碼。

除了從目錄上 infrastructure 包/層,容納相關的基礎設施代碼。我們還要考慮到分層上的單一職責,因為需要剝離基礎設施與業務代碼的關系。所以,為了實現 Clean Architecture 的大業,你還需要一層抽象接口,比如你要訪問存儲業務相關的數據。那么抽象在你的 domain 中,具體的 RepositoryImpl 實現是在你的基礎設施。

離心分離模型

 

在一個系統中,你會存在這么一些不同的 model:

(PS:部分描述可能不準確,歡迎指正)

  • 與數據庫表結構對應的 DO( Data Object)/ PO(Persistant Object)。
  • 查詢數據的 Query、Request。
  • 對外傳輸的對象:DTO( Data Transfer Object)。
  • 業務層之間的數據對象:VO(Value Object) / BO(Business Object)。
  • 訪問數據庫的:DAO (Data Access Object數據訪問對象)。
  • 以及我們想要的 DDD 中的實體 Entity
  • 還有其它的 POJO( Plain Ordinary Java Object)

但是它們都是 model,所以它們都被扔到 model 中……,又或者是 bean 中……。導致,你有了一個巨大比的 model 層。

所以,在 DDD 又或者是 Clean Architecture,我們重新命名了不同的模式:

  • 使用 Command / Request 作為輸入參數。其中的 Command 模式在完成后需要發出對應的 Event。
  • 使用 Response / DTO / Representation 作為返回結果。
  • 對 Entity 大家保持了一致的意見
  • 還有 PO / DO 作為作為數據庫的存儲模型
  • DAO 作為數據庫的訪問模型
  • ……

不過,其實你只要不再讓使用 model 和 bean,相似會有更多地收獲。

以領域為核心,豐富行為

 

當完成了大坨的移動文件夾操作之后,我們來到了最麻煩和復雜的一部分。

我們需要對領域模型進行重新建模,重新規劃 model 和 service,讓 model 變成了富血模型。也許,你需要一場 Event Storming,才能完成真正意義的事件風暴建模。不過,步驟上也不會有太多的差異。

  1. 重新劃分包。即在保持業務不中斷的情況下重構,以讓新的代碼運行在新的架構上。
  2. 分析抽象領域模型
  3. 編寫 API 測試,保證現有的功能
  4. 編寫抽象接口,進行依賴反轉
  5. 拆分 service 層,重構代碼。將行為綁定于是領域對象上。

其它的情況,還要進行 case by case 的分析。

剩下的呢?

共享的業務邏輯,可以采用 sharedkernel,或者其它模式來處理。

待繼續補充。

代碼共用分層:功能內聚

 

創建通用的共享組件導致了一系列問題,比如耦合、協調難度和復雜度增加。

當我看到一個個巨大的 common 包時,我開始痛恨 common、 base、 util 這些該死的包,還有它們目錄下統一管理的 bean。我們真的已經把它們用爛了,所以你應該重新審視一下你的項目代碼。

所以,從這種意義上來說:復用與低耦合,本身存在一定的互斥關系。

base 下的 base

過去,我曾經重構過一個 base 項目的代碼,正是這次重構讓我意識到 base 并不是一個好東西。如果在項目中已經抽取出了一個 base 模塊,那么這個模塊下是不應該存在 base 這樣的業務邏輯。而且,base 這個東西導致了一個問題是,只要是共用的東西就會不加思索的扔到 base 中。

你會有一個 base 的包,放著各種抽象接口,但是你需要一個更好的名字,比如 concepts,比如 support。

總之,你不應該存在 base 模塊,讓開發人員思考一下哪去放新的類。

無比臃腫的 bean 和 model

“這本身是怪不得程序員的,要怪就怪該死的 Java 語言。”

轉而,我開始考慮一個問題,當個包(文件夾)下的文件數是否不應該超過一定的數量?

如果一個包下的類數,超過一定的范圍,那么我們應該考慮是否存在職責相似的類。

這部分可以參考上一部分的離心分離模型。

什么不是 common

common 這個名字真的很爛,比 base 和 model 更爛。

一旦你從項目中拆出了一個 common 模塊,那只會有一個結果,你將得到一個 5G 時代的 jar 包。甚至于,你看到有一塊代碼在 IDE 中是灰色的、未使用的,你也不敢輕易去刪除這些代碼。直到有一天,這個 common 包構建出來的大小有 10M、20M,而你只需要引用一個 AESUtil 的時候,你才發現了問題:原本幾十 K 的 hello, world,現在變成了幾十 M。

不要事先創建 common 模塊,你可能不會有這個模塊。

任何的水平分層拆分應用,在項目復雜化的今天都是不靠譜的。

誰用誰管理,而不是覺得是 common 就扔 common 模塊。

它真是個 util 嗎?

 

哦,不,它是個惡魔,因為它是 util。

你會往 xxUtil 不加思索地扔入邏輯,正如你會往 common/bean 中扔入所有的 model,直次有一天,你擁有一個巨大無比的 base、common 代碼。

大多數情況下,所有和業務相關的 Util 都存在一定的問題,如 CaptchaUtil,它要么應該劃到自己的上下文中去,要么扔到諸如于 domain/shared 等共享上下文,而不是和其它 util 放到一起。

而諸如 FileUtil、DateUtil、RedisUtil、JdbcUtil 這些都可以說是基礎設施相關的部分,它們可以劃到 infrastructure/file 又或者是 infrastructure/date 目錄下,而不是統一的管理這些 util。

如 StackOverflow 的相關問題所列,我們還有諸如 Coordinator、Builder、Writer、Reader、Handler、Container、Protocol、Target、Converter、Controller、View、Factory、Entity、Bucket 等名稱。

試著干掉 Util,你將收獲更多的類,笑~。

需要個例子?

看看 Spring Framework 的源碼的分層結構,如 Spring Orm:

  1. └── orm 
  2.  ├── ObjectOptimisticLockingFailureException.java 
  3.  ├── ObjectRetrievalFailureException.java 
  4.  ├── hibernate5a/ 
  5.  ├── jpa/ 
  6.  └── package-info.java 

又或者是 spring-context 下的目錄分層結構:

  1. └── springframework 
  2.  ├── cache 
  3.  │   ├── annotation 
  4.  │   ├── concurrent 
  5.  │   ├── config 
  6.  │   ├── interceptor 
  7.  │   └── support 
  8.  ├── context 
  9.  │   ├── annotation 
  10.  │   ├── config 
  11.  │   ├── event 
  12.  │   ├── expression 
  13.  │   ├── i18n 
  14.  │   ├── index 
  15.  │   ├── support 
  16.  │   └── weaving 

它們都在自己的限界上下文內,維護自己的 annotaion、bean、support、i18n 等等的包。

分層架構重構

 

所以,我們可以嘗試這么去做架構重構

  1. 分析、診斷現有項目結構
  2. 劃分新的分層架構
  3. 功能測試
  4. 使用抽象解耦依賴
  5. 進行細粒度的代碼重構
  6. 重新劃分領域服務

還有嗎?

  1. 不要預先設計,而是定義原則與規范。
  2. 以簡單的設計開始,在生命周期中演進架構。
  3. 以多個 common 包,替代統一的 common 包
  4. TBC。

結論

 

那么,我們怎么才能做好分層架構呢?

by experience。

哦,不對,DDD 大法好。

責任編輯:武曉燕 來源: Phodal phodal
相關推薦

2012-05-11 09:45:07

海量數據

2022-02-22 19:26:58

Wi-Fi 6EWi-Fi 7Wi-Fi 6

2009-07-27 10:11:08

富士康孫丹勇

2019-05-23 11:23:50

2013-07-15 09:57:24

微軟SaaSTurner

2023-03-09 08:13:34

2022-05-17 14:17:50

物理安全網絡攻擊網絡安全

2020-11-17 09:15:21

ColabJupyterPython

2021-06-17 07:47:03

軟件架構分層

2019-12-18 15:05:17

運營商5G物聯網

2023-01-05 08:12:11

分層應用代碼

2009-06-02 09:48:36

分層架構PetShop.NET

2015-03-12 09:57:44

App StoreDNS宕機

2015-03-12 11:04:39

App StoreDNS宕機

2023-08-02 08:51:46

服務架構分層架構

2023-04-07 14:04:51

AI

2024-03-29 12:50:00

項目分層模型

2023-06-16 13:34:00

軟件架構模式

2020-08-12 09:44:10

AI 數據人工智能

2017-10-15 14:36:10

互聯網分層架構服務化
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 色婷婷精品国产一区二区三区 | 丝袜美腿一区二区三区 | 国产精品美女视频 | 欧美视频二区 | 成人国产精品久久久 | 亚洲成人精品国产 | 亚洲国产精品久久 | 精品一区二区三区免费毛片 | 国产一级在线 | 日韩另类视频 | 国产精品福利网站 | 亚洲免费精品 | 午夜视频在线免费观看 | 国产高清在线精品 | 黄色三级在线播放 | 久久国产成人 | 免费在线观看成人 | 日韩a在线 | 国产欧美日韩一区二区三区在线 | 国产传媒在线播放 | 久久视频精品 | 亚洲国产精品久久久久秋霞不卡 | 电影午夜精品一区二区三区 | 亚洲网站在线观看 | 免费在线h视频 | 亚洲一区国产 | 999精品网| 视频在线一区二区 | 9191在线播放| 国产精品久久久久久福利一牛影视 | 在线免费激情视频 | 青青草社区| 黄色毛片免费看 | 久久久久久久久久久福利观看 | 国产精品1区 | 欧美综合一区二区三区 | 一区二区三区四区免费观看 | 精品欧美一区二区三区久久久 | 日韩精品免费一区二区在线观看 | 一区二区三区视频在线免费观看 | 久久99视频这里只有精品 |