自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

你的分層架構(gòu)還好嗎?

開發(fā) 架構(gòu)
當(dāng)我們開始一個新的項(xiàng)目,我們就開始創(chuàng)建一個個折文件夾。哦,不對,那我們在做分層架構(gòu)設(shè)計。架構(gòu)最后落到現(xiàn)有的計算機(jī)操作系統(tǒng)上,其的展示形式是分層架構(gòu)。畢竟,硅基不如碳基。

 分層架構(gòu),不就是建文件夾的藝術(shù)嗎?

[[285132]]

注:本文更適用于中大型項(xiàng)目,小項(xiàng)目開心就好了。因?yàn)闀r代的原因,對部分詞匯描述可能不是那么準(zhǔn)確,歡迎指正。

當(dāng)我們開始一個新的項(xiàng)目,我們就開始創(chuàng)建一個個折文件夾。哦,不對,那我們在做分層架構(gòu)設(shè)計。架構(gòu)最后落到現(xiàn)有的計算機(jī)操作系統(tǒng)上,其的展示形式是分層架構(gòu)。畢竟,硅基不如碳基。

可是呢,為什么我們要做分層架構(gòu)設(shè)計呢?通過層(Layer)來隔離不同的關(guān)注點(diǎn)。

So,我要開始瞎扯了。

基本思想:關(guān)注點(diǎn)分離,劃分邊界

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

 

問題:落后的三層架構(gòu)

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

大泥球是指一個隨意化的雜亂的結(jié)構(gòu)化系統(tǒng),只是代碼的堆砌和拼湊,往往會導(dǎo)致很多錯誤或者缺陷。

在今天 DDD + 整潔架構(gòu)流行的今天, 三層分層架構(gòu)已經(jīng)完全不能滿足現(xiàn)有應(yīng)用的需求,甚至看上去一團(tuán)糟糕。它存在這么一些問題:

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

可是,為什么會這樣呢?

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

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

重新定義:消除二義性

 

當(dāng)我們談?wù)?service 的時候,我們談?wù)摰氖峭粋€ service 嗎?

當(dāng)我們談?wù)?model 的時候,我們談?wù)摰氖峭环N model 嗎?

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

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

最后,你還需要有一個相關(guān)領(lǐng)域的名詞表。

劃分邊界:業(yè)務(wù)導(dǎo)向架構(gòu)

開始之前不得不說的是:

  • 微服務(wù)是一種業(yè)務(wù)導(dǎo)向架構(gòu)。
  • 微服務(wù)是一種業(yè)務(wù)導(dǎo)向架構(gòu)。
  • 微服務(wù)是一種業(yè)務(wù)導(dǎo)向架構(gòu)。

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

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

隨后,我們還可以嘗試將單體應(yīng)用拆分到微服務(wù)。

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

關(guān)注點(diǎn)分離:針對接口編程

我們看到了整潔架構(gòu):

 

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

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

這一點(diǎn)在大部分的項(xiàng)目中,已經(jīng)實(shí)踐得相關(guān)的好。畢竟,有各種各樣的 * Service + * ServiceImpl。

除此,為了實(shí)現(xiàn)這樣的目標(biāo),對于采用 DDD 架構(gòu)的應(yīng)用來說,在我們的 domain 層的限界上下文,除了包含自身的 entity、vo 等,它應(yīng)該還帶有 repository 的抽象。這樣一來,我們的 domain 層便不依賴

應(yīng)用分層:DDD 與整潔架構(gòu)

 

所以,讓我們來看個問題。這是一個在 GitHub 上 star 數(shù)接近 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/ 

這是一個技術(shù)導(dǎo)向的應(yīng)用架構(gòu)。所以,當(dāng)我要新加一個功能的時候,我需要:

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

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

而隨著時間的推移,你現(xiàn)在已經(jīng)有一個巨大無比的 model 層,修改代碼時需要在不同的模塊跳轉(zhuǎn)。而不能快速修改相關(guān)的代碼。甚至于,你無法采用微服務(wù)架構(gòu),你是一個巨大的單體應(yīng)用。

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

切割基礎(chǔ)設(shè)施

 

你的基礎(chǔ)設(shè)施自開發(fā)完成之后,基本不變,而你的業(yè)務(wù)代碼一直在發(fā)生變化。

引起技術(shù)實(shí)現(xiàn)發(fā)生變化的原因與引起領(lǐng)域邏輯發(fā)生變化的原因顯然不同,這就導(dǎo)致基礎(chǔ)設(shè)施和領(lǐng)域邏輯問題會以不同速率發(fā)生變化。——《領(lǐng)域驅(qū)動設(shè)計模式、原理與實(shí)踐》

當(dāng)你來到一個項(xiàng)目一眼看到這么多基礎(chǔ)設(shè)施相關(guān)的目錄結(jié)構(gòu)時:

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

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

除了從目錄上 infrastructure 包/層,容納相關(guān)的基礎(chǔ)設(shè)施代碼。我們還要考慮到分層上的單一職責(zé),因?yàn)樾枰獎冸x基礎(chǔ)設(shè)施與業(yè)務(wù)代碼的關(guān)系。所以,為了實(shí)現(xiàn) Clean Architecture 的大業(yè),你還需要一層抽象接口,比如你要訪問存儲業(yè)務(wù)相關(guān)的數(shù)據(jù)。那么抽象在你的 domain 中,具體的 RepositoryImpl 實(shí)現(xiàn)是在你的基礎(chǔ)設(shè)施。

離心分離模型

 

在一個系統(tǒng)中,你會存在這么一些不同的 model:

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

  • 與數(shù)據(jù)庫表結(jié)構(gòu)對應(yīng)的 DO( Data Object)/ PO(Persistant Object)。
  • 查詢數(shù)據(jù)的 Query、Request。
  • 對外傳輸?shù)膶ο螅篋TO( Data Transfer Object)。
  • 業(yè)務(wù)層之間的數(shù)據(jù)對象:VO(Value Object) / BO(Business Object)。
  • 訪問數(shù)據(jù)庫的:DAO (Data Access Object數(shù)據(jù)訪問對象)。
  • 以及我們想要的 DDD 中的實(shí)體 Entity
  • 還有其它的 POJO( Plain Ordinary Java Object)

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

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

  • 使用 Command / Request 作為輸入?yún)?shù)。其中的 Command 模式在完成后需要發(fā)出對應(yīng)的 Event。
  • 使用 Response / DTO / Representation 作為返回結(jié)果。
  • 對 Entity 大家保持了一致的意見
  • 還有 PO / DO 作為作為數(shù)據(jù)庫的存儲模型
  • DAO 作為數(shù)據(jù)庫的訪問模型
  • ……

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

以領(lǐng)域?yàn)楹诵?,豐富行為

 

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

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

  1. 重新劃分包。即在保持業(yè)務(wù)不中斷的情況下重構(gòu),以讓新的代碼運(yùn)行在新的架構(gòu)上。
  2. 分析抽象領(lǐng)域模型
  3. 編寫 API 測試,保證現(xiàn)有的功能
  4. 編寫抽象接口,進(jìn)行依賴反轉(zhuǎn)
  5. 拆分 service 層,重構(gòu)代碼。將行為綁定于是領(lǐng)域?qū)ο笊稀?/li>

其它的情況,還要進(jìn)行 case by case 的分析。

剩下的呢?

共享的業(yè)務(wù)邏輯,可以采用 sharedkernel,或者其它模式來處理。

待繼續(xù)補(bǔ)充。

代碼共用分層:功能內(nèi)聚

 

創(chuàng)建通用的共享組件導(dǎo)致了一系列問題,比如耦合、協(xié)調(diào)難度和復(fù)雜度增加。

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

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

base 下的 base

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

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

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

無比臃腫的 bean 和 model

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

轉(zhuǎn)而,我開始考慮一個問題,當(dāng)個包(文件夾)下的文件數(shù)是否不應(yīng)該超過一定的數(shù)量?

如果一個包下的類數(shù),超過一定的范圍,那么我們應(yīng)該考慮是否存在職責(zé)相似的類。

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

什么不是 common

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

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

不要事先創(chuàng)建 common 模塊,你可能不會有這個模塊。

任何的水平分層拆分應(yīng)用,在項(xiàng)目復(fù)雜化的今天都是不靠譜的。

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

它真是個 util 嗎?

 

哦,不,它是個惡魔,因?yàn)樗?util。

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

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

而諸如 FileUtil、DateUtil、RedisUtil、JdbcUtil 這些都可以說是基礎(chǔ)設(shè)施相關(guān)的部分,它們可以劃到 infrastructure/file 又或者是 infrastructure/date 目錄下,而不是統(tǒng)一的管理這些 util。

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

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

需要個例子?

看看 Spring Framework 的源碼的分層結(jié)構(gòu),如 Spring Orm:

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

又或者是 spring-context 下的目錄分層結(jié)構(gòu):

  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 

它們都在自己的限界上下文內(nèi),維護(hù)自己的 annotaion、bean、support、i18n 等等的包。

分層架構(gòu)重構(gòu)

 

所以,我們可以嘗試這么去做架構(gòu)重構(gòu)

  1. 分析、診斷現(xiàn)有項(xiàng)目結(jié)構(gòu)
  2. 劃分新的分層架構(gòu)
  3. 功能測試
  4. 使用抽象解耦依賴
  5. 進(jìn)行細(xì)粒度的代碼重構(gòu)
  6. 重新劃分領(lǐng)域服務(wù)

還有嗎?

  1. 不要預(yù)先設(shè)計,而是定義原則與規(guī)范。
  2. 以簡單的設(shè)計開始,在生命周期中演進(jìn)架構(gòu)。
  3. 以多個 common 包,替代統(tǒng)一的 common 包
  4. TBC。

結(jié)論

 

那么,我們怎么才能做好分層架構(gòu)呢?

by experience。

哦,不對,DDD 大法好。

責(zé)任編輯:武曉燕 來源: Phodal phodal
相關(guān)推薦

2012-05-11 09:45:07

海量數(shù)據(jù)

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

物理安全網(wǎng)絡(luò)攻擊網(wǎng)絡(luò)安全

2020-11-17 09:15:21

ColabJupyterPython

2021-06-17 07:47:03

軟件架構(gòu)分層

2019-12-18 15:05:17

運(yùn)營商5G物聯(lián)網(wǎng)

2023-01-05 08:12:11

分層應(yīng)用代碼

2015-03-12 09:57:44

App StoreDNS宕機(jī)

2015-03-12 11:04:39

App StoreDNS宕機(jī)

2023-08-02 08:51:46

服務(wù)架構(gòu)分層架構(gòu)

2009-06-02 09:48:36

分層架構(gòu)PetShop.NET

2023-04-07 14:04:51

AI

2024-03-29 12:50:00

項(xiàng)目分層模型

2023-06-16 13:34:00

軟件架構(gòu)模式

2020-08-12 09:44:10

AI 數(shù)據(jù)人工智能

2019-12-23 14:36:24

運(yùn)營商攜號轉(zhuǎn)網(wǎng)5G
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號