1
背景
笔者入职微保两年以来,正是业务快速拓展的时期。为了尽快能上线各种似同非同的保险产品,我们设计了一个通用的保险产品框架,通过配置来完成绝大部分保险产品上架,前后尝试过不少配置方案,也踩过不少因配置不当而引起的坑。
产品管理系统(PMS)
为了能够方便的配置通用框架的产品详情页以及保险文档,我们开发了PMS系统。这个系统专门用来配置各保险产品的展示素材、管理保险产品相关的文档以及文案。
PMS是定制化的开发模式,前端页面需要什么配置,就在PMS上开发相应的表单。这种完全定制化的开发模式,虽然十分贴近业务,但是无形之中也增加了开发同学的工作量,每当产品详情页或者文档页有新的特性都需要耗费人力去开发表单,以及后续的自测上线,都需要占用开发同学的时间。从长远看来,这并不是一种良好的、可发展的配置开发模式。
JSON配置
在开发一些小型活动页面时,经常会为一些无处安放的零散配置项发愁,所以为了能够方便的配置小程序内的小型活动页面,我们采用过将JSON文件上传到CDN的方案。
如下图,是一个活动页面的外露icon控制,进入页面之后我们将会拉取相应的json配置,然后进行前端页面的渲染。
这种做法虽然开发时很省事,但是日后维护时可能就没那么开心了,既没有版本控制,也没有操作权限控制,且无法监控配置出错的情况,甚至可能会出现CDN缓存无法刷新的尴尬情况。
其他配置
除了上述的方案,我们还使用过中心内的其他系统进行配置,这样的后果就是配置零散分布在各个配置系统中,想完整的配置好一个新产品需要打开多个不同的配置系统才能完成,且这种零碎化的配置很容易造成配置漏发或错发。
尽管这些配置系统的界面都近乎一致,但是配置表单的交互却各不相同,我们很难用同一套操作交互来操作每一个系统,这也降低了配置的效率。
渐渐的,配置数量、配置系统都已经开始野蛮生长,整个系统随着时间的推移,会变得越来越混乱,就如物理学中的熵增一般,如果不及时的对系统进行干预,它必然会走失控甚至消亡。
蓦然回首
上面提及的配置方案基本可以归类为两种类型:开发友好型以及使用友好型。
以PMS系统为首的各种配置系统,都是属于使用友好型的配置方案,它们都提供了配置界面甚至还提供了配置预览界面,但是对开发人员来说这就不太友好了,无论是业务的改动还是数据结构的变更,都需要投入本就稀缺的人力去开发。
以JSON配置为首的便捷配置方案,则是开发友好型的方案,它几乎没有任何开发成本,写一个JSON上传到CDN就可以使用了,可以将每个JSON都看作一个微型的配置系统。这样开发人员很轻松,但是配置方就有苦难言了,特别是不熟悉JSON的产品人员,每次改动JSON配置都如履薄冰,每改一个符号都得小心翼翼,因为稍不小心就真的会影响线上的业务。
这么看来,我们使用过的方案可以说是两个极端,我们是否可以取其中间呢,就如同我们常说的中庸,在配置上我们能否取二者之长走出一条中庸之道呢?这就是我们统一配置平台上线之前的历程。
2
统一配置平台V1.0
在1.0版本中,我们确定了平台的核心理念,也是平台的提供给用户最核心的能力 – 可视化的配置表单。
可视化的配置表单
如上图,如果我们提供一个文本框,在文本框里面输入JSON,这算是可视化的表单么?如果业务要求的是接受一个JSON串,这样也可以算可视化的表单。
但是在统一配置平台对配置的理解中,这还不是一个完善的可视化表单,我们认为JSON内的每个字段都是可以演化成表单组件的,如下图。
例如:一个字符串类型的数据,我们可以通过一个普通的输入框进行输入,一个图片链接,我们可以提供图片上传组件,直接上传并返回字符串链接。我们认为这样的才是符合统一配置平台理念的可视化配置表单。
如何实现表单的可视化?
与传统配置系统的表单组件拖动组成表单不同,我们的表单组件是通过一个proto文件解析而来的。大家可能会有这么一个疑问,为什么是proto呢?
我们可以先从一个情景切入,相信大家看完之后,也会对我们的选择有所理解。假如,有一个前端页面需要这么一个配置:根据请求的来源(H5 or 小程序)展示不同的保司介绍以及品牌露出。我们会怎么去规划这个配置以及配置的界面呢?
规划配置,不外乎这两个方向:数据类型、配置界面。
数据类型,根据业务需求我们大概可以确立以下数据结构:
既然我们已经可以规划出所需的字段了,那么是不是通过一种规范的方式使其成为一种数据结构协议呢?当然可以,我们为每个字段都添加了一个描述类型的字段。
数据类型的描述已经基本完成了,我们能否在其中将配置的界面也描述出来呢?
当然也是可以的,例如companyCode字段,它应该是字符串,那么我们可以为其分配一个输入框组件;而introImgURL字段,虽然最终需要的是字符串,但它应该是一个图片链接,我们自然可以为其分配一个图片上传组件。这么一来,也就得出了下面的配置描述。
至此,已经完成了一个完整的配置描述,并且我们一开始也是这么实现的,但是我们始终觉得这样的配置太过繁琐,并且不够直观。如果让开发同学直接这么定义表单,也并没有想象中的那么方便。
于是我们着手对其进行优化,如果能在一行内完成字段类型、字段名的配置,可以让整个配置直观、简洁不少。顺着这个优化的思路,我们想到了使用proto。
proto作为一个高效、通用的网络通信和数据交换协议,在数据结构的描述上有天然的优势,并且公司内部接入的后端服务可以直接使用定义好的proto进行开发,前端开发人员也可以通过proto提前确定数据结构,进行数据mock。这些优势,促使着我们探索放弃json拥抱proto的可能性。
如上述proto代码,之前通过json描述的数据类型已经可以完美的在proto中复刻,并且更加简洁易懂,但是表单界面的描述该怎么办呢?
这里我们想到的是YAML与proto注释的结合。通过YAML的描述,我们可以为每个字段解析出一套属于它的表单界面(组件)以及表单特性(是否必填、是否有默认值等)。最终实现下图的表单生成流:
开发到这一阶段,我们已经可以做到不进行任何逻辑开发,仅靠一份proto配置就生成一套完整的配置表单。
这也就是我们上面提及的,在开发友好和使用友好中,我们期望各取二者所长:开发人员可以尽量少的关注配置的界面开发,专注配置本身的结构规划;而使用人员则可以通过交互良好的表单组件来修改配置内容,不需要付出额外的学习成本。
但是,这又引申出另一个问题:这种开发模式所输出的表单,岂不是只有开发同学才能进行配置项的修改了吗?
是的,我们认为一个健壮的配置确实是需要开发同学进行编辑。一般,我们在需求开发前就会对整个数据结构有个相对完善的预设,例如需要什么类型的字段、需要怎样的数据结构甚至是否需要这个字段,这些都应该是开发同学比较擅长的。
以上,是统一配置平台第一版的概况,核心已经明确并且也初步实现出来了,随着大家对初版平台的使用深入,我们收集了不少反馈,并以此为契机我们将平台进程推到了第二阶段,通过对搜集来的反馈进行细致分析,并且结合对平台的后续展望,我们认为需要对系统的设计进行重构。为了让系统能够更灵活的面对各种配置需求,我们还需要赋予其应用以及菜单的理念。
3
统一配置平台V2.0
在本阶段增加了应用层以及菜单集合的功能,并且确立了整个平台的架构。
新版平台架构
系统核心
这里的核心指的是统一配置平台的核心服务,这部分服务是与应用、功能隔离的,它主要的功能是生成应用、挂载应用,以及应用最初的管理员分配。在系统中的其他操作都与核心无关,都属于应用内的操作。
应用层
应用层又名APP层,对于后端服务来说,这是功能层的集合,也就是配置表单的集合,多个业务相关或互相依赖的配置表单将会形成一个应用。
相较于系统核心,应用层需要管理的事情就更多一点。配置的权限分配、菜单管理、角色管理以及一些拓展功能的管理都需要应用层亲力亲为。
功能层
功能层其实就是通过proto文件生成的配置表单,我们认为通过每份配置表单配出来的数据都是可以完成一种功能的,所以将这一层命名为功能层。它掌控着配置表单组件的渲染模板以及数据文档的版本存取。
因为加入了应用的概念,等于在系统核心与配置表单中间加多了一层抽象,正因为应用层的接入,我们将很多原本收束在核心内的权限及功能分发出去。
核心与应用间的分权自治
在我们的设计理念中,系统核心与各个应用间是一种分权自治的关系。
系统核心在生成应用的时候,会做许多初始化的工作来帮助应用实现自治。
当我们输入新应用的信息后,核心会根据所输入的信息建立相应的Git仓库(用于存储proto文件),并为Git仓库挂上Push钩子(用于接收并解析proto)。
然后生成与应用相关的库并内置必备的表,最后在记录应用的表中插入新应用的信息以完成新应用的挂载。
从上述应用生成的流程可以看出,与传统的配置系统不太一样,我们系统核心十分的“佛系”,它只负责应用的初始化,后续并不会干涉应用内部的运作,在生成应用的时候就会将权力下放给各个应用,每个应用都是可以自治的。
2.0版本开发完成后,我们将整个平台面向各个业务开发团队开放。
4
尾声
回望一下,统一配置平台从一开始的项目构思、项目孵化再到现在的开放使用,已经有接近一年的时间了。
在这一年的时间里,我们创建了13个应用,在每个应用中维护着大家创建的表单配置,一共维护了大约105个表单配置。在这上百个配置表单下,关联着大约11000条数据。已接入的配置中,日均请求量大概有835万次。
在项目的开发实践中,我们尝试了各种配置储存以及归类的方案、也怀疑过自己的设计理念、质疑过自己的项目初衷,但通过不断的实践我们认为这是适合微保的最佳实践,项目的不断完善和口碑也验证了这一点。