溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于領域分析web設計的架構規(guī)范

發(fā)布時間:2021-11-16 13:41:38 來源:億速云 閱讀:112 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“基于領域分析web設計的架構規(guī)范”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“基于領域分析web設計的架構規(guī)范”吧!

讀寫隔離后的世界

基于上面提到的讀寫隔離的思想,那么我們可以很清楚地看到上面這種情況可以看到:

基于領域分析web設計的架構規(guī)范

查詢業(yè)務,從入口層(如Controller),調(diào)用Finder,而Finder調(diào)用Repository(具體實現(xiàn)如Hiberante,Mybatis等等均可),這一條線下來,我們?nèi)徊挥每紤]這個系統(tǒng)的增刪改就是如何做的,就像他們完全處于不同的空間一樣,互不干涉,互不影響,甚至,永遠互不相見。 某種程度上來說,這種這種架構追求的效果,一種美感。

所以,接下來,我們關注的,就是增刪改這一部分了,也就是命令操作 是開始要扎扎實實地來對這個系統(tǒng)進行修改了

首先讓我們把視野抬高一些,從整個項目產(chǎn)品的上空來看看

業(yè)務靈魂-狀態(tài)圖

除開少數(shù)非常扁平的純技術服務項目(比如AI識別,文本分析等等),其他絕大部分企業(yè)項目都有其核心的商業(yè)邏輯,而這些邏輯,往往也會以核心的領域概念來提現(xiàn),從簡單粗暴一點角度映射到設計開發(fā)中,那就是類class

  • 電商系統(tǒng),核心領域至少有【商品】,【訂單】,【用戶】,【物流】等;

  • SNS社交平臺,至少有【用戶】,【博文/帖子】,【私信】,【通知】等;

  • 進銷存系統(tǒng),至少有【賬戶】,【角色/權限】,【商品】,【客戶/供應商】等;

  • 在線教育平臺,至少有【用戶】,【課程】,【訂單】等;

而這其中,也有主次,大家可以回頭看看自己所開發(fā)過的項目。 但凡是有狀態(tài)字段的類,很大可能都是整個項目的核心領域之一。 其實很好理解,因為它有流程,因為它需要被各類操作來變更它的狀態(tài),所以,他很可能貫穿了這個項目中某一個關鍵商業(yè)邏輯,比如電商系統(tǒng)中,

  • 【訂單】肯定有狀態(tài),從[待支付]-[已支付]-[派送中]-[已收貨],甚至還有[已取消],[退款中],[退款失敗],[退款成功],腦補一下,就知道會生成多少復雜的業(yè)務流程了

  • 【用戶】一般來說也會有狀態(tài),比如[正常],[凍結],但是可以想到,如果某個系統(tǒng)沒有這方面權限與安全的要求,【用戶】也可能就沒有狀態(tài)了,那么自然也不會有對應的操作對其進行修改,可能只會有創(chuàng)建

所以,如果在這些系統(tǒng)的早期設計階段,要我選擇一個最重要的UML圖,我會選擇狀態(tài)圖,以下就是整個系統(tǒng)中最核心的訂單狀態(tài)圖

基于領域分析web設計的架構規(guī)范

可以看到,把握一個核心領域的狀態(tài)變更,自然而然就能歸納出來很大一部分系統(tǒng)的功能需求。我們在這里看到,這些所有箭頭所觸發(fā)的動作,其實都是命令,也其實都是會落地到各個相關領域的增刪改上。

當然這里還是一個粗粒度的表示,無法單單依據(jù)這個就馬上落地開發(fā),因為即使每一個箭頭所代表的功能都可以寫出一個完整甚至很復雜的用例。但至少這是一個非常清晰的引導。

貧血模型的世界

我們目前所用的Spring體系,幾乎都是貧血模型,也就是說,真正的實體類里,都只有各個屬性的Get與Set方法。 而假如我們要進行一個操作,訂單取消,那么最常見的做法是什么?

//一個大而全的訂單服務類
public class OrderService{
   public void cancelOrder(Long orderId){
       Order order = orderRepository.getById(orderId);
       order.setStatus(OrderStatus.CANCELLED);
       //省略,其他屬性的操作...
   }
}

//然后在上層(如Controller層)中這么調(diào)用
orderService.cancelOrder(10086);

這是目前行業(yè)中非常流行的做法,也是Spring的IOC機制天然形成的做法————盡可能的無狀態(tài)化。這種做法,在業(yè)務迭代時對代碼的變動評判標準相對簡單,都往Service里放就行了,然后實體對象只需要GetSet即可,簡單粗暴,非常容易上手,也正是這種特性,讓這種編碼風格廣為流傳。

以上這些話沒有任何貶義,因為任何事情,存在即合理,我所經(jīng)歷的公司項目,幾乎都是這樣做的,大家合作起來沒多大問題,業(yè)務也都還跑得不錯。

那為什么我還想去做一些改變呢?

實體Entity的世界

因為我覺得我們需要再重新審視一下實體Entity

實體為什么要有主鍵? 因為沒有主鍵,那我們怎么知道時要查詢/修改哪條數(shù)據(jù)呢?

這個回答沒有問題,只是這句話里其實還蘊藏更深的含義

  1. 這個實體是一個真實存在的東西(對,哪怕它看不見摸不著,但也是存在的),而且會以一種形態(tài)被“存儲/持久化”在一個存儲介質(zhì)里,比如說數(shù)據(jù)庫;

  2. 當我們需要對某個實體進行操作時,我們需要通過一種手段將它“加載/讀取/獲得”出來,就像你取快遞時,快遞員根據(jù)你提供的編號,從包裹里把那個東西取出來,完全一樣;

  3. 取出來了怎么辦?那自然就是要對它進行操作了。沒錯,這個操作,就是對我們找出來的實體進行操作,而不是別的東西。

所以,從“拿取”,到“操作”,這兩步,一切順理成章,行云流水,所以,以領域驅(qū)動設計的做法,或者說,充血模型的做法,會是這樣:

//應用層入口類,這里以Controller為例
public class OrderController{
   
   @PostMapping("/cancel")
   @Transactional
   public ActionResponse cancelOrder(@RequestBody CancelOrderRequest request){
   
       //拿?。焊鶕?jù)標識符定位到我們要操作的實體
       Order order = orderRepository.getById(request.getOrderId());
	   
       //操作:對,沒錯,說的就是你 order,就是對你,進行操作,不是別人!
       order.cancel();
	   
       //返回結果
       return ActionResponse.ok();
   }
}

//真正的業(yè)務邏輯,就是在Order實體里
@Entity
public class Order{

	private OrderStatus status;
	private String customerName;
	//...
	
	public void cancel(){
	    //變更狀態(tài)
	    status = OrderStatus.CANCELLED;
	    //一些其他屬性變動,略
	}
}

好,依舊有不少值得探討的地方:

  1. 我們這里直接在Controller中就開啟了Transactional,可能看起來有點反常規(guī),但我個人覺得沒什么問題,除了有點不習慣,仔細想想,本身都只不過是Spring的一種組件而已

  2. 所以如果你用的諸如Hibernate之類的JDBC框架,可以無需再進行多余的類似save操作,這也更好的提現(xiàn)了領域設計的思想,因為這時,這個order就是一個實實在在被我們找出來的實體,對它的改動,自動映射到底層持久化,很自然,也必然。

最更容易引發(fā)槽點的地方,就是order.cancel(),也就是充血模型的精髓,將行為定位到一個實體類上,而不是不加思考地直接扔進OrderService里。

業(yè)界一直有一種非?!懊烂睢钡卣f法,曾經(jīng)我一度非常向往,就是“讓代碼成詩”。 換句話說,就是既然追求可讀性,那么我們要盡可能的讓代碼天然具有一種“主謂賓”的感覺,就拿上面“取消訂單”做比方,我們是否會覺得:

訂單好端端的在那里放著,它自己又不能對自己做什么,自然應該“別人”對他進行了操作:

OrderService.cancel(orderId);
  某某某      取消了 這個訂單

Perfect! 這樣讀起來,才非常通順,可讀性才更好!

我曾經(jīng)也是這種風格死忠,而Spring廣為流傳的無狀態(tài)架構模式也將這種風格發(fā)揚光大。 只是我現(xiàn)在,在經(jīng)歷了越來越多復雜業(yè)務,長事務的開發(fā)需求后,越來越覺得,這個還有有些硬傷

  • 如果一定要讀得通暢,更應該是someOperator.cancel(orderId)即某個操作人取消了訂單,而不是OrderService,誰都知道OrderService就是一個無狀態(tài)的代碼大集合,一個冰冷的代碼而已。但顯然someOperator.cancel(orderId)這種做法也是更加不可能實現(xiàn)的,原因就不用過多解釋了。

  • order.cancel(),只有2個部分,{操作目標是誰}.{做了什么事情},清晰明了,言簡意賅。我相信絕大多數(shù)人的閱讀習慣也都是從左往右,那么視線第一下掃到的目標一定是最左邊的執(zhí)行對象,也就是order,那么可以在第一時間明確,這個行為是發(fā)生在誰身上,而如果是orderService.cancel(orderId),無形中,orderService是一個占據(jù)了視線最有力位置的一個巨大的噪點——因為它沒有任何的業(yè)務意義,你要看的,反而是后面的方法和參數(shù),這在閱讀上百行甚至幾百行的復合長業(yè)務的時候,你會很快困頓,迷失方向。

感謝各位的閱讀,以上就是“基于領域分析web設計的架構規(guī)范”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對基于領域分析web設計的架構規(guī)范這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

web
AI