拆解零售商品架構的底層邏輯

一、引言

 

在當今數字化時代,零售業正迅速發展,消費者的購物行爲和期望發生了巨大的變化。爲了滿足不斷增長的需求,零售企業必須構建高度靈活、穩健可靠的商品系統。

 

本文將深入探討零售商品系統的底層邏輯,聚焦領域驅動設計(DDD)和複雜業務系統架構經驗,揭示其在零售業務中的應用和價值。

 

二、面臨的挑戰

 

商品系統幾乎貫穿了整個業務流程,比如:收銀機的掃碼加購、下單、商品詳情頁、小程序加購、營銷活動、進銷存、供應鏈、售後、履約等,各個業務環節都以商品爲載體。由於商品系統的這種基礎性和核心性,它所面臨的挑戰也愈發顯得複雜而嚴峻。

 

挑戰一:廣泛行業需求的融合

 

零售領域擁有多元化的行業,每個行業對商品管理的需求都存在顯著差異。從超市便利店到酒店教培,再到生鮮行業,不同行業的商品屬性截然不同。

 

挑戰二:複雜業務鏈路的支撐

 

商品系統作爲零售業務的中樞,需要支持從採購到銷售再到退貨的各個環節。這涉及到供應鏈、訂單、物流、結算、售後等多個業務域的協同運作。

 

挑戰三:面向B端與C端的雙重需求

 

商品系統不僅要爲商家提供強大的商品管理工具,還需要爲消費者提供良好的商品展示和購物體驗。B端需求關注商家的批量操作、庫存管理等,而C端需求則關注用戶的瀏覽、購買、支付等。如何在系統中同時滿足兩者的需求,保證系統的易用性和擴展性。

 

面對泛行業需求的融合、複雜業務鏈路的支撐以及B端與C端雙重需求,業務架構師需要有深刻的洞察力,結合架構的“道”與“術”,在複雜性中找到平衡,構建出穩定、靈活零售商品系統,爲業務持續迭代提供有力支持。

 

三、架構“道”與“術”

 

架構不僅涉及技術層面的決策,還關乎對業務需求的深刻理解以及對系統演化的預判,它決定了系統的整體設計和演化方向。

 

1. 架構的“道”

 

架構的“道”強調系統的整體規劃、設計和演化策略。它包括以下核心要素:

 

  • 深刻的業務理解。在設計架構之前,要深刻理解業務需求,通過領域驅動設計(DDD)來捕捉業務的核心概念和領域模型,保證架構與業務的緊密契合。

  • 可演化與擴展性。架構需要具備演化的能力,以適應不斷變化的業務需求和技術進步。同時,它還應該有足夠的擴展性,以應對未來可能出現的挑戰和機會。

  • 業務驅動的設計。架構應該以業務爲核心,將業務邏輯和技術方案相結合。通過領域建模,將業務的核心概念映射到系統架構中,實現領域模型的高度一致性。

 

2. 架構的“術”

 

架構的“術”關注具體的技術選型、設計和實現。它包括以下關鍵方面:

 

  • 分層與模塊化。將系統劃分爲不同的層次和模塊,每個層次和模塊負責特定的功能。分層和模塊化有助於職責的清晰劃分,減少代碼的重複性。

  • 設計原則與模式。技術設計時,需要考慮一系列設計原則和設計模式,如單一職責原則、開閉原則、依賴倒置等,構建松耦合、高擴展的系統。

  • 技術選型。選擇合適的技術棧是方案中的重要決策之一。技術棧涉及編程語言、中間件框架、數據庫等,它們直接影響到系統的性能、可擴展性和開發效率。

 

四、零售商品架構

 

1. “分治” 策略

 

零售商品關聯了非常多的業務模塊,比如:商品SPU、規格SKU、前臺類目、後臺類目、品牌、庫存、標品、屬性和模板等,不同業務模塊在橫向存在千絲萬縷的關係。同時隨着用戶規模擴大業務拓展,各個業務模塊垂直化建設也會加大,進一步加劇系統複雜度。

 

爲了解決這一複雜性,我們首先採取“分而治之”,引入限界上下文,將大商品域進一步拆分爲主商品、庫存、類目、屬性等一些列自治的領域,縮小業務域範圍,並按職責分爲核心域、通用域、支撐域,每個領域專注於處理自己本域的特性問題,弱化橫向之間耦合,降低了複雜度。

 

圖片

 

領域內早期只有單一的普通商品,業務邏輯比較簡單。然而,隨着業務不斷迭代,商品湧現很多新玩法,如組合商品、臨時商品、虛擬商品、預售商品等,每一種商品類型都表現出獨特的規則和特性。

 

如果不同類型商品獨立構建,像一個個孤立的煙囪,勢必會導致重複建設問題。一旦修改通用邏輯,不得不在多處進行重複性改造,增加了維護成本。另一方面,將不同類型商品集中於一個主流程中,雖然可以減少重複建設,但這也可能出現大量的 if、else邏輯以處理差異化邏輯,影響代碼整潔性。

 

爲了解決這一問題,領域內我們採用 分解+編排的策略,結合主流設計模式,以構建高效、可維護的系統。

 

  • 分解:將複雜的業務邏輯分解爲更小組件,使每個組件只關注一個特定功能。這種分解符合軟件設計的單一職責,同時降低單個組件的複雜度。

  • 編排:採用責任鏈選擇需要的業務組件進行串聯,通過組裝方式實現一個業務流程,保證了軟件的開閉原則,同時也實現同一個組件在不同的業務流程複用。

 

如何在領域內分解和編排?有什麼工具方法論可以開箱即用?

 

這裏推薦使用 “矩陣思維”,梳理每一個業務流程,自上而下分解將一個大流程拆解爲若干個小業務組件。以商品創建流程爲例,橫向表示業務動作,縱向表示業務場景,中間表示詳細的業務流程。拆解後得到下面表格所示的矩陣。

 

圖片

 

通過矩陣工具將橫、縱兩個維度的複雜度清晰展現出來,方便我們直觀發現不同流程之間的共性和特性,接下來就要考慮組件編排工作。

 

圖片

 

將標準化業務邏輯封裝成一個個獨立的業務組件,在應用層通過組件編排的方式組裝業務流程。每個業務動作都有自己獨享的編排流程,它輕量化易修改,承載業務功能的落地實現。

 

舉個例子,當我們接到業務方需求,開發一種新的組合商品,創建商品環節只需要增加兩個業務組件:檢查組合商品前置條件、記錄組合明細,然後複用其他組件快速編排出一個新接口。整個過程對其他業務沒有影響,符合軟件的開閉原則,並且大大降低測試工作量。

 

2. “抽象” 領域模型

 

新零售服務的行業非常多,不同行業的商品屬性差異非常大,下圖示例是商超便利店與教育培訓的商品。面對泛行業的“差異性”、“不確定性”特點,我們該如何架構系統?

 

如果每個行業單獨創建一套存儲結構,看似滿足了需求但成本巨大,而且靈活性也不高。

 

如果將所有行業的數據放在一個地方存儲,那差異化的數據結構如何滿足,而且很多字段還涉及到校驗規則或作爲搜索條件。不僅要能寫進去,還要讀出來。

 

圖片

 

軟件架構中解決複雜業務的另一法寶就是將業務需求抽象成領域模型,那什麼是領域模型,先來看下維基百科給出的定義

 

領域模型(Domain Model)記錄了一個系統中的關鍵概念和詞彙表,顯示出了系統中的主要實體之間的關係,並確定了它們的重要的方法和屬性。

 

領域模型是將現實世界的客觀對象抽象爲一種信息結構,並能精確地反映業務領域的本質特徵,這種信息結構不依賴於具體的編程語言,具有很強的獨立性。

 

這樣我們就可以將業務與技術實現分離,所有人的焦點放在領域模型,通過統一領域語言,讓業務專家、研發人員在一個頻道溝通,收集業務核心特徵。下圖是零售商品的領域模型:

 

圖片

 

主商品模型的屬性根據其是否通用,拆分成兩部分,對於相對穩定的數據,如“商品名稱”、“類目”、“條形碼”、“商品類型”、“售賣單位”等放在主商品上。而對於“產地”、“上課時間”等不固定數據抽取到自定義屬性中,並與模板綁定,主商品只綁定一個模板標識號即可。

 

圖片


當商戶創建商品時,根據業務類型找到對應的模板和關聯的自定義屬性,自定義屬性主要包含以下內容:

 

  • component_config:主要是前端渲染頁面使用,如輸入框、下拉列表、單選、多選框等;

  • label:輸入框 左側的字段標題說明;

  • rules:值校驗規則,用於校驗商戶輸入是否滿足要求。比如:“字段是否必填”、“輸入文本長度”、“字段是否只讀”、“字段是否可見”、“正則校驗”等。

 

用戶填寫完商品頁面的各種輸入信息,並且通過所有校驗規則,接下會將發佈一條商品,核心字段放在主商品,而對於“重量”、“起售份數”等非核心字段與屬性“field_id”關聯,然後採用泛化集合存儲到模板實體。

 

細心的小夥伴可能發現,這裏的field_id是個重複字段如 保質期(expiration_data),每個商品都有這個字段,如果商品表的數據量非常大,這種冗餘字段會佔用很大空間。針對這個問題,可以借鑑 Protocol Buffers 的設計思想,爲每個屬性分配一個獨立編號,通過字典記錄它們的關聯關係。這樣模板實體中綁定的不再是英文字段而是一個數字編號,空間會成倍的降低。

 

3.DDD 分層架構

 

一個好的系統一定有個好的架構模式,不管在六邊形架構還是Clean Architecture中,似乎更習慣把Domain作爲最底層,而Infrastructure是作爲上層來實現Domain的Repository,將業務複雜度和技術複雜度分離。

 

業務複雜度主要體現在領域模型,通過實體、屬性值、聚合根來呈現業務的本我,然後通過領域服務對實體數據驅動,完成一個生命週期。不管規則如何變化,最終通過模型來承接數據。

 

系統落地主要體現在代碼排兵佈陣,這裏就用到 DDD 分層架構。分層是爲了解決技術複雜度,讓每一層有自己的專屬職責,如:數據轉換、RPC遠程調用、異步消息解耦、緩存性能加速、動態配置中心、定時任務。

 

圖片

 

整個系統分爲四層,每一層都有明確的職責定義:

 

1)接口層:定義接口服務,包括入參、響應結果,對外通過二方包的形式呈現。

 

2)應用層:表述應用和用戶的行爲,對領域服務進行組合和編排,對領域實體中的字段提取並轉換成外部想要的形式。如果寫服務,作爲生產者對外發布消息事件,當然也可以作爲消費者,訂閱外部消息。這裏也是MQ消息和定時任務的觸發入口,所以也稱爲觸發層。

 

3)領域層:用於表達業務概念和業務邏輯,是系統的核心。包含:實體、值對象、聚合根、領域服務、倉儲服務等。

 

  • 實體主要是承載業務的領域模型及關聯關係,以及自身的動作行爲。有字段變量,有方法,也成爲充血模型。

  • 領域服務主要完成領域中跨實體或值對象的操作轉換而封裝的服務,領域服務對同一個實體的一個或多個方法進行封裝組合,對外隱藏領域層的業務邏輯實現,以黑盒形式對外服務。

  • 倉庫服務職責單一,主要負責將領域模型傳給存儲層,持久化存儲。考慮到存儲中間件的多樣化,爲了避免多變性對領域層的干擾影響,這裏只定義接口,接口實現放在基礎設施層。通過依賴倒置保證了領域層的核心地位。

 

4)基礎設施層:爲上層提供基礎技術能力。如MySQL數據庫操作、緩存數據讀和寫、遠程RPC接口防腐層封裝,以及其它中間件的初始化config 等,降低外部資源變化對系統的影響。

 

圖片

 

縱向,我們從技術視角分爲四層,每層有自己的專屬職責。橫向,從業務維度切割爲多個子域,如商品、庫存、類目等。落實到具體代碼,我們通過 package 實現代碼隔離。爲了兼顧領域的內聚性,頂層包按領域劃分,每個分層內部再按模塊職責定義子包。

 

4.數據流轉

 

無論系統的複雜程度如何,其本質都歸結爲數據操作。從本地存儲或遠程接口獲取數據,經過一些列的轉換、加工和組合等來表達業務邏輯。這一流程自上而下經歷多個階段,最終完成數據的持久化存儲,同時自下而上地通過各種轉換和加工,將數據最終展示給用戶。

 

圖片

 

爲了有效限制各個分層數據模型的職責範圍,從而避免交織耦合,我們採取了數據模型分層的策略,將其分爲三個主要類別:DO(數據庫持久對象)、VO(領域模型對象)和DTO(數據傳輸對象)。

 

數據庫持久對象爲 DO,通過 Repository 接口完成 DO 到 VO 的領域模型轉換,然後通過領域服務向上暴露。

 

在這個架構中,數據庫持久對象(DO)承載了與數據庫之間的直接映射關係,通過Repository接口完成 DO 到 VO 的領域模型轉換,然後通過領域服務向上層暴露。在應用層,對領域模型 VO 進行一系列業務邏輯處理,最終轉換爲 數據傳輸對象(DTO),以便與外部世界進行交互。DTO充當着外部和內部數據傳輸的媒介,它不僅可以承載所需數據,還能夠在傳輸過程中進行數據格式的轉換和優化,以適應不同的客戶端需求。

 

通過明確的分層和數據模型職責,我們能夠實現不同層次之間的解耦。這種解耦使得每個層次都可以專注於特定的任務,而不需要過多考慮其他層次的細節,保證系統低耦合特點,擴展性更強。

 

五、結語

 

在零售業的數字化浪潮下,構建高度靈活、穩健可靠的商品系統已成迫切需求。

 

面對業務挑戰,領域驅動設計與分解+編排策略成爲解決問題的關鍵。架構的"道"注重業務理解與業務驅動設計,而"術"關注分層設計和模式運用。從抽象領域模型到DDD分層架構,系統持續演進。這些舉措以數據操作爲核心,聚焦業務與技術,構建穩定、高效的零售商品系統,爲業務發展保駕護航。

 

作者丨智慧經營開發部-宋志朋
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章