分享从吴多益的【从实现原理看低代码】展开谈谈【众触应用平台】在低代码实现原理上的探索和实践

zcimg1 年前
00

引言

2015年写下众触应用平台第一行代码时我是完全没有理论支撑的,只是一心想做一个WEB开发的效率工具并降低些开发门槛。2020年时平台已基本成熟,也使用它来开发过一些商业项目了,猛然抬头发现低代码名词到处飞,才发现自己做的不就是大家口中的低代码平台吗?
拜读百度吴多益写的【从实现原理看低代码】,感同身受,受益良多。拿着文章去比较了一下当前主要的低代码平台,理解就更到位了。
众触早期走的是闭门造车的开发路线,跟主流理论自然就会有所不同(虽然大部分其实是不谋而合的)。如是也想比照着文章谈一谈【众触应用平台】在低代码实现原理上的探索和实践。

可视化编辑

吴提到【可视化编辑是低代码唯一不可少的功能】,【所有低代码平台必然只能采用「声明式」代码】,众触应用平台就是使用「声明式」的标准的HTML+CSS来渲染界面的。标准的东西可以让可视化编辑器的开发工作变得很简单,使用起来也更符合直觉。Flex弹性布局Grid栅格布局新拟物设计CSS滤镜编辑器CSS遮罩编辑器多边形裁剪编辑器都是很好的可视化编辑的例子。

由于直接支持原子级别HTML和原生的CSS,「一键导入HTML和CSS」就是水到渠成顺理成章的事情了,低代码平台瞬间变身仿站神器,湖上日出中国色、天空之城、Worktile就是通过「一键导入」的仿站习作。类似于源码开发,众触平台还支持CSS选择器、变量和伪类,全局CSS文件、页面CSS、内联样式和动态样式。

但低代码平台不是只能开发前端界面,【所有低代码平台必然只能采用「声明式」代码】就有点绝对了,专注于后端服务的低代码情况就不同,换成【要实现前端可视化编辑必然只能采用「声明式」代码】可能会准确些。
直接支持标准的HTML的低代码平台不多见,一般都会封装一下。当然众触平台也有封装好的高级组件,比如数据组件,它除了支持对象和数组作为数据源还支持树形结构的数据,在Worktile仿站习作中用它来渲染公司组织架构和网盘文件层级结构就变得很轻松自然。
文中还谈到声明式语言的缺点,但众触只是拿它来渲染WEB页面这个特定领域,这些缺点也就无所谓了。对于要实现跨端的低代码平台来说可能就麻烦点。

生成代码 vs. 动态渲染

吴谈到“生成代码的方案不算真正的低代码,本质上它还是一种开发辅助方式”,我也比较认可。众触应用平台不支持导出代码自行发布,而是运行时通过动态渲染引擎根据即时数据实时渲染的。

动态渲染可以带来很多好处:完全的即见即所得,给什么数据马上渲染成什么样子,预览和客户最终看到的没有任何区别,所以众触不强调实时预览,也没有预览按钮。不用生成代码,也就省去了代码生成和编译的时间,渲染速度之快让你误以为数据的改变和界面的重新渲染是完全同步的。【发布】动作也变得及其简单,仅仅是更改一下状态而已(标记一下当前版本是否可以交付给客户使用)。

有一点众触平台跟其它低代码平台不同的是,开发模式下中央占据最大面积的预览区是不让直接编辑的,为的是让预览看到的和交付给客户的界面完全相同。事实上,预览的唯一区别是绑定(劫持)了右键以便选择组件和选择组件时添加outline样式高亮突出一下。

话说回来,动态渲染也是有缺点的,比如浏览器需要加载渲染引擎代码,庆幸的是,众触的JS代码非常精简轻量,包括表达式DSL解释器和React.js在内的所有的代码压缩后(zc.min.js)只有285KB。另外众触也是允许导出元数据和业务数据进行私有部署的。

当然,对于需要多端发布的低代码平台来说出码就成了无奈的必选方式了,国内的情况更加复杂,除了iOS和Android还有各种小程序端。我其实也没那么激进,认为采用生成代码方案的平台(微搭、ZION)还是属于低代码平台的,属于应用开发平台但不是应用运行平台。

动态渲染还能即改即用,给「低代码快速交付」加分。很多时候甲方一个电话过来要求改这改那的时候,对于简单的需求改动,电话还没挂我就告诉对方刷新一下页面看看改的是否符合要求了。
在一次武术比赛现场【即改即用】更是体现的淋漓尽致。几百人的比赛场地,检录、裁判同步评分、裁判长调分、大屏投影显示、自动颁奖、批量打印奖状都要一气呵成,力图让选手参赛完成后尽快领到奖状离场。 第一次现场使用此比赛系统时,甲方发现几个未考虑到的需求,如是现场就改,即改即用,充分发挥的低代码快速交付的优势。

界面渲染实现原理

吴谈到【amis核心原理是将JSON转成自研的React组件库,然后使用React进行渲染】,众触平台也正是如此。只不过众触里的组件数量最多的是HTML原子组件,高级组件数量不多。稍懂HTML的开发者学习起来非常快,只需要把时间花在少量的高级组件就可以了。巧的是【amis可视化编辑器里提供了直接修改JSON的功能】,众触也是如此,就是最右边的【元数据】面板,更进一步的是开发者通过任何一种方式选中一个组件时,组件对应的JSON片段也会被选中并高亮显示,反之亦然。直接编辑JSON和通过可视化面板编辑是等效的,但通常我们并不太鼓励直接编辑元数据(却比较鼓励直接编辑CSS)。另外在众触平台逻辑编辑的时候是支持注释和多行字符串的。

交互逻辑的实现

吴得出推论【如果一个事物没有形体特征,它就没法被可视化】和【图形化不适合用来实现业务逻辑,只适合用来做更高层次流程控制】,非常赞同,众触作为通用的低代码平台也不提供可视化逻辑编排。

这个我是走过弯路的,发明了众触表达式DSL后感觉对小白来说还是门槛高了点,于是我花了半年时间基于Google的Blockly探索如何可视化编排生成众触表达式DSL并互相转换,最终都完全可以用Blockly拖拽业务逻辑了,和文本编辑等效,也可以来回切换。但我最终还是抛弃了Blockly,因为在后来的demo案例和商业应用开发中我都几乎没用过Blockly来开发,总觉得太啰嗦,不直观,占据屏幕空间过大。

我们发现目前市面上绝大多数的低代码平台要实现自定义交互逻辑时是要求开发者写JavaScript代码的。但这样做的门槛非常高,即使是专业的开发者也是如此,比不用低代码平台完全用代码开发的门槛还要高,因为还得学习平台的各种规则和约束,从一个代码片段调用另一个片段没有完全手写那样自如,而且很多时候代码量不减反增。

低代码顾名思义是要简化代码,才能降低写代码的门槛,其次代码量要少,不需要写那么多代码了开发效率自然就高了,Bug也少了。 在低代码平台上写代码肯定不如在IDE(VS CODE)里写来得爽。

众触发明了一种低代码逻辑处理的表达式DSL, 它是简化版的JS子集,但去除了很多JS程序的概念和写法。它的一个重要特征就是【分行编写,同步执行】,每行表达式默认会等待上一行表达式执行完后才开始执行,所有表达式执行完成后自动重新渲染。
比如在社区论坛中,用户点击某个分类,系统就要到product表里检索最新的50个此分类下的帖子和作者信息。每个帖子有个auth字段,保存的是作者的_id,显示帖子列表时也要显示作者的头像昵称等信息,所以获得帖子列表后还要继续拉取用户信息。但新拉取的帖子列表的作者有可能前面就已经拉取过了,这次就没必要重复拉取了,还可能这个列表包含同一个作者的多个帖子,那拉取一次就可以了。实现这个功能的表达式是这样写的:

$product.search("posts", {type: $v.type}, {limit: 50, sort: {_id: -1}})
$l.auths = $r.all.map('$x.auth').unique().filter('!$c.user[$x]')
$l.auths.length ? $user.search("auth", {_id: {$in: $l.auths}}) : ""

$v是页面变量,翻页时会被回收;$l是临时变量,事件结束后也会被回收;$c是全局变量,数据库返回的数据都会自动保存在那里。
$r是上一行表达式返回值(return、received),这里是刚刚拉取的帖子列表;$x是数组循环中的数据项,这里是作者_id

先是从帖子列表中提取auth数组,去重,再把已经读取到前端的作者排除,最后把新作者列表一次性拉取出来。
事件执行完了平台自动重新渲染,用户就能看到此分类下的帖子列表和用户信息了。

不仅每行表达式会同步执行,即使在循环中也会如此。比如把上面表达式简化一下:

product.search("posts", {type: $v.type}, {limit: 50, sort: {_id: -1}})
$r.all.map('$x.auth').forEach('$user.get($x)')

也能到达同样的效果,这次是循环作者列表,每次读取一个作者的信息,前一个拉取到了才去拉下一个。
表达式是更简单了,但会牺牲一些性能,同时平台会自动做一些优化。每次读取之前会检查一下即将要读取的信息是否已经读取过,已经读取了就直接返回以前的信息,相当于自动做了unique().filter('!$c.user[$x]')的工作。

当然异步执行也支持的,比如一个按钮上添加多个点击事件,它们是异步执行;有些函数有异步执行的版本,比如forEach(exp)是同步执行,而forEachA(exp)就是异步执行(A是Async的缩写)。我们把上面的forEach改成forEachA

$r.all.map('$x.auth').forEachA('$user.get($x)')

这个时候就变成异步执行了,平台会一次性发出所有读取作者数据的请求,不等待请求结果。
不用等待,以为速度会变快,其实未必,一方面浏览器HTTP请求是并发限制的,另一方面平台此时无法完美做优化了,多个请求中有可能是重复请求同一个作者的,浪费了网络资源。

目前我发现有类似表达式DSL的是微软的PowerApp的Power Fx,但它的表达式为了向Excel看齐,包含了大量的自定义函数,学习成本高,用起来也别扭。比如赋值Price = 12它非得用函数写成Set(Price, 12),比如比较运算符Price == 100它偏要写成Price = 100,反直觉了。

后端存储的实现方案

众触采用的是方案2:使用文档型数据库。正如吴谈到的这个方案的优缺点,优点是实现简单,具有更好的用户体验。不要求开发者一上来就建模,模型其实在开发早期是很难定下来的,门槛也高,需要具备高度抽象的能力,而且更改模型还是个非常复杂的过程。主要缺点是无法直连外部数据库,通常是通过API来交换数据。

低代码平台未来会怎样?

非常认同吴总结的低代码平台未来关于零代码和低代码的两个发展趋势。我们把众触归为低代码,整体使用门槛比无代码高,灵活性也强很多。从我们的实践来看几乎所有的WEB应用都能应付,像俄罗斯方块在线五子棋中国象棋做的也很好,甚至3D动画也能通过可视化来做,但开发效率并不算很高,效率最高的是数据驱动的信息系统,像天空之城,Worktile。

划分零代码和低代码也不是绝对的,我们就可以把众触平台分成两部分来看:
前端可视化开发UI可以认为是零代码了,因为只需要拖拉拽不用写HTML和CSS就可以开发出漂亮的静态页面来,略懂CSS原理的设计师就可以做到,业务、售前、产品也可以参与进来。
我们设想的是设计师(业务、售前、产品)通过可视化拖拉拽来设计前端UI,包括设计类名,CSS选择器,静态交互。工程师通过低代码DSL表达式实现业务逻辑,包括数据库设计和CRUD,数据绑定和运算,动态交互,以及后端安全。对于小项目或者UI要求不太高的项目很多时候工程师就全干了。

低代码平台不应束缚开发者

另外我想到的是低代码平台是要助力开发者的而尽量少限制/束缚开发者,可视化拖拉拽做的再好对于写了十来年CSS的前端大佬来说有时候也可能是隔靴抓痒。
众触提供的编辑器都是可以切换的。对于前端UI,既可以拖拉拽进行可视化设计,也完全可以像IDE里那样手写CSS,提供语法高亮和自动完成功能。可视化拖拉拽和手写编辑是等效的,可以随时切换;对于复杂的业务逻辑,既可以使用表达式DSL减少代码量提高效率,也可以使用原生JS代码来完成,它们之间甚至可以混用。

后记:我也试用了一下百度AMIS,感觉成熟度还不高,就没去深入了解,后来碰到几个awesome-lowcode群的行业大佬对amis赞不绝口,也就明白是自己太浅尝辄止了。

余贤域 2022年7月

投诉
收藏
点赞 0
评论 0
由众触低代码平台生成和驱动