一、背景

vivo游戏中心是一款垂类的应用商店,为用户提供了多元化游戏的下载渠道。随着游戏中心手游品类的丰富,各品类用户的量级也不断增加,不同游戏偏好的用户核心关注点也不同,从预约、测试、首发、更新到维护,不同游戏生命周期节点的运营需要突出的重点不同。

针对上述不同业务场景,运营人员为了服务好广大的vivo游戏用户,需要进行精细化运营,以不同的视觉样式呈现给不同用户。比如,针对独立游戏品类的用户,平台如果提供了活动,攻略等内容的透出,能够促进用户更多的下载和消费。活动、攻略等内容以不同视觉样式呈现,运营需要通过实验的方式来验证效果,以确定最终的投放方案。这些需求都需要重新开发。受限于游戏中心APP较长的发版时间,运营的预期效果往往不佳。

因此,我们希望系统具备以下能力:通过不同视觉样式的抽象与复用,快速灵活的对页面进行布局调整,对不同的人群投放,最终以实验的方式来确定最佳的投放方案。

怎么样才能实现这些系统功能呢?答案就是模块化。下面为大家介绍一下游戏中心的模块化实践。

二、什么是模块化

所谓模块化,其实它是一种模块化的设计思想,即指能针对相同或不同功能、性能、规格的产品,进行功能分析,并设计出一系列的功能模块。

透过模块的多样选择将产品客制化,可以满足市场许多不同的需求。那么游戏中心模块化就是针对游戏中心相同或者不同功能的视觉样式,进行业务场景分析,并设计出一系列的功能模块。通过模块的多样选择,快速灵活的搭建出不同的页面,来满足不同用户的需求。

模块化有三个能力:组件化,配置化和实验化。

大家可以看到,三个功能分别对应了三个概念。组件化对应了组件,配置化对应了页面,实验化对应了方案。它们是包含的关系,即一个方案包含了若干个页面,而一个页面也包含了若干个组件。

模块化之前,游戏中心的首页是由顶部的广告Banner,导航栏,游戏列表和穿插组件构成的。穿插组件即为横向插入在游戏列表中用于运营推广的由视觉样式和数据组成的广告。从穿插组件的定义来看,其实就是组件化的概念,只是当时把组件化和游戏列表做了相应的区分。穿插组件的视觉样式比较单一,只有专题、视频、热词、活动、论坛等。如图1中,小编推荐,热游驿站,抢先推荐是1*4的游戏专题穿插,类似九宫格(八个热搜词)为热词穿插。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(1)

(图1:模块化前)

穿插组件按照一定的规律穿插在游戏列表的任何位置,但是广告banner和导航栏是固定的,整个页面布局混乱,形态固定,不易变更。假如把最顶部的banner挪到小编推荐的下方,只能通过发版解决。将专题右上角的“更多”改成“换一换”,或者将游戏列表中某些游戏改为其内容的介绍,也需要通过发版解决。

模块化之后,利用组件化能力,既可以灵活的调整顺序,也可以动态更改组件的视觉样式,即使是游戏列表,也是可以动态配置。利用多个组件的顺序排列,可以快速搭建出一个页面。

通过ABtest框架和DMP系统,不同的页面,以投放方案的方式,能够快速呈现给对应的人群,进行多版本的运营。图1和2是模块化前后首页推荐的对比图,虽然从大的样式的没有太大的改变,但是模块化之前的样式相对单一,而模块化之后游戏列表中排列了单游戏大图、金刚位、小喇叭、专题、新游预约、下载榜等组件。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(2)

(图2:模块化后)

不同的组件可以满足不同的业务场景。例如单游戏大图组件,辅以推荐,可以快速推广新游和热游,满足了不同用户对不同游戏节点的需求;新游预约组件可以从更多角度满足用户对于单款游戏提前订阅内容或关注其实时动态的需求。

三、怎么实现模块化

从前面的介绍大家可以看到,模块化通过组件化的方式快速搭建页面并将其投放给不同标签的人群,功能强大且配置灵活,为我们省去了不少的开发成本,那么我们的底层是怎么实现的呢?

3.1 模型抽象和统一

根据组件布局,我们可以将组件抽象成两部分:视觉样式和数据;视觉样式可以简单理解为UI样式,即呈现在用户面前的展现形式,我们可以将视觉样式简单概括为模板。

模板定义了当前组件最基础的形式,比如当前组件是滑块的形式,还是固定的形式;模板上还定义了一些可变的样式,即定义了当前模板哪些位置是可以通过配置来完成的,比如模板的长宽高、组合样式(2*2,1*4)、包含列表的个数等,能够动态配置的程度依赖模板的定义。

所谓的数据,按照来源分为推荐数据和人工排期数据。推荐数据来自算法和大数据,而人工排期,则是运营在后台配置的。由于推荐数据背后的逻辑比较复杂,本文只讨论人工排期数据。人工排期是一个四维数据。除了数据本身的“业务性”之外,它是有时效性的,游戏中心的广告位展示都是有时间限制的,比如游戏中心首页顶部banner,今天和昨天展示的是不一样的;其次,它是有“空间性”的,即不同的用户可能看到的数据是不一样的;另外,它是有动作性的,即点击后产生的事件。比如点击某个组件,可以是弹出一个悬浮窗,或者切换到到另外一个页面。

因此,模块化可以简单理解为模板和人工排期的组合。通俗点理解,组件其实像一个类,每个页面上不同的组件即为组件的对象,对象会实例化一些数据和行为。通过组件化的方式,我们不仅解决了端侧和服务端的耦合,同时还实现了组件在不同页面的复用。

排期数据的组成分为三个层次(即素材、推广物料以及排期)。最底层数据当然就是图片,视频,推荐语,评论等,当然游戏信息中也会包含游戏icon,背景图以及简单的视频,但是此处的图片并不是指游戏icon,而是比icon更精致,用来宣传广告的素材图片,这类数据我们统称为素材。由素材组成了上层的推广物料。

什么是推广物料呢?推广物料其实就是基于某种目的,按照一定的形式来展示的内容集合。比如banner,其实就是一张图片加上其背后的关联的内容构成,图片是为了吸引用户点击,目的是为了推广背后关联的内容。推广物料加上时间空间和动作属性就变成了排期。素材,推广物料和排期都进行了统一的抽象。

如下图3,推广物料有Banner、专题、活动、网页等;排期有胶囊banner、游情报,种草机、重磅更新等;如种草机就是网页(内容链接)加上时间组成的;整个结构呈现一个倒金字塔结构。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(3)

(图3)

原先游戏中心每个资源位的排期数据都是放在不同的地方,比如顶部banner排期,网游banner排期都有各自的表来保存。在这样的情况下,数据库表的数量可能会比较多,对统一拓展来说就更加复杂。假如我需要对顶部banner和网游banner都要增加对不同人群(DMP系统)展示不同数据的时候,通常需要在每一张表中都增加一个DMP的字段来表示当前排期需要展示给用户的标签id。

模块化之后,我们将游戏中心所有的资源位都当成一个个模块,也就是都可以看成是排期数据,我们只需要两张表就可以做到排期三维数据的展示:排期数据表以及排期关联的具体素材表。因此我们在设计排期表的时候, 将素材信息(如图4中的material_id和material_type)数据保存在排期表中, 将DMP或者其他统一的信息也保存在排期表中, 这样做的好处就是对所有的排期都能生效统一的流程。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(4)

(图4)

3.2 后台业务流程统一化和可视化

如此复杂的业务流程,肯定少不了后台的配合。素材,推广物料和排期的统一后,我们也将后台的配置流程标准化。

具体的配置流程如图5,6。图5偏向于后台的配置流程,是自下而上的配置。而图6是为了方便大家理解,是自上而下的结构。用户层面展示的是某个具体的方案,方案由若干个页面组成,但是会根据用户的画像具体展示,即配置的页面个数不一定是展示的页面个数。页面由若干个组件组成,组件由模板和数据组成....一层层往下分解,可以整体理解模块化的结构组成。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(5)

(图5)

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(6)

(图6)

模块化之前,配置首页banner排期,需要到首页banner的tab栏下,在全部banner排期里面加入相关的排期,然后在首页banner排期里面挑选全部banner排期里面的数据,而配置其他页面的banner排期呢,也是需要在类似的目录结构中做相关操作,彼此之间的banner是割裂的,无法通用;对于运营来讲,配置工作量也增加了不少。

模块化之后,操作变得非常简单了。在组件层面,通过数据库配置,我们可以将模板的信息事先保存在数据库中。在数据层面,我们把所有的banner数据统一保存在推广物料管理并绑定到排期中,做到复用。在业务组件管理页面中,根据组件应用场景来选择模板,之后配置对应的排期数据。

如图7,当前重磅更新场景关联的是人工排期(如果关联的是推荐,则是推荐对应的code),配置好样式后整个业务组件也就配置完成了。然后在页面管理中将你想要配置的组件添加到某个页面中,设置好对应的DMP。配置好组件后,在后台页面上可以滚动进行整体页面效果预览。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(7)

(图7)

如图8。最后可以将页面复用到不同的投放方案中,运营后台通过审核流和上线点检后,最终显示在用户界面端。当前配置流程自下而上,逻辑清晰,符合运营的配置习惯。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(8)

(图8)

3.3 前端业务流程抽象与统一

目前,游戏中心首页和新游专区改造成了模块化页面。首页是游戏中心非常重要的分发渠道,模块化要求页面形式多种多样,同时假如模块化改造不被用户认可的时候也要能够动态回退。

因此首页模块化页面会有三种类型:

所谓纯模块化页面,即页面中的所有元素都是由组件化数据构成。所谓穿插模块化页面,其页面结构为按照一定规律在游戏列表中穿插了若干个组件,和模块化之前的页面组织结构是一模一样的,只是后台的实现方式不一样。

穿插模块化页面中的列表还有两种不同的形式,分为游戏列表和混合数据流列表。穿插页面可以在一个屏幕中最大效率的展示游戏。

最后的H5模块化页面,可以认为由H5组件所构成的页面,由我司的悟空建站提供页面。通过多层试验框架和DMP获取不同方案以及不同页面的流程不在此处赘述。这里我们讲一讲整个流程中最为复杂的穿插页面流程,以及我们怎么在如此复杂的流程中抽象和设计。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(9)

(图9)

3.3.1 流程统一

从上图(大家无需过分关注流程图里面各个步骤的业务逻辑,流程图只是为了展示原来流程的复杂度)我们可以看出来,用户请求开始,需要经过N个步骤。这么冗长的步骤,如果写在一个service,那么就会造成逻辑混乱,维护性不高和扩展性差的效果,因此我们可以分而治之。图9中,我们用不同的颜色来区分步骤,可以做一个简单的流程归纳。

归纳后的流程如下图所示。我们可以把提交异步线程池进行归纳,可以理解为获取组件列表和混合数据列表为两个步骤。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(10)

(图10)

我们再进行归纳和抽象后,整个模块化的页面获取流程就可以简化为四个步骤:初始化阶段、获取组件列表阶段、构建阶段和合并阶段,如图;

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(11)

(图11)

在《金字塔原理》一书中曾说过,读者在阅读文章的时候,必须阅读理解每一句话,并且寻找每句话之间的联系,前前后后反复思考。如果你的文章结构呈现金字塔形,文章的思路自金字塔顶部开始逐渐向下展开,那么读者肯定会觉得你的文章比较容易读懂。这一现象体现了人类思维的基本规律,那么阅读代码其实也是一样的逻辑。好的代码即是一段业务逻辑的注释,通过阅读代码能够大概判断主要的业务流程。在构建阶段, 可以通过组合不同的策略来获取不同的排期数据。策略和组件解耦,当新增策略的时候,无需改动原有的业务逻辑。此处不同的策略也可以采用工厂模式的方法来获取。

首页的组件展示逻辑是比较复杂的,尤其对于穿插模块化页面。正如前文所述,穿插页面由游戏列表和业务组件构成,即在一个游戏列表中,穿插了各个业务组件。数据列表如果是游戏数据列表, 那么每个游戏都是按照一定的比例来排列的,且需要和组件中推广物料的底层数据是游戏的去重。比如游戏按照网游,单机和独立游戏的比例来展示,假如上一个组件展示过当前游戏,那么这个游戏需要被过滤,且补位游戏也是有一个逻辑,比如网游被过滤了,那么取补位游戏列表中的游戏,其次用网游来补,再次用下面的游戏顶上来。去重逻辑包含两种,一种是能被之前的游戏过滤,也能过滤下面的游戏;另外一种则只能去重下面的游戏,不会被上面的游戏去重。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(12)

(图12)

在获取业务组件中排期数据(如上图,其中也包含了游戏信息)的时候,还会有获取ABTest信息(不同的用户展示不同的游戏信息),游戏黑白名单过滤,已安装过滤,已曝光过滤,额外信息处理,组件数据组装等过程。每一个排期数据获取都会用不同的Handler来处理。每一个Handler都有自己的处理逻辑,针对如此多的排期以及他们的扩展,如果没有一套处理的统一逻辑,那么简直是灾难。新人在开发新组件中排期数据的时候,可能会遗漏非常多的细节。另外,推广物料之间其实是有一些通用逻辑,如果不将这些逻辑沉淀到领域模型中,逻辑无法复用,将会散落在各个Handler中,我们以下图橙色的步骤来详细说明。

3.3.2 推广物料的流程统一化

一方面,我们将获取并处理推广物料的流程统一化。如下图所示流程中,其实基本上就包含了所有推广物料需要处理的步骤逻辑(不重要的步骤已忽略)。统一之后,我们可以将一些通用的逻辑下沉,形成统一的方法调用。比如我们可以根据人工排期,推荐排期等,采用工厂方法的设计模式来屏蔽获取推广物料的逻辑。当然我们为了提升性能,对于人工排期数据,利用统一缓存的方式,通用场景code来获取;接着利用不同过滤策略来过滤掉进入黑灰名单的游戏或者内容。处理完额外信息之后再用列表的数据将组件中重复的数据给去除。

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(13)

(图13)

3.3.3 模型的逻辑抽象与沉淀

另一方面,我们将统一处理组件和推广物料的逻辑沉淀到对应的领域模型中,如图;

如何弄个小游戏框架(如何拼出一个页面-游戏中心模块化实践)(14)

(图14)

整个过滤重复数据的流程都是针对组件进行的,那么在组件层面,会有大量的重复逻辑,比如每个组件需要在最后返回的数据个数处理上,不同的组件返回的个数是不一样的,那么这部分逻辑写在组件这个领域模型中会更加妥当。比如已曝光和已安装处理,这个逻辑就可以放在组件层面来处理, 当然放置在Handler层处理也是没有问题的。在推广物料层面,也有一些通用的逻辑,比如1*4个游戏组成的专题和2*2个游戏组成的专题,他们背后都有一套接入推荐系统并兜底的逻辑,也可以沉淀在专题这个领域模型来处理。

四、写在最后

当前,很多业务开发的同学,尤其在熟悉了业务之后,通常会陷入一个误区:做业务的基本上就是CRUD,没有什么技术含量。但是在开发的过程中,往往又缺乏相应的思考,导致重复开发。那么如何才能让业务开发变得更有吸引力和技术含量呢?

游戏中心模块化改造过程中,利用组件的抽象和复用,提升了组件化,配置化和实验化能力,快速的支撑了业务需求,同时通过统一标准流程和利用领域模型知识不断的完善业务代码,提升了代码的维护性和可扩展性。随着业务的不断发展,即使现在非常合理的架构也会变得臃肿,难以扩展,但是如何做好业务的方法论确是不变的。因此做业务开发同学,应该多思考怎么把业务做深做通用,提升快速实现业务价值的能力。

作者:vivo互联网服务器团队—Chen Wenyang

,