本文基于面向基本公共卫生的业务系统设计经验,抽象出一套适合大型ERP系统的表单业务数据模型,目标是最大限度保留系统弹性的同时,尽量下降系统复杂度和开发成本。enjoy~程序员
填写表单应该是全部业务线条中最避免不了的环节,例如我所经历的医疗项目:算法
以上面两个例图做为示例,能够看到姓名、性别、出生日期、血型等字段是彻底重复的,因为业务场景的差别,表单被定义了不一样的样式和字段结构,此时将遭遇如下几种问题:数据库
居民健康档案
中血型填写为A型,而在居民健康档案信息卡
中填写为B型;传统的区域化基本公共卫生系统正在经历这样的剧痛,固然其余行业好比金融的部分业务一样面临相同问题(本人只经历过这两个行业,见谅),如何在纷繁复杂的业务环节中抽离出四两拨千斤的数据模型,除了知足日益频繁的业务调整外,还能将数据完整的、标准的存储并利用起来,是后端产品经理的安身立命之本。做为一个游手好闲的产品经理,此次就从数据库表结构设计上,介绍一套解决方案:结构化动态表单。后端
1.可覆盖绝大部分表单业务场景。 2.表单样式和字段可灵活调整,不影响历史积累数据,不会形成数据库和代码层面的频繁变动; 3.数据统计时可以快捷、准确、全面地获取到想要的字段数据,不过分依赖文档和程序员老员工;框架
全部表单中全部的字段都在属性库中定义,至关于表单字段的字典。定义的核心包含属性的惟一标识、属性名、属性值取值规则和约束等信息。模块化
由于我认为全部的字段都是围绕某个业务进行的,把这个业务抽象成对象,那么这些表单的字段就是这个对象的属性,因此命名为属性库工具
若是用关系型数据库表达属性库,根据以往的经验能够总结出以下两个基础表: 布局
属性分类,主要根据使用者需求对属性进行分类,方便查找和后期的批量数据统计,好比健康管理把心率、瞳孔大小、脉搏等属性规划到生命体征类,把身高、体重等属性规划到基本体征类等等,所以仅须要定义惟一识别码、名称和分类说明便可。字体
属性,这个表很是重要,是数据标准化的基础表。惟一标识、名称、说明,这是一个属性最基础的说明,不用解释。优化
分类ID字段可支持多个ID,表示一个属性可划分到多个分类下,这个可根据实际需求定义,我所经历的场景是有这种状况的,好比心率,既能够是生命体征类属性,也能够是临床诊断类属性,很难绝对界定。固然属性和属性分类也能够经过单独建关系表来定义对应关系,方法有不少,各有优劣,看技术leader自行选型吧。
属性类型,根据我的的经验,总结出图中的几种类型,相信你们都认识,不用展开,其中单选框、多选框两种类型由于还依赖对应的取值字典,所以还须要到属性值字典中定义取值选项。另外值单位
这个字段,方便作数据转换和终端数据展现用,好比时长的值60,单位是分钟,经过算法便可转换该单位的值为1小时。
属性值字典,主要用于配合属性类型为单选框或多选框的取值,也是数据标准化的一部分。
例如定义一个属性叫性别的属性规划到基础信息分类中,此时会属性库的三个表中分别插入如下数据: 属性分类表:ID=‘1’,分类名称=‘基础信息’,分类说明=‘用户基本信息’ 属性表:ID=2,分类ID=‘’,属性名称=‘性别’,属性说明=‘用户的性别’,属性类型=‘单选下拉框’,值单位=空 属性值字典:[ID=3,属性ID=‘2’,字典值=‘男’],[ID=4,属性ID=‘2’,字典值=‘女’],[ID=5,属性ID=‘2’,字典值=‘未知’]
全部的动态表单都是以模版的方式保存在数据库中,表单模版中定义表单中填写的字段、字段的默认值和表单样式。
因为表单样式的不可预见性,所以能够准备一套符合自家产品风格的视觉设计语言,限定表单视觉样式的框架,包含前面提到的属性类型呈现样式,和细化到UI在手写、PC端、移动端的字体大小、线条风格、交互方式、间距、缩进、比例、布局方式等参数,固然本篇因为篇幅限制不展开和视觉风格相关的讨论,读者可自行脑补。
既然是模版,确定少不了控件,模版由控件组成,在这里把控件分为两类:属性组件和容器组件。
表单模版,是表单的字典表,用于定义表单的基础信息如名称、用途说明等,若是与业务衔接,还能够添加关联的业务、填写对象、触发填写的时间等,这部分信息由具体的业务场景决定,可根据实际需求设置字段。
容器组件,负责定义外观样式的组件,决定了属性组件在表单中的呈现样式,可根据不一样布局需求细分更多容器组件,这里不展开细讲。
顺序号,在同级下的显示排序,从左至右,从上至下的原则进行排列。
容器名称,即表单中某方框的名称,可不填
在终端显示表单时,须要充分考虑各个组件在页面上的默认布局参数和可变参数。一般前面提到的设计语言中会定义标准的内边距外边距、线粗和线色等视觉样式,这些就是默认布局参数,但组件在表单中的显示顺序、嵌套关系和组件内的组件排列方式等参数多数时候是须要配置的,依据实际需求添加参数便可。
容器组件可嵌套,当遭遇多级层级关系时,用容器组件实现嵌套关系再好不过了,不建议属性组件也支持嵌套,由于会提升属性值的取值复杂度,除了开发和数据存储逻辑复杂度高外,后期数据分析时也会进入逻辑黑洞,应尽可能避免
是否支持累加数据,此字段用于控制组件内的元素,是否能够按照定义的字段多组生成,例如如:
主要用药状况
中,属性组件药物名称
、用法
、用量
、用药时间
、服药依从性
的值能够添加屡次 还能够添加跟多字段或子表,描述容器更多的视觉布局样式,好比支持PC端、移动端、打印手写的样式定义。
属性组件,来自于属性库中的属性,决定了表单中填写的字段信息。
容器ID,当前属性组件放置在某个容器组件内,若值为null,表示直接放置在表单中
属性别名,为适应部分个性化的需求,能够为属性定义别名,好比身高,对婴儿一般叫身长,对青少年或成年人叫身高。别名定义到模版中而不是在属性库的意义在于,用户的个性化称呼一般只会在本身所处的场景内使用,对于其余场景下的其余用户并不必定通用。
属性默认值,很好理解,没用把这个字段放到属性库的理由和别名同样,场景不一样,默认值不必定通用。
是否必填,表单提交前判断必填项的依据。
页面区域,用于判断当前组件出如今其父组件的位置,枚举类型。
属性组件还能够有更多可扩展特性,后面会提到一些。
有了前面的属性库和表单模版库的配置,便可配置出各式各样的表单,而实际使用这些表单保存下来的数据格式是怎样的呢?
表单主表,做为表单的索引表,主要是提供表单的填写来源、时间戳和与业务相关的标记。
容器明细表,这里保存了表单内负责样式的容器数据,由于表单模版可能会变动,所以须要将其视觉样式数据保存下来,以记录当时呈现的样式,避免由于模版变动而形成的布局样式丢失。
属性明细表,保存了全部表单的全部字段的值。
为了配合容器组件记录其布局样式,还添加了容器ID、顺序号、组号、页面区域,用于记录保存表单时属性在表单中的位置。
组号,当遇到属性组件放置在容许累加数据的容器组件中时,标记出属性值所在的组。
别名,若属性在模版中配置了别名,则保存在这里,若是值为空,则显示原属性名。
修改时间,表单可能会遇到修改部分数据,所以标记字段的最后修改时间。若是有属性值的操做日志,能够不要。
动态表单的存在,在必定程度上能够缓解产品迭代因业务变动带来的压力,但其开发复杂度较高,尤为表单模版,解析模版数据呈现到终端时,依赖遍历算法,对程序员的要求不低,若整套产品的应用规模不大,不建议使用动态表单,或者根据需求开发简配版。
因为表单依赖属性库和表单模版的配置,属性和表单模版的维护质量决定了表单的数据质量,所以须要有高度责任心和专业能力的人员来进行属性库的维护,提升了使用门槛,但反过来说,罗马不是一天建成的,若是有野心创建行业标准,自己也须要大力投入数据质控。
产品开发和业务运行尽量的解耦。业务人员没必要彻底依赖产品业务功能的状况下才能运行相关业务(这个问题单独靠动态表单没法彻底解决,还须要依赖工做流,不过没有工做流时也能够勉强适应部分场景作业务试运行);
产品永远作功能迭代,尽可能避免数据迭代。常见的C端产品每每会有不少的营销推广广告页,这些广告页经常会频繁变化,并且为了抓热点每每须要即时响应跟进,若是按照每周发版1-2次的节奏,等发出来商业机会已经凉了,所以每每会作一个后台配置广告页的功能,使运营人员能够自行配置广告页面,包含页面元素、入口布局、外链引导、渠道埋点配置等等,这就是功能迭代。若是运营改一次广告,产品即发一次版,这就是数据层迭代。每一次变动都将累积相应的数据,产品是生成这些数据的工具,产生数据是业务人员作的事情,产品和业务是冰淇淋机和卖冰淇淋的小姐姐的关系。
用户永远只能看到功能,只关心产品是否知足其需求,而产品经理永远要从高低远近多维视角看待和解构需求,不断的整合、重组、拆分、概括,穷举各类场景下的业务形态,在业务耦合和模块化处理上达到平衡,本质上是优化效率,创造利润,若是达不到这两个目的,这个产品不能叫产品,只叫艺术品。
提早预判功能模块的发展趋势,在设计初期预留充分的扩展性和迭代方向,避免高频率的推倒重来,固然若是是敏捷开发,请无视这条。
如下是随意举例的可能的功能扩展方向,仅做为扩展阅读
多属性之间的逻辑约束和默认值
单属性复用
属性值字典 诊断、症状字典数据可能依赖外部接口调取,而非本地属性值字典库