在开始介绍配置化系统之前,我们先看几个场景。

1.加字段

image.png

2.改流程节点

image.png

3.UI动态化

image.png

这些都是我们在日常开发中的场景。通常来说,如果我们能够实现不进行大量的开发就能实现上面这些需求,我们就会把这样的应用称为可配置化的应用。

什么是配置化

  1. 对于配置化其实并没有一个标准的定义。也有人认为,配置能力是计算机软件天然具备的能力,没必要单独把它作为一个领域。但因其实现难度相对较高,在实践过程中,大家经常会把它拎出来说。软件系统通常按照MVC来进行分层,配置化能力与之对应,可以分为:**数据可配置,流程可配置和界面可配置**

1.数据可配置。横表转纵表,弹性字段(一个弹性域由多个段组成,每个段是数据库的一个列),预留字段 2.界面可配置。界面定制和界面控制。界面控制包含配置文件的设计、解释器设计和输出结果的设计 3.流程可配置。工作流引擎(流程的状态转换机和路由控制器)

配置化都在做些什么

这个话题比较大,时间也有限,我们今天的分享主要集中在数据可配置这一部分。我们以大家比较熟悉的手机的经销商作为背景:
苹果如果出了一款手机,大家既可以在他的官网上直接进行购买,也可以在经销商那里购买。比如常见的淘宝上非官网直营店,和线下的许多非苹果直营的门店,都是经销商的一部分。其中大家熟知的最大的经销商就是苏宁易购了。要称为苹果的经销商也是有着门槛的,需要进行申请和审核。我们今天就以这个申请系统作为例子。

1.最开始的系统可能是这样的:

image.png

简单的提交表单,发起申请,数据库把它存下来。如果字段增加了,前端增加一个FormItem,问题不大。后端就会开始遇到一点麻烦了

经典的代码分层结构:DAO,Service,Web,前端
1.DAO层和表结构一致,底层改了,所有的上层代码都需要修改
2.单业务系统还好,多业务系统就会非常麻烦。比如DAO层或Service层的接口,在被其他系统使用,需要推动其他系统做调整。如果系统被其他应用调用得多,自己可能都不清楚有多少应用在使用相关服务
image.png

2.第一次优化

image.png

前端可能会用一个JSON来描述这个表单,以后每添加一项,JSON加一项就好了,不用再写FormItem相关的代码。后端可以增加一张拓展表,关联上原来的主表,减少对主表的操作。虽然本质还是增加列,但是因为放在拓展表里面,用到的地方会少一点

3.支持多种表单输入类型

常见的用户输入,除了输入框,还有文件,多选,下拉选择,日期选择等。为了支持多种表单输入,我们还得增加一个type字段。
为了实现快速复制一项就增加一列,前端需要对基础组件进行封装。
比如Select需要获取可选的枚举值,文件上传要先传到OSS最后只提交URL,省市区和行业范围等级联选择要获取配管系统的数据

  1. [
  2. {
  3. "name": "字段名称 1",
  4. "code": "字段code 1",
  5. "type": "input"
  6. },
  7. {
  8. "name": "字段名称 2",
  9. "code": "字段code 2",
  10. "type": "file/radio/checkbox/select/Date",
  11. "options":[]
  12. },
  13. ...
  14. ]

如果存在表单联动,需要对表单的状态进行管理

4.表结构动态化

我们的表结构,虽然把一些后续可能添加的字段移到了拓展表里面。但其实我们在增加字段的时候还是通过新增一列的方式。用这种修改表结构的方法添加字段,服务端代码也需要做相应的调整才做最终新增一个字段。在代码耦合程度比较高,多处代码需要修改,新增一个字段要一周真的是不奇怪。

另一方面,随着公司发展,业务不只局限于手机,可能会开始开展电脑,平板,手环等业务。一开始的时候可以复用这套准入流程,找到各个业务之间的共性。但业务增多,开展跨国业务之后,就会开始需要有定制化的能力。针对不同的业务,不同国家有不同的业务要求,这时就会对准入流程有定制化的能力

这里也是系统建设的分叉点:
1.搭建方案
2.动态生成表单
其实他们俩本质上是一样的,区别只在于配置数据存放在哪。但在前后端分离的现在,对我们区别比较大,所有分开来说。搭建方案可以前端控制,动态生成表单则是后端控制
除了这两种,其实前端还可以通过硬写代码的方式实现:毕竟没什么东西是不能通过写代码实现的。每一种业务类型,有自己的入驻页面。数量少的时候,这样做是没问题的。多了之后就不行了:一来是成本太高,二是很多组件其实是可以复用的

image.png

image.png

还是分成两边:
后端要把表结构变成动态的

a.动态增加数据库表字段
数据库表增加列,不可取

b.预留足够的空白字段,运行时作动态影射
image.png

c.用JSON/xml格式保存在单字段里

image.png

d.改列为行,用另外一个表存放定制字段

image.png

动态列性能上确实可能会有点问题。比如你要统计:红色的手机的一个月销售额就需要至少在四个表(类型:手机、产品:型号、属性:颜色、销售:一个月内的销量)进行联合查询。

方案比较

个人认为,主要包括高效率的查询性能以及可易扩展的设计。
我们于是从这两个方面分析上述四种设计,
第一种方案几乎没有可扩展性(列的扩展远远不够于包含所有产品不同的属性);
第二种方案看上去可扩展性不错,不过它的属性就全部以纯文本的样式存储,查询效率自然想到差;
第三种方案看上去是一个折中,实际上它是产品、属性、属性值的笛卡尔积了,数据量将非常巨大,根本不适合大型的电子商务平台,因为查询效率会很低,并且对于结果的拼排将是很大的代销;
第四种方案也许拥有最好的扩展性,但是如果对于跨产品的查询,也将是低效率的。

前端:

复杂点

表单校验规则
参数传参(key value 的方式后端不好接收),后端也不知道会有多少个参数,不能穷举参数
表单联动(reactive,字段监听,字段可能不存在的,进而可能影响)
字段分组(EPP管理中心,纯展示的虚拟节点)
Options获取,存储和关联(级联选择,省市区,行业范围,公司能力),数据格式化(日期)
提交表单的时候文件上传只传URL

周边方案及其关系

jsonform,Uform,Flex,乐高

基本原理:

image.png

jsonform/uform

jsonform 用 redux 管理状态,uform 用 rxjs

优势:**
1.动态,递归
2.安全可控
劣势:
1.需要写一些代码,渲染引擎用jsonform/uform,主要是粘合代码

image.png

递归

image.png

乐高/flex

image.png
优势:
1.乐高自带渲染引擎,设计器可拖拽
缺陷:
1.没有真正的动态,无递归。更像模板
2.数据库无字段,需要hook机制和组件生成机制
3.配置和系统脱节的可能(类比TMS)
4.PD操作,有误操作的可能

流程可配置

流程引擎,BPMN,activiti

前台流程

后台流程

流程不一致

界面可配置

定制列

参考文章:

数据库设计如何实现属性可配置化:https://blog.51cto.com/changmen/1937349
如何设计动态(不定)字段的产品数据库表:https://my.oschina.net/xldc/blog/856626
Stop making software configurable! : https://www.weshigbee.com/stop-making-software-configurable/
Customized vs. Configurable Software Solutions: Which Should You Choose?
https://npengage.com/nonprofit-technology/customized-vs-configurable-software-solutions-which-should-you-choose/
The Changing Landscape of Nonprofit Technology (and What It Means for Your Org)
https://npengage.com/nonprofit-technology/the-changing-landscape-of-tech/#
数据库字段动态扩展设计:https://blog.csdn.net/kk185800961/article/details/53208667
配置化系统周边知识:https://yuque.antfin-inc.com/docs/share/9916d960-5de0-4fdc-92bd-2e528b9a746f?#
[RFC] x-linkages 联动规则描述提案:https://github.com/alibaba/uform/issues/478
可配置化软件架构探析及实操秘诀:https://mp.weixin.qq.com/s?__biz=MjM5ODIzNDQ3Mw==&mid=2649965996&idx=1&sn=617c19cc1cfeb28ebd7aed1bbad0a7ff&scene=0#rd