有赞移动端商品模块的架构演变之路

商品作为电商SaaS业务中的核心模块,提供了最基础的功能,用户从进入商家主页开始预览、查看商详、到下单完成交易,都离不开商品这个最小单元。商品不仅需要提供最基础最通用的功能,也需要根据业务方的需求能够快速并且动态扩展自己的能力来满足不同类型商家日益变化的需求。

网店商品则主要针对线上店铺,提供在线购买商品场景下所需要的商品数据能力。网店商品SDK是有赞App中的网店商品业务模块,目前支持微商城、零售。本文主要介绍了有赞App中是如何沉淀网店商品SDK的以及一些思考。

为什么要做

为什么要做网店商品SDK?我们看下面这张图:

图1

首先,商品业务模块包含了商品管理、商品编辑、分组管理这三大模块。

图中左侧展示的是零售App中商品管理和商品编辑页面,右侧是微商城App中的商品管理和商品编辑。经过对比可以发现功能是极为相似的,之前是有两个团队维护,存在以下问题:

  • 需求的重复开发与不一致性

    由于有两个团队,因此每一个需求都会经过不同团队的产品、设计、视觉、开发、测试,导致了资源的重复投入,虽然是同一个功能但最后在不同业务落地也会有一定的差异,无法保持功能统一。

  • 交互视觉不规范

    有赞目前已沉淀一套基于SaaS产品的设计体系,内部也沉淀了非常多的UI标准组件,而由于两边的历史原因一直基于老的业务迭代开发导致无法使用最新的视觉交互。

  • 商品中心对接业务方多,沟通协调耗时

    商品中心是提供商品基础服务的后端团队,需要对接微商城、零售、美业、教育等多个业务方,每次需求沟通协调耗时,导致产品功能迭代慢,跟不上业务的步伐。

  • 代码可维护性差、快速支持能力差

    基于历史包袱商品编辑页的代码可维护性差,每增加一个配置项都增加不少工作量导致迭代周期长,无法快速响应产品的需求。

基于这些痛点,我们孵化出了一个技术改造项目,即零售网店商品和微商城商品的合并项目,目标是最终沉淀一个通用的网店商品SDK,支持多个业务方,达到收拢需求入口,统一交互体验,提升开发效率,加快产品功能迭代目的。

业务梳理

有赞微商城是面向全行业的移动电商解决方案,通过完整的在线开店、客户管理、营销推广和经营分析工具。其商品业务模块是为线上交易提供更多的能力,他的销售渠道是线上商城。

有赞零售是一款面向线下零售门店的全渠道经营软件,为门店商家提供商品、会员、场景互通的新零售解决方案。其商品业务模块分为商品库、门店商品和网店商品这三部分。其中门店商品是为线下门店收银提供更多的能力,他的销售渠道是买家到店通过收银机进行结算,商品库则是管理门店和网店两种渠道商品的商品池,他能够统一设置商品信息和发布渠道,能够决定发布到哪些门店或网店。

了解了他们的差异之后,我们再来梳理下商品支持的能力,如下图:

商品作为基础服务,目前支持多个店铺类型,覆盖实物商品、虚拟商品、电子卡券、分销商品、海淘商品、蛋糕烘焙、生鲜果蔬、酒店商品、预售商品、餐饮商品等多种类型,不同店铺类型、不同商品类型有各自不同的配置。

其中,业务标识与通用能力是一对多的关系,每一个业务标识对应一套商品的通用能力的配置。不同业务标识可能包含相同的能力标。这样就可以达到每增加一种业务标识,都可以通过从现有的能力标中选择、组合来快速支持,目前App中的商品模块并不支持这样的能力,所以这也是在这次改造中需要达成的目标之一。

技术梳理

在做网店商品SDK之前,可以先了解下App端的架构设计:

主要分为了应用层、通用业务、基础库三层:

应用层,包含了模块化之后的业务组件,这些业务组件彼此独立,没有直接依赖,仅依赖业务common,但应用层的业务组件是无法做到跨App复用的。

基础库,这一层是跨App复用的基础功能组件,与业务无关。我们在很早的时候大概2015年就开始做基础库了,在业务开发过程中不断的会有基础库沉淀下来,以至于我们在做模块化的时候已经有了很好的基础。

通用业务,包含的是相对独立、功能更加通用的跨App复用的业务组件。网店商品原来是在应用层中,现在我们将他下沉到通用业务层,总结一下在这个过程中遇到的几点问题:

1. 模块化

关于模块化,我们目前接入的是自研的模块化中间件,通过协议(接口)+ 路由的方式来跨模块通信,应用层的业务组件都是通过这种方式来互相访问的,每个模块的接口和路由都有单独的类去定义且对外只能通过这个类去访问,这个文件我称他为 moduleService ,因此在将商品模块从应用层下沉到通用业务层的过程中,只需将其模块实现和 moduleService 拿出来即可。

但是还有一点是应用层的组件还依赖了业务common,因此还需要解决这个依赖问题,在这里只能一步步去梳理具体依赖的什么内容,再根据这些依赖去拆分,部分可以下沉到基础库,部分带到网店商品SDK中去。

更多关于模块化相关的内容,iOS可以参考 有赞移动 iOS 组件化(模块化)架构设计实践,Android可以参考 有赞微商城-Android组件化方案

2. 向上数据依赖

既然是业务模块,一般都会依赖一些业务数据,例如登录、帐号、店铺等信息,在这之前会通过跨业务模块获取或者通过业务common获取全局存储的一些信息,但是现在下沉到通用业务层了,不能再向上依赖应用层业务和common了,因此这部分数据的获取需要换一种方式。

第一种方式是在初始化的时候或者适当时机传入数据,基础库一般会以这种方式获取接入方的数据。但是业务数据变化的时机、入口都不确定,那就需要业务方在每个有可能变化的地方都需要同步更新信息给SDK,因此这种方式就不太适合。

另一种方式就是通过代理(接口)的方式,让业务方自己去实现,我们这里采用这种方式,通过自研的模块化中间件去实现,SDK定义一套接口,例如店铺信息、账号信息,业务方自己去实现即可。iOS 模块化中间件已开源,参考 Bifrost,下面以iOS端网店商品SDK实现为例:

2.1 SDK定义一套接口

@protocol XXInterface <NSObject>
@required
- (XXShopInfo)getXXShopInfo;
@optional
- (XXAdminInfo)getXXAdminInfo
@end

2.2 业务方(App)实现

#import <Bifrost/Bifrost.h>
#import <XXSDK/XXInterface.h> //需要依赖SDK中的接口定义
#import "AppCommonUtil.h" //需要依赖App应用层的存储店铺、登录等信息的类
@interface AppXXInterfaceImp<XXInterface>
@end
@implementation
- (void)setup {
      //在合适的时机注册实现
      [Bifrost registerService:XXInterface withModule:self];
}
- (XXShopInfo)getXXShopInfo {
  //...
  return [[AppCommonUtil getShopInfo] convertToXXShopInfoModel];
}
//...
@end

2.3 SDK调用

#import <Bifrost/Bifrost.h>
@interface XXSomeClass
@end
@implementation
- (void)someMethod {
  //通过模块化中间件获取依赖的数据
    [[Bifrost moduleByService:XXInterface].getXXShopInfo];
}
@end

以上这两点,就组成了SDK对外需要提供的两个类,一个是 moduleService ,是SDK定义的一套对外提供的服务,业务方通过 Bifrost 访问 moduleService ,另一个是 interface, 是SDK定义的一套需要业务方实现的接口来提供必须的数据,也是通过同样的方式访问。除此之外的代码应该都是SDK内部的实现代码,外部不应该直接调用。

3. 设计规范

关于设计规范,在产品初期,视觉、交互是没有像现在这么规范的,通常都是一个需求有自己的一个设计风格,经常导致开发重复的风格多样的组件,这样的UI组件也无法下沉到基础库,因为他不规范、不通用。那么在下沉SDK的时候会将这些不规范组件也带走,导致了一个UI组件会有两份,一份在应用层,一份在通用业务层,而且如果其他通用业务组件也用到的话会共存三份,这个问题之前没有暴露出来是因为以前还没有通用业务层。

从去年开始,我们体验设计团队针对移动端开始设计规范、标准化的组件,至今我们内部也沉淀了很多移动端的UI标准组件并且在有序的进行替换和迭代,一方面节约了我们很多重复开发的成本,一方面也给我们的App带来了体验的优化和提升。更多关于UI标准化的内容可以阅读 聊聊UI标准化

4. 移动网关

首先简单介绍下移动网关是什么,他其实是一个标准的JAVA后端应用,只不过不是由后端团队维护开发,而是由我们移动团队来负责的。

App端作为直接面向用户的端,接口里的内容往往不是仅仅由一个提供方提供的,例如订单列表的接口中同时会有订单、买家、商品的信息,而在实际场景中,用户、订单、商品往往是由不同的部门负责的,这样的话给app端提供的接口的维护归属就有了分歧,任何一个改动都需要通知各方协调,当有线上问题出现时查询问题原因也需要大家共同去查,会浪费很多人力,如果各方只提供自己相关的数据,由app端自己去组合数据提供给app端,那么责任划分和查询问题就会轻松得多。

另外,这也拓展了我们移动团队的技术栈,能够学习到更多的后端知识,有利于双方之间的沟通。关于移动网关的更多内容可以阅读 移动开发者的后端开发入门体验

那这跟我们的这次项目有什么关系呢?因为我们目前只有微商城App走的是移动网关,零售App仍走的是零售的后端服务,也就是下图这样的:

如果网店商品SDK下沉到了通用业务层,就不应该去依赖零售相关的后端服务,而是通过移动网关依赖电商商品服务,因此在这次项目中,我们会将合并部分相关的接口全部迁移到移动网关,这样的话就能统一调用链了。

总结

  1. 产出了通用业务组件网店商品SDK,可支持多业务方接入使用,无需再重复开发相关业务。
  2. 统一了原来零售和微商城两端网店商品的功能,替换了UI标准组件,使之符合有赞最新的SaaS设计体系,提升商家用户体验。
  3. 由一个团队来维护网店商品相关功能,快速响应产品需求功能迭代,提升开发效率。

至此,我们完成了网店商品SDK的第一期改造,也给后续更多的通用业务提供了实践总结经验。后续规划是会从中沉淀一些组件以及商品编辑页考虑可动态配置来快速支持商品类型的扩展。希望这篇文章能给在做相同事情的开发者提供一些参考。

欢迎关注我们的公众号