本文是一篇讲解元数据案例的技术文章; 同时也谈论如何对传统 CRUD 进行破局的文章。
元数据思想-打破传统的思维方式
打破传统的思维模式, 跳出固有的认知模型,从更高的视角去理解这个世界。
我将从案例进行逐步分析、讲解,一步步地打破固模式; 感受一下从元数据的思维方式去解决传统的 CRUD。
一、构建查询案例--"看山是山,看水是水"
1.1 案例背景
下面是一个案例,该工具是帮助运维人员对公司的不通账号类型进行管理的后台;比如下面是 T1 类型的账号, 通过输入 T1 类型账号,可以显示账号的数值列和操作列。 比如"打标" 是可以点击操作的操作列,员工ID只做展示的就叫数值列。
当然我也很难用一两句话让大家明白业务; 于是我简化业务,用更加技术的语言和图片来描述上面的功能场景。
T1 类型账号, 有3个数值列,2个操作列。
T2 类型账号:3个数值列,3个操作列
当然还有 T3、T4......不再赘述。
总结的规律:数据列和操作列是根据账号类型返回的, 列和值的数量是不同的。
一句话需求: 不同账号类型有不同的数值列和操作列。
那么,针对这样的需求,应该返回什么样的数据格式呢?接下来按照传统方式写一些 CRUD了。
1.2 传统思维模式-照着原型建模
于是会按照给定的原型进行数据建模,针对不同的账号类型返回不同的 VO 对象。
比如 T1 类型的账号 VO 返回体和数据实例如下:
css
[{ "userId":"T1-001", "userName":"运维人员A", "isEnterprise":"是", "doFlag":"打标", "resetStatus":"重置状态" }]
并且和前端约定:doFlag 和 resetStatus 有值的时候,作为行为列。(告诉前端这个两个值要写死!)
同理 T2 类型的账号 VO 返回体方式一样, T3、T4....... 如下所示:
传统开发模式: 拿着原型进行建模,就像上图一样,一一对应,好像没有什么难度。
打入这一行起,好像都是这么搞的,毫无问题。
这是一种传统的思维,甚至是一种僵化的思想。
1.3 劣势
这种按照原型建模开发的方式虽然非常简单,但是也存在一些弊端。
结合案例说劣势可能会更有体感。
比如 T1类型和 T2类型,虽然很相似,但是一样需要有两套数据模型,甚至前端也需要写两套逻辑;类型越多,模型越多;
另外哪些列需要写成行为列,也需要固定写死;
甚至当业务需求发生变化后,比如增加一个字段或者删除一个字段,从后端到前端,都要进行一一修改。
二、打破思维僵局--"看山不是山,看水不是水"
2.1 思维破局
既然传统方式有这么多不足,那么是否可以寻求一些变化,以此来破局呢?
再来回顾下面这张图(看这个世界的视角不同,解决方法也是不同的)
视角是会影响到思维的,因此可以从更高的视角来解决问题
进行传统功能开发的,就是按照一种较低的视角进行思维活动的。
如下所示:照着原型建模,谁不会呢? 上半部分是原型,下半部分是模型; 就像那只在井里的蛙一样,看这个世界的方式总是抬头向上。
尝试站在更高的视角去看问题呢,尝试跳出固有的认知习惯,尝试以不一样的方式去理解这个需求。
于是提出一个想法:对表头行,数据行进行统一的建模。
- 对表头进行分析,建模;对列值再进行分析建模。
- 达成统一抽象
表头建模:
key:表示表头的唯一id值
title:表头需要展示值
type:表头对应的类型,type=action 表示这个列是行为列。
当然还可以对表头增加宽度、数值类型的元素,但考虑简单就忽略了。
列值建模:
key:与表头保持一致
value:表示具体值
对整个查询列表进行模型的重构,这样的模型具有更高的抽象维度,更具有普适性,扩展性。
所有的查询列表都按照上面的模式进行重构了; 不管是 T1、T2、T3还是其他,都能使用统一模型进行表示。
对数据本身进行一种描述;从更高的视角进行抽象。
2.2 新的思维建模
那么返回的数据不再是固定模式的值了。对表头进行建模。三个字段如下:
对于数值列,这里比较简单,就用 key 和 value 就好了。类似 Map<Key,Value>
表头和数值列就如下所示:
数据案例如下:
json
{
"headerList": [{
"key": "userId",
"title": "员工Id",
"type": "display"
},
{
"key": "userName",
"title": "员工名称",
"type": "display"
},
{
"key": "isEnterpise",
"title": "是否已是企业账号",
"type": "display"
},
{
"key": "doFlag",
"title": "打标",
"type": "action"
},
{
"key": "resetStatus",
"title": "重置迁移状态",
"type": "action"
}
],
"valueList": [{
"isEnterpise": "是",
"isWhiteList": "是",
"userName": "运维人员A",
"userId": "T1-001",
"doFlag": "打标"
}]
}
针对数据列,采用统一的接口。前端不用关系业务。
ini
{{url}}/opsOperation?operationKey={{key}}&userId={{userId}}
通过 operationKey 作为后端路由值。比如打标的时候,operationKey = doFlag
通过这样的方式:所有的账号类型都可以采用统一数据模型。具有统一性、普适性、扩展性。
2.3 优势
- 前端不用再关心业务,仅关注技术开发,不用涉及业务
- 更能应对变化:比如可以将表头等信息放在分布式配置中心,这样可以动态新增调整,如后端可以动态控制列的个数、行为个数;当业务发生变化的时候,只后端进行调整,变更成本更低
- 技术质量:代码重复度低,扩展性也更强
- 当然也更有趣
虽然实现效果可能都是一样的,但实现的方式却千差万别;后续的维护成本也完全不同。
这是视角的不同,思维方式的不同, 同时也是一种抽象能力的不同。
三、一招鲜,吃遍天 --"看山还是山,看水还是水"
3.1 元数据思维
可以再来回顾一下这种图,可能现在会更有体感了。
元数据思维,从更高的视角去看问题;习惯跳出数据本身,而不是被数据本身所束缚。
只有跳出数据的泥潭,才能看清泥潭。"不识庐山真面目,只缘身在此山中。"
元数据是对数据本身的描述,层次更高!也是抽象维度、抽象粒度的不同。
可能你想问有什么秘诀吗?我可能会回答你,依葫芦画瓢地实践!这样你才会慢慢有体感!
关于抽象的文章,感兴趣可以阅读这两篇文章。
写代码这件事,迈入第七个年头才有了一些心得(第二章 抽象) - 掘金 (juejin.cn)
写代码这件事,迈入第七个年头才有了一些心得(第三章 抽象下篇) - 掘金 (juejin.cn)
简单总结:
元数据:对数据进行描述。元数据的思想,尝试用更高抽象度定义数据;并跳出传统思维,用不一样的视角进行思维活动。 通过实践练习可以达到更好的效果。
3.2 更多案例
这种更高粒度的抽象案例其实还挺多的。也挺有意思的,对于 CRUD 传统思维的破局是一个非常不错的方式,简单再总结几个曾经做过的小案例。
案例一:表单类型的搜索
比如:搜索大于,小于,等于。
针对搜索控件进行建模,比如可以抽象建模:
- 搜索方式
- 搜索值
- 数据类型
案例二:动态展示列
可以动态展示列。比如本案例中过,就可以根据前端勾选列,动态从后端去搜索多少列动态返回。
案例三:低代码
底代码平台则更是抽象层次更高也更复杂,但是这种思维是能进行移植的。
其他的就不再一一赘述了。
3.3 最后感慨
编程的核心不是技巧,而是思维 !
与其天天写一些没啥技术含量的东西,不如尝试变通一下!
与其坐而论道 不如起而行之!
最后再来回味一下这个图,希望有更多的想法和灵感!
到此结束,感谢阅读。本文将收录到公众号(面汤放盐)中,欢迎关注!