文 | Alex、Siam
面对线下收银场景,针对商品收银业务,如何提升商家收银的效率?如何保证即使在弱网或无网条件下商家正常的收银?如何设计大量商品时搜索方案?如何对业务模块进行解耦和各种复杂的业务场景交互?都是在设计零售收银业务时,需要去认真思考的问题。
有赞零售移动团队在业务快速地迭代中,沉淀出商品收银的一套可行方案。
模块化设计
得益于零售移动的组件化框架,对业务线划分为店铺、交易、商品、营销等模块
路由负责页面跳转与组件间通信
私有化商品模块数据,商品模块提供查询接口
离线商品数据
客户端本地存储商品商品,即使在无网时,商家仍可正常收银
提供商品名拼音搜索、扫码枪的商品条码扫码能力
商品收银与营销活动
支持门店商品收银时营销活动的数据组装
支持不同营销活动时门店商品页面数据渲染
硬件支持
扫码枪、电子秤等多种硬件设备支持,提升商品搜索与收银效率
一、模块化设计
最初的零售移动多业务线共用本地数据库,调用时业务方式直接访问数据库 DAO 类查询数据,虽然使用上来说各个业务 Module 无须重新定义 DAO 数据类,但是业务之间耦合反而加重,违背了业务组件化的初衷。因此决定对数据库进行拆库:
按照业务线将数据库进行拆库
业务 Module 统一数据访问的入口
路由调用方法
上图是商品模块进行数据库拆分之后的基本模型。拆分之后:
单个数据库职责更单一,清晰明了,耦合降低
商品模块统一各个业务线访问商品数据的入口。
商品业务或底层数据变更时,其他业务线无须关心数据模型变更
各个业务组件之间数据通过 JSON 或商定好的协议进行数据传递
模块化设计把与业务强耦合的数据封装到业务模块内,调用方无须关心具体的业务细节;同时业务有变更或重构时,只要能够保证接口新旧一致性,上层业务方做到无感知,业务变更影响面减少,代码便于维护,一举两得。
业务模块化解决了业务模块间的耦合问题,那么如何设计商品离线数据同步机制?先思考一个问题:为什么要做商品离线同步?答案很显然:
线下门店与线上网店不同,在弱网或无网条件时,仍需要保证商品收银可用。
本地商品搜索效率上来说要比只依赖与网络接口请求要高效很多
门店收银要涉及到对接硬件的场景,在这些场景下,离线数据也有天然的优势
那么回到问题上如何设计商品离线数据的同步机制?应该至少考虑以下几个要求:
保证尽可能少的数据传输量
同步任务启动时机:网络重连后要进行数据同步等
同步任务尽可能地简单高效,便于维护
服务端数据变更后能够实时同步到客户端
同步数据的一致性与稳定性
二、离线商品同步设计
2.1 全量同步还是增量同步?
从设计复杂角度来说,全量同步是最容易实现的,数据的一致性容易保证。然而随着数据量的增加,每次全量同步消耗的资源和同步时间会越来越多,而且服务端数据变更后都要进行一次全量更新。与增量同步相比缺点比较明显。
相比于全量数据同步,增量同步只在初始时批量拉取服务端的商品数据。在本地已有商品时,通过本地最新的同步时间拉取商品,在数据传输量亦比全量同步更少,降低同步时间与流量消耗。
在选型上零售移动采用后者作为商品离线数据方案,通过同步时间来进行增量更新拉取最新的门店商品数据。
同步任务采用 单任务方式
(即同步时只有一个同步任务在执行)减少多线程带来的并发问题维护成本,数据的一致性得到保证。
基本的同步过程:
移动端读取本地最新同步时间,根据时间请求服务端
服务端下发增量数据
客户端对比本地时间和增量数据的时间,判断是否已拉取最新数据
如果本地已是最新数据,停止同步;否则继续增量拉取数据,重复步骤1
忽略掉各种边界条件和异常状况,一个简化的增量拉取流程可以抽象为下图: