[Skr-Shop]購物車設計之需求分析

skr shop是一羣底層碼農,由於被工作中的項目折磨的精神失常,加之由於程序員的自傲:別人設計的系統都是一坨shit,我的設計纔是宇宙最牛逼,於是乎決定要做一個只設計不編碼的電商設計手冊。

項目地址:https://github.com/skr-shop/manuals

對於一個電商來講,購物車是整個購買流程最重要的一步。因爲電商發展到今天購物車不僅僅只是爲了完成打包下單的功能;也是收藏、對比、促銷提醒、相關推薦的重要展示窗口。如此多的能力我們該如何設計保證購物車的高性能、以及良好的擴展能力來滿足未來的發展呢?

今天開始我們就以一個假定的場景來輸出一個購物車設計:某某電商平臺,是一個多租戶模式(我們前面的諸多設計都是多租戶模式),用戶可以把商品加入到購物車,並切按照商戶緯度來展示、排序。當然購物車也支持常規的各種操作:選擇、刪除、清空、商品失效等。並且有相關的促銷能夠提醒用戶。同時爲了監控、運營,要支撐購物車數據同步到監控、數倉等能力。

本文會從用戶使用的角度以及服務端兩個角度來講解系統的能力。本篇我們的主要目的是說清楚購物車的能力以及一些邏輯。下一篇會進行購物車模型設計以及接口定義。

用戶視角

我們先來定義一下在用戶側用戶操作購物車的功能有哪些?
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hGj3j9Fo-1575961846225)(https://dayutalk.cn/img/user-cart-c.png)]

一個購物車基本的能力基本上都在上圖中,下面我們一一來分解。

操作

我們從用戶的角度來看,購物車對於用戶來說可以添加商品到購物車(加購物車、立即購買都屬於一種添加方式);加入進購物車後,不想要了可以刪除該商品(刪一個、刪多個、清空);想多買可以修改購買數量,發現錢不夠可以減少購買數量;或者發現紅色的比白色更漂亮,可以在購物車方便的進行更換規格;對於一些價格很貴的商品,能夠在購物車添加一些保障服務(其實是綁定的虛擬商品);在要去結算的時候,還會提供選擇能力讓用戶決定哪些商品真的本次要購買。

通過上面的描述我們可以看到這個過程是有其內在聯繫的。這裏說一下關於選中功能,業界有兩種做法,各有優劣,我們來看一下。淘寶的產品選中狀態是保存在客戶端的,並且默認不選中,刷新、重新打開APP狀態會消失;京東、蘇寧這一類是保存在服務端,會記錄用戶選中狀態。針對這兩種情況各有優劣。

客戶端:

  1. 性能,選中/不選中的邏輯直接放在本地做,減少網絡請求
  2. 體驗,多端不能同步,但是購物車相對來說更像是一個收藏夾,每次用戶自己選擇也無可厚非
  3. 計算,價格計算時需要上傳本地選中商品(也可以本地計算)
  4. 實現,主要靠客戶端實現,與服務端無關,研發解耦合

服務端:

  1. 性能,每次操作選中都需要調用服務端,而該操作可能很頻繁,除了網絡損耗,服務端也需要考慮該如何快速找到修改的商品
  2. 體驗,多端同步狀態,記錄歷史狀態
  3. 計算,服務端可獲取數據,請求時無須上傳額外數據
  4. 實現,服務端與客戶端需要商定如何交互,以及返回數據(每次選中會導致價格變化),耦合在一起

個人認爲這兩種方式並無誰具備明顯優勢,完全是一種基於業務模式以及團隊情況來做選擇。我們這裏後續的設計會基於在服務端保存商品選中狀態。

在整個操作邏輯中,有個兩個比較重要的地方單獨說明一下:購買方式與購物車內修改購買屬性

購買方式

主要的購買方式有立即購買、加入購物車、拼團購三種方式。

首先普通的加入購物車沒什麼太多要說的。重點來看下立即購買與拼團。

立即購買在於操作上來說就是選擇商品後直接到了訂單確認頁面,沒有購物車中去結算這一步。但是它的實現卻可以依賴購物車的邏輯來做,我們來看一下使用購物車與不使用購物車實現這個邏輯有什麼差別?

如果使用購物車來實現,也就是用戶點擊立即購買時,商品本質上還是加入到購物車中,但這個購物車卻與原型的購物車不同,因爲該購物車只能加一個商品,並且每次操作都會被覆蓋。在視角效果上也是直接從商品詳情頁面跳轉到訂單確認頁面。來看看這種方式的好處

  1. 與購物車在訂單確認、下單邏輯上一致,內部可以直接通過購物車獲取數據
  2. 需要一個獨立的專門用於一鍵購買的購物車來實現,內存有消耗

另外一種實現方式使用一個新的數據結構,因爲一般來說一鍵購買更簡單,它只需要商品信息、價格信息即可。每次交互均可以根據sku_id來獲取。

  1. 訂單確認、下單邏輯上需要進行改造,每次請求之間要傳遞約定參數
  2. 節省內存,上下交互通過sku_id來保證

我們會採用使用在服務端一鍵購買以獨立的購物車形式來實現。購物車的數據模型一致,保證了後續處理流程上的一致。

對於拼團,他其實分爲兩部分,首先是開團這個動作,當團成立後。我們可以選擇將成團的商品加入普通購物車,同時可以加購其它商品。也可以選擇將成團商品加入一鍵購買的購物車,保證成團商品只能買一個。拼團模式更像是加入購物車的一個前置條件。本質上它對於購物車的設計沒有影響。

購物車內修改購買屬性

這裏主要是指可以在購物車便捷的操作一些需要在spu緯度操作的事情,比如:變更規格(也就是更換sku),以及選擇綁定到spu緯度的服務(保險、延保等)。

我們重點說一下選擇綁定的服務。例如:我們買一個手機,廠家提供了延保、各種其它附加服務,一般情況這種服務都是虛擬商品。但是這有個特殊情況。這些保障服務首先不能單獨購買,其次他是跟主商品的數量息息相關。比如買兩個手機,如果選擇了加購服務,那麼這些服務的數量必須是2,這會是一個聯動關係。

這些保障服務是不能進行單獨購買的,它一定要跟特定的商品捆綁銷售。

服務端在存儲這部分數據時一定需要考慮如何保存這種層級關係,這部分我們後面模型設計的時候大家會看到。

在這裏插入圖片描述

提醒

促銷提醒很簡單,返回的購物車數據,每一個商品應該攜帶當前的促銷信息。這部分重點在於怎麼獲取促銷信息,會在服務端看到。

然後說下購物車數量的提醒,也就是顯示當前購物車商品的數量。一般來說進入到APP就會調用一個接口,獲取用戶的未讀消息數、購物車商品數等。這裏是需要非常高的讀取速度。那麼這種需求該如何滿足呢?

方案一: 我們可以設計一個結構保存了用戶相關的這種提醒信息數量,每次直接讀取這個數據即可。不需要去跟消息服務、購物車服務打交道拿這些數據。

方案二: 在消息、購物車的模型中均設計一個保存總數量的字段,在讀取數據的接口中,通過併發的方式調用這些服務拿到數據後進行聚合,這樣在速度上只取決於最慢的服務。

這裏我們的設計會採用 方案二,因爲這樣在某種程度上效率可以得到保證,同時整個系統的結構數據的一致性更容易得到保障。當然這裏有個細節一定要注意,併發讀取一定要設計超時,不要因爲某個服務讀數問題而導致拖累整個接口的性能。

接下來再來看看促銷,這部分除了提醒,還需要提供對應的入口,讓用戶完成促銷的操作。比如說某個商品有券,那麼可以直接提供入口去領取;可湊單,有入口進入湊單列表並選擇商品等。這部分需要解決的問題是服務端該如何及時從商品緯度拿到這些促銷活動。

從用戶的視角看完了,我們再來站在研發的角度看看服務端有哪些事情要做

研發視角

還是先來看看需求的彙總圖:

在這裏插入圖片描述

存儲

對於存儲,首選肯定是內存存儲,至於要不要落庫,我覺得沒有必要。說下我的理由:

  1. 購物車的數據相對變化非常頻繁,落庫成本比較高,如果異步方式落庫,很難保障一致性
  2. 極端情況,cache奔潰了,僅僅需要用戶重新加入購物車,並且我們可以通過cache的持久化機制來保證數據的恢復

所以對於購物車,我們只會把數據完全保存在內存中。

商品銷售類型發生變化

現在我們來討論 商品銷售類型發生變化 這個問題。這是什麼意思呢?大家想一下:比如我把A商品加入到購物車,但是一直沒有結算。這時運營說針對A商品搞一個活動,拿出10個庫存5折購。那麼問題來了,對於之前購物車中就有該商品的用戶該如何處理?這裏解決的主要問題是:購物車有該商品的用戶不能直接以5折買。幾種方案,我們來看一下:

方案一: 促銷配置後,所有購物車中有該商品的用戶失效或刪除,這個方案首先被pass,操作成本太高,並且用戶體驗差

方案二: 購物車中要區分同一個SKU,不同銷售類型。也就是說在我們的購物車中不是按照SKU的緯度來加商品,而是通過 SKU+售賣類型 來生成一個唯一識別碼。

可以看到 方案二 解決了同一個sku在購物車並存的問題,並且庫存之前互相不影響。不過這裏又有一個問題?商品的售賣類型(或者說這個標記),該怎麼什麼地方設置?好像商品系統可以設計、促銷系統也可以設置。我們的邏輯中會在促銷系統中進行配置。因爲商品屬於基礎邏輯,如果一改就是全局庫存受到影響。活動結束後很難做到自動正常售賣。因此這個標記應該落到活動中進行設置(活動設置時會通過促銷系統獲取該商品之前的活動是否互斥,以確保配置的活動不會互相矛盾)。

依賴系統

購物車系統依賴了非常多的其它系統。

  • 商品系統
  • 庫存系統
  • 促銷系統
  • 結算系統

這些依賴的系統,有的是爲了傳輸數據,有的是爲了獲取數據。我們按照這兩個緯度來看一下。

促銷提醒與計算

服務端要解決的是促銷的提醒與價格計算問題。

現來說計算,針對這部分最佳的方式是,調用結算中心的價格計算。我們來看一下購物車中的價格計算與訂單結算時的價格計算的差異。

首先購物車中計算價格時不知道用戶的地址,這會影響運費的計算;再是不知道用券的情況。那麼其實如果解決了這兩個問題,我們就可以讓價格計算出自同一個邏輯,僅僅是部分入參不同罷了。因此我們這裏計算時可以按照最高運費來計算,同時用券默認在購物車都不使用券。對於促銷問題這裏是可以通過促銷系統確認選中的商品可以享受哪些價格的。因此促銷的價格應該計算在內。

接下來在再來說說如何爲用戶高效的提供促銷的信息。先從我們的配置視野出發。

我們在配置一個促銷活動或者發一張券時,都是將多個商品歸到一個促銷活動或者券的下面。如果按照活動、券的緯度來獲取商品效率相對比較高。

在這裏插入圖片描述

但是在購物車的場景中發生了一個變化。我們是需要從商品緯度獲取到該商品的所有活動信息(全平臺活動、店鋪活動);
那麼購物車中爲了展示這些信息該怎麼做?很常規的一個做法(也確實不少公司是這樣):把所有活動信息取出來,遍歷出所有跟該商品相關的信息。這種做法效率很低,並且無法滿足大規模的應用場景,比如雙十一期間。

因此這裏爲了滿足該需求,促銷系統需要提供一個能力按照商品獲取對應促銷(活動、券)。因此一般來講促銷系統配置的活動不能僅僅是按照活動緯度存儲,同時還需要生成一份商品緯度的促銷信息。

在這裏插入圖片描述

購物車數據分析

對於購物車數據來說,前端會通過埋點記錄加入購物車數據的情況,但是前端埋點一般是記錄觸發了某個前端操作,但是並不知道該操作是否成功與否。以及無法及時瞭解當前整體購物車的數據情況。

爲了讓運營團隊更完整的瞭解購物車當前情況,我們通過後端打本地日誌,然後通過日誌收集的方式將日誌同步給數據、監控等服務。

失效與排序

還有兩個小部分沒有講到,一是商品該如何失效,比如:庫存沒有了、下架了;二是購物車中的商品是多個店鋪的,排序的策略是什麼?

由於本文我們還只是討論需求,不涉及具體的模型設計,因此只是介紹方案。首先是商品失效,這很像一個軟刪除操作,一旦設置,用戶側看到的商品將是無法進行結算的,只能進行刪除操作。

對於排序我們會採用的設計是:根據某個店鋪在購物車中最後發生操作的時間,最新的操作肯定在最上面。

結尾

通過上面我們基本上搞清楚了購物車設計中我們要做什麼,依賴的系統要提供什麼能力。下篇開始進入數據模型的設計、前後端接口設計。

如果你對購物車上面的需求還有哪些補充,歡迎留言。我們一起來完善。

項目地址:https://github.com/skr-shop/manuals

發佈了113 篇原創文章 · 獲贊 153 · 訪問量 62萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章