低代码平台的实现

1,175 阅读22分钟

前言

年末的时候面试官问到了简历上的低代码项目,因为项目时隔久远,又着重准备刷了面试题,乍一闻直接懵了,30%的重点都没卡对,失策失策,所以下面是自我的一些总结。将从两个方面叙述低代码平台的实现,第一、我过往的低代码项目开发方案以及使用场景,第二、市面上常见的低代码实现技术选型及落地。话不多说,Let‘s start!!!

低代码平台过往案例

使用场景:第一家工作时,开发工作流的过程中,遇到了一些痛点。每个部门的业务流程并不统一,每个流程需要填写的表单内容也不相同。

如请假流程:

image.png

采购流程:

image.png

为了节省定制工作流,反复添加修改表单字段的工作量,配置了类似上述示例的低代码平台。通过拖拉拽的方式生成表单字段,供不同的定制工作流使用。

前端配置好,表单,以及表单属性,生成固定的Json格式,绑定到对应的工作流ID上,存入数据库。在工作流的渲染中,在根据type等字段将JSON数据,用element组件渲染出来。

遇到的问题:

  1. 表单字段过多时,JSON数据很大,有时候会超出数据库能存入的最大数据限制。
  2. 其实如果不是深度的粘性用户,一般很少有用户将低代码平台用起来,从0到1去一步步构建整个表单内容,因为现在盛行的还是懒人文化,大部分场景还是找到我们研发技术员,我们去给他们拖拉拽一个完成的审批流,这显然和我们一开始的初衷有些违和,消耗了一部分人力

如何解决:

1、设计好JSON数据结构,避免一些无用属性占据数据存储

2、为了解决这个问题,真正应用于内部公司的审批流中,解放程序员,我们定制了常用的一些模板,即使与一些业务部门的流程有些差距,使用人也可以自己稍作修改,比起从0到1的使用体验来说,模板的建立大大推广了功能的使用率。

常见低代码平台数据选型及落地方案

什么是低代码

低代码的核心要素就是可视化编辑,因为非可视化就是代码编辑。

前端低代码实现原理 - 界面渲染

前面提到前端 HTML+CSS 可以看成一种描述界面的低代码 DSL,因此前端界面实现低代码会比较容易,只需要对 HTML+CSS 进行更进一步封装,这里以我们的开源项目 amis 为例进行介绍。

核心原理是将 JSON 转成element、iview等组件库,然后使用React、Vue技术栈进行渲染。

比如

image.png

低代码平台为什么几乎都使用JSON

  1. 低代码平台编辑器几乎都是基于 Web 实现,JavaScript 可以方便操作 JSON。
  2. JSON 可以支持双向编辑,它的读取和写入是一一对应的。

低代码的缺点

不适合复杂的业务逻辑处理,适合一些固化流程或步骤的(个人理解)-〉

(题外话:不然怎么还需要产品、程序员呢,Chat GPT搞定就行了 )

后端低代码的方案

前端讨论完了,接下来是后端部分,后端低代码需要解决以下三个问题:

  • 如何实现自定义数据存储?
  • 如何实现业务逻辑?
  • 如何实现流程流转?

如何自定义数据存储?

低代码平台需要支持用户存储自定义数据,因为每个应用所需的字段是不一样的。

自定义数据存储是后端低代码最重要的功能,使用什么方案将直接影响这个产品的适用范围,目前我们已知有 5 种方案,每种都有自己的优缺点。

存储的实现方案 1:直接使用关系型数据库

这个方案的原理是将数据模型的可视化操作转成数据库 DDL,比如添加了一个字段,系统会自动生成表结构变更语句:

image.png 这个方案的优点是:

  • 所有方案里唯一支持直连外部数据库,可以对接已有系统。
  • 性能高和灵活性强,因为可以使用高级 SQL。
  • 开发人员容易理解,因为和专业开发是一样的。

但它的缺点是:

  • 需要账号有创建用户及 DDL权限,如果有安全漏洞会造成严重后果,有些公司内部线上帐号没有这个权限,导致无法实现自动化变更。
  • DDL 有很多问题无解,比如在有数据的情况下,就不能再添加一个没有默认值的非 NULL 字段。
  • DDL 执行时会影响线上性能,比如 MySQL 5.6 之前的版本在一个大数据量的表中添加索引字段会[锁整个表的写入]
  • 部分数据库不支持 DDL 事务,比如 MySQL 8 之前的版本,导致一旦在执行过程中出错将无法恢复。
  • 实现成本较高,需要实现「动态实体」功能,如果要支持不同数据库还得支持各种方言。

尽管这个方案有很多缺点,但它的优点也很突出,因此爱速搭里实现了这个方案,因为我们觉得能连已有数据库是非常重要的,其它方案都只适合用来做新项目,这个方案使得可以逐步将已有项目低代码化,不需要做数据迁移。

存储的实现方案 2:使用文档型数据库

文档型数据库不需要预先定义表结构,因此它很适合用来存储用户自定义数据,这个方案实现起来比较简单,以 MongoDB 为例,可以这样做:

  1. 用户创建一个自定义表的时候,系统就自动创建一个 collection,所有这个表的数据都存在这个 collection 里。
  2. 用户新增字段的时候,就随机分配一个 fileId,后续对这个字段的操作都自动映射到这个 fileId 上,用 fileId 的好处是用户重命名字段后还能查找之前的数据,因为所有数据查询底层都基于这个 fileId。
  3. 查询的时候先找到对应的 collection,再通过 meta 信息查询字段对应的 fileId,使用这个 fileId 来获取数据。

这个方案的优点是实现简单,用户体验可以做得更好,是目前大部分零代码平台的选择,使用这个方案的产品也很好识别,只要看一下它的私有部署文档,如果有要求装 MongoDB 就肯定是。

但这个方案也有显著缺点:

  • 无法支持外部数据库,数据是孤岛,外部数据接入只能通过导入的方式。
  • MongoDB 在国内发展缓慢,接受度依然很低,目前还没听说有哪家大公司里最重要的数据存在 MongoDB 里,一方面有历史原因,另一方面不少数据库都开始支持 JSON 字段,已经能取代大部分必须用 MongoDB 的场景了。
  • 不支持高级 SQL 查询。

你可能会问,现在 MySQL、Postgres 等数据库都支持 JSON 字段类型了,是否可以用这个字段来实现低代码?答案是不太行,只适合数据量不大的场景,虽然 JSON 字段可以用来存用户自定义数据,但无法创建字段索引,比如在 MySQL 要想给 JSON 创建索引,还是得创建一个特殊的[字段],这又需要 DDL 权限了,没有索引会导致这个方案无法支持大量数据查询。

在爱速搭中我们也实现这个方案,目前是基于 MySQL JSON 字段,后续可能也会支持存储使用 MongoDB,目前它的使用场景是流程执行过程中的数据存储,因此数据量不会很大,我们希望流程功能用起来可以更简单些。

它的最大特点是界面编辑和数据存储是统一的,当你拖入文本框到页面后就会自动创建对应的字段,不需要先创建数据模型再创建界面,因此用起来更简单。

image.png

表单模型

存储的实现方案 3:使用行代替列

这是很多可扩展平台里使用的技术,比较典型的是 WordPress,它的扩展性很强,装个扩展就能变成电商网站。而整个 WordPress 只有 12 个表,它是怎么做到的?方法是靠各种 meta 表,比如用于扩展文章的 wp_postmeta 表结构如下

image.png

其中的关键就是 meta_key 和 meta_value 这两个字段,相当于将数据库当 KV 存储用了,因此可以任意扩展字段名及值。

这个方案的优点是实现简单,但缺点也很明显:

  • 查询性能低,如果有 10 个字段就要查 10 行。
  • 无法支持 SQL 高级查询,因为数据是按行存的。

这个方案主要用于成熟项目的扩展,比如在 CRM 产品中允许用户扩展字段,但因为性能较低,并不适合通用低代码平台。

存储的实现方案 4:元信息+宽表

早期数据库不支持 JSON 字段的时候,有些开发者会预留几个列来给用户扩展自定义属性,比如在表里加上 ext1、ext2、ext3 字段,让用户可以存 3 个定制数据,基于这个原理我们可以进一步扩展,通过预留大量列来实现应用自定义存储。

这个方案最早出现在 [force.com]

实现它有两个关键点:元数据、预留列,这里简单说明一下原理,首先系统预先创建一个 500 列的表,比如就叫 data:

tenant_idtable_iduuidvalue0value1...value 4000

也可以创建更多,但注意有的数据库对列的数量有限制,比如 MySQL 最多是 [4096] 列。

上面的 data 表里主要有 4 类字段:

  • tenant_id 是租户 id,用于隔离不同租户
  • table_id 是自定义表的 id
  • uuid 是具体这一行数据的 id
  • 后面的 value0 到 value500 都是预留的列,用于存储实际数据,一般使用变长字符串类型

当用户给这个表新增一个字段的时候,怎么知道这个字段放哪?这就需要另一个用于描述字段信息的元数据表,比如增加一个「标题」字段时,使用另一个 table_fields 表来描述这个字段的信息,示例如下:

tenant_idtable_idfield_idvalue_indexnametype
1100标题string

在这个 table_fields 表里:

  • tenant_id 和 table_id 和前面一样。
  • field_id 对应的是给这个「标题」字段分配的 id。
  • value_index 对应前面那个 data 表里预览列的位置,比如这个值是 0,就意味着 value0 列被分配给了这个「标题」字段。
  • name 用来存名称,type 用来标识类型,这样查询和写入数据的时候,首先从这里查询 value_index 是什么,然后再去前面那个预留列的表中查询对应列的值。

最终在实际查询的时候需要根据元数据表做一下转换,比如 select 标题 from blog 要转成 select value0 from data where tenal_id = 1 and table_id = 1。

要完全实现这个方案还有很多细节问题得解决,由于篇幅原因这里不详细介绍,感兴趣可以阅读前面提到的 [force.com] 技术白皮书,这里列举其中几个问题:

  • 因为存储只能是字符串,所以对于日期、数字等其他类型,因此读取的时候需要根据类型使用数据库里的函数进行转换,比如 STR_TO_DATE

  • 需要单独处理唯一性功能,因为这个数据表是所有租户共用的,没法设置表级别的唯一性索引,这时就需要新建一个表来单独做,坏处是数据多份容易产生不一致,需要在所有更新操作都加事务。

  • 需要单独处理索引功能,同样是因为字段是字符串,因此没法直接在 data 表里加索引,如果数据存储的是数字,排序就是错的,为了解决这个问题需要另外创建一个一个包含常见字段的索引表,数据更新的时候。

  • 自增字段需要自己实现。

  • 元数据信息需要缓存,不然每次查询前都需要先查询元数据信息,然后再去查询真正的数据。

这个方案比前面几个方案的优点是:

  • 比起第一种原生数据库表方案,它不需要 DDL 操作,不容易出问题,跟适合 SaaS 产品。
  • 比起第二种文档型数据库方案,它的存储使用更为成熟的关系型数据库,相关的运维工具多。
  • 比起第三种行代替列方案,它的查询性能好,因为是读取一行数据。

但它也有许多缺点:

  • 无法支持 SQL 所有功能 比如 force.com 的 SOQL 无法 select *、没有视图、不支持写入和更新数据,通过这个特点就能识别出使用这个方案的产品,这类产品虽然看起来很像在用传统数据库,也支持使用 SQL,但这个 SQL 一定是受限的。

  • 数据泄露风险高

  • 一些数据库高级字段难以支持

  • 整体实现成本高

爱速搭中没有实现这个方案,我们曾经考虑过但后来放弃了,我认为这个方案虽然很适合 SaaS 类的低代码产品,但它的用户定位比较尴尬,一方面是有一定复杂度导致不能做到零代码平台那样的易用性,另一方面是有不少限制导致专业研发不喜欢,所以最终是两边都不讨好,这种产品想做成需要依赖广泛使用的平台,因此 Salesforce 才能做成,而国内类似情况我能想到的唯一成功案例是微信小程序,尽管有很多限制,但因为微信广泛使用,所以才成功了,如果是一个独立的小程序平台肯定没人用。

这里说一段小历史,在十几年前,当时云计算领域最先推出的是谷歌 2008 年发布的 App Engine,这是谷歌的第一个云产品,而当时类似 AWS EC2 那样的虚机产品国内都还没有,毕竟 KVM 也才刚发布。如果你当时问云计算的专家,云计算的未来是 App Engine 还是虚拟机,我听到不少专家的回答是 App Engine,因为这看起来更有前景,你只需要写代码,不用操心运维,平台会自动水平扩展,这才是云该有的样子,当时国内不少公司都推出了类似产品。

但 13 年后的今天,国内 App Engine 平台几乎都关闭了,而虚机不但是主流,还更进一步出现了物理机产品。这个元信息方案给我的感觉和当年 App Engine 很像,看上去能完成增删改查的简单应用,但如果深入就发现缺少很多功高级功能,导致两边不讨好:

  • 技术薄弱的开发者不会用,比如因为 App Engine 是分布式部署,导致上传文件不能放本地,必须改成对象存储,所以没法直接用 WordPress 没法用,对于小站长来说还不如用虚拟主机。
  • 对于有技术实力的开发者,又会觉得平台能力受限,不利于自己后续发展,比如谷歌的 App Engine 直到 2019 年才支持 WebSocket。

整体而言我不看好这个方案在国内的发展。

存储的实现方案 5:使用单文件

这个方案目前只在「仿 Excel」的零代码平台中见过,它和 Excel 类似,数据全都放一个文件里,查询过滤完全靠前端,优点是:

  • 实现简单,部署成本低,因为表的存储就是单文件。
  • 容错性强,数据类型都是靠前端处理的,不会出现存数据库导致。

缺点是:

  • 如果要支持行列级别权限校验,还得在后端实现一遍过滤,而每次都加载一个巨大的 JSON 文件对服务器内存有较高要求。
  • 难以支持事务操作,尤其是支持行级别的操作。
  • 目前看十万级别数据处理可以只靠前端,但再大量的数据就不合适了,一次性加载太多对带宽和浏览器内存要求比较高。
  • 只能当成 Excel 的替代品,数据是孤岛,不能直连外部数据库。

这个方案比较特殊,主要工作量在前端,有大量细节体验优化,在爱速搭中没实现,后续可能会考虑。

后端业务逻辑的实现

说完了存储,接下来是第二个问题:如何实现后端业务逻辑?

前面提到过代码难以图形化,这在后端也是一样的,因此大概有这几种方案:

  • 逻辑图形化,这个目前看各个产品效果都不太理想,看上去还不如代码易读。
  • 固定行为,主要是对数据存储提供增删改查操作。
  • 支持 JavaScript 自定义。
  • 简化 DSL 语言,类似 Excel 中的公式。

前面两种方案之前介绍过了,这里只讨论后面两种。

后端支持使用 JavaScript 是种常见做法,主要原因是 JavaScript 引擎容易被嵌入,而且启动速度快,了解的人多,比如市值超过 1200 亿美元的 ServiceNow 后端自定义业务逻辑就是基于 Rhino 引擎实现的。

简化 DSL 语言的主要是使用场景是做表达式计算,比如在流程中的分支流转规则判断,需要用户能自定义表达式,比如金额大于多少换成总监审批,这时用公式会比 JavaScript 会更简单,因为系统可以自动转换数据类型,并自动处理异步函数的调用,目前爱速搭的流程里有实现,同时在 amis 里也提供了

另外除了上面提到这四种,我们在爱速搭中还设计了另一个方案:执行树,它长这个样子:

image.png 左侧是树形结构,右侧是点中某个节点时的参数配置,左侧的树形结构其实是直接参考代码的树形结构:

  • 默认从上往下执行,但有个特殊的「并行执行」节点可以并行执行。
  • 对于循环和分支会创建子节点,并且子节点可以无限嵌套,相当于代码里的花括号。
  • 节点可以折叠,这样就能先将复杂的逻辑折叠起来方便看主流程,这是使用图模式难以实现的,在图里收起后无法修改其它节点的位置,导致空出一块。

为了方便实现简单逻辑处理,我们还增加了 JavaScript 节点和 SQL 节点。

但执行树这个方案目前的定位是聚合多接口,将多个后端接口数据合并后给前端,类似于 BFF 的作用,我们推荐复杂的后端逻辑还是用 Spring Boot 吧,成熟稳定且好招人。

流程的实现

接下来是第三个问题:如何实现流程?这是大部分低代码平台标配的功能,流程的逻辑不像普通代码那么抽象,因此适合用可视化编辑。

流程可视化存在很久了,著名的 BPMN 规范最早版本在 2004 就发布了,因此大部分产品都会支持 BPMN 2.0 规范。

但 BPMN 本质上是一种图形规范,它的最大作用是给事件、动作及分支条件这些抽象概念分配了不同的形体,使得熟悉这个规范的用户有了共同语言。

BPMN 不能解决平台锁定问题,在一个平台开发的流程无法直接迁移到另一个平台。

流程的核心是实现流程流转引擎,以爱速搭为例,流程可视化布局后最终存储的格式是有向图,比如下面这个最简单流程:

image.png 简化后的存储数据格式是两条连线和三个节点:

image.png 流程流转算法的核心就是根据当前状态和这个有向图,判断出下个节点是什么,然后执行那个节点的操作。

同时因为主要面向的是审批流,所以还需要处理审批场景特有的逻辑,比如有的审批是全部通过才算通过,有的审批是只需要一个人通过就算通过,还有回退、加签等功能,并处理各种边界条件,比如找不到审批人的时候怎么办。

虽然目前业界有开源的流程引擎,但这些引擎大多是面向代码开发,不太好改造成平台模式,因此在爱速搭里自己实现了流程引擎,这样才能更好定制功能。

低代码平台未来会怎样?

前面提到了各种低代码的实现方案细节,这里抛开具体细节,来整体讨论一下未来低代码平台会怎样。

最开始提到过低代码唯一不可缺少的功能是可视化编辑,这是低代码的最大优势,但是低代码的最大缺陷,因为可视化难以表达复杂的抽象逻辑,因此长远看低代码并不会在所有领域取代专业开发,更多是和专业开发配合来提升效率。

从技术方案上看低代码平台主要有两个方向:

  • 偏向零代码的方案,它的特点是
    • 易用性强
    • 灵活性差
    • 适合小公司,客单价低,但客户数多
    • 标准化程度高,导致功能都很类似,将面临同质化竞争
    • 产品使用简单,客户支持成本低
  • 偏向专业开发的方案,它的特点是
    • 易用性弱
    • 灵活性强
    • 适合中大型公司,客户数少,但客单价高
    • 标准化程度低,每家都有各自的特点
    • 产品使用复杂,客户支持成本高

未来会怎样呢?转载作者的想法是:

偏向零代码方案,因为功能类似支持成本低,可以同时支持很多用户,容易出现赢者通吃的情况,但由于 toB 领域发展速度慢,所以还是有不少机会,可以类比 BI 数据可视化产品,BI 这个领域的软件出现至少 20 年了,比如 Qlik 1994 就发布了,现在市面上的 BI 软件在基本功能上都大体相同,但没有哪个产品占据绝大部分市场份额,我们的 Sugar 产品虽然两年前才推出,但依然得到了不少优质客户,所以只要产品优秀就有机会。

零代码产品有好几种形态,和去年一样,我更看好「在线 Excel」,因为既然是面向非开发者,类 Excel 是上手成本最低的方案,而且这一年来许多「在线 Excel」的产品都加上了低代码功能,比如 Airtable 的 Interface,在功能上和表单驱动的零代码越来越接近了。

而偏向专业开发的方案,因为支持成本高导致没法同时支持很多客户,因此更难出现一家独大的情况,而偏向研发会导致细节方案有很多区别,没太多可比性。

以我们的爱速搭为例,目前产品选择的方案是偏向专业开发,现有客户都是知名企业,但也导致了支持成本很高,因为客户问的问题都很专业,大多只有核心研发才能解答,在功能方面我们的特点是前端使用了我们开源的 amis 框架,这个其它家是不会提供的。

TL;DR

前面字太多了,总结一下主要观点:

  • 低代码都是一种「声明式」编程,因为只有声明式才能可视化编辑,而可视化编辑是低代码唯一不可少的功能。
  • 低代码的优缺点其实来自于「声明式」本身。
  • 编写代码是一种抽象思维,因此并不适合可视化,导致低代码只能面向特定领域,复杂应用需要和专业开发配合。
  • 前端界面的 HTML+CSS 可以认为是一种低代码 DSL,因此界面的低代码比较容易实现,只需要在 HTML+CSS 基础上抽象一层。
  • 后端存储的低代码有几种方案,但没有哪个方案是完美的,它们都有各自的优缺点,这将决定一个低代码平台的适用范围,建议在选型时重点关注。

作者有话说:总结低代码平台的实现主流是JSON + UI组件+ 技术栈渲染的模式,前端实现。后端实现要调研好数据存储以及后端的业务逻辑设计,这里搬运的是知乎大佬的详细解读,目前个人过往项目实现均为前端渲染模式。

参考资料

从实现原理看低代码

手撸低代码平台搭建(一)走进前端低代码手撸低代码平台搭建(一)走进前端低代码

讲讲我做低代码平台这一年