做梦也不敢想的 FusionX 研发感想
Dec.24, 2024此文章内容摘取和总结自 FusionX v1.0.0 发布后内部分享会议
什么是低代码?
什么是低代码?Wikipedia 和 Forrester 给出了两个定义。
让我们画一下这两条定义中的重点:图形化界面(GUI)、配置式、快速/快捷交付、不需要了解常规开发中的前置工作。对这四点稍作总结,我们会得到四个关键词:
- 图形化界面(GUI);
- 配置式(Configurable);
- 低门槛(Minimal Upfront Investment);
- 快捷交付(Rapid Delivery)。
通过图形化界面和配置式开发方式,以最低门槛实现快捷交付。
在 FusionX 的设计与开发过程中,项目团队的同事们始终将这四个特点所组成的定义作为我们低代码开发平台的宗旨与目的。
值得一提的是,Gartner 在此前预测,在即将过去的 2024 年,65% 的应用开发活动将由低代码平台完成;而在 2025 年,这个数字将上升到 70%。这也证明了开发低代码平台所占据的市场份额将进一步提升,而使用低代码平台实现降本提效的任务也势在必行。
FusionX 架构设计
前面提到,低代码平台通过图形化界面和配置式开发方式实现开发活动。换句话说,我们需要建一个桥梁,将用户(开发者)在图形化界面上配置的结果与最终终端用户所使用的软件进行连接。
因此从产物的角度上来讲,我们需要完成的包或模块包括以下几类:
- 低代码设计器:进行低代码应用开发的模块,允许用户拖拽和配置应用的 UI;
- 低代码物料:一些可以被低代码设计器所支持配置的资产;
- 低代码渲染器:可以在终端设备上运行低代码应用的模块,负责渲染低代码应用并与终端用户进行交互;
- 低代码协议:描述从设计器到渲染器之间的映射关系,即表征用户设计的低代码应用的存储结构。
其中,低代码协议是支撑整个架构的基础。通过低代码协议描述的一种数据结构——Schema——可以表示开发者利用 FusionX 设计的应用与用户的交互规则与最终的渲染效果。
在低代码协议的支撑下,建设低代码应用设计器与渲染器。遵循低代码协议的规范对 UI 组件库进行“入料”,即处理成符合低代码协议的低代码组件,然后加入到我们的低代码资产库中。已经入料的资产我们称为物料或 Building Block。物料可以在低代码设计器中被用户用于拼装用户界面和交互逻辑,并在渲染器中被最终呈现给终端用户。
低代码设计器和低代码渲染器目前只能用于流程+表单的编排形式,即我们业务中常见的申报、审核流程。此外,不包含流程的应用也可以被支持。在未来,低代码设计器和渲染器将具备开发整个项目的能力,包括常规视图、数据可视化、数据洞察等。
最终,由低代码设计器和渲染器构成低代码引擎。低代码引擎被设计成可以支持插件和定制化的核心模块,在内网 GitLab 中以独立 npm 包的形式存在(@fusionx/core
)。通过注册低代码引擎插件,大家可以体验到来自同事们共建共享的低代码开发工具链,例如低代码调试工具、一键表单测试填充等。
由整个体系形成的平台,就是低代码开发平台 FusionX 了。
Schema
在低代码协议的约束下,描述应用结构、形态、交互逻辑的私有 DSL 称为 Schema。Schema 是 JSON 结构,因此具有平台无关的特性,任何语言下均可依照低代码协议实现对 Schema 的序列化和反序列化。因此,从理论上讲,只要都严格遵循低代码协议规约,那么其他语言的低代码设计器和渲染器也可以实现。
通过类似于 DOM 树的形式,我们对低代码组件进行描述。
当用户在低代码设计器中对应用进行设计时,其本质是对 Schema 结构的修改,即:
- 当用户新增组件时,体现为在 Schema 中插入新元素;
- 当用户修改组件的配置项时,体现为修改 Schema 中对应的元素中的某个属性;
- 当用户调整两个组件的顺序时,体现为修改 Schema 中对应的两个元素的下标;
- 当用户删除组件时,体现为从 Schema 中移除对应的元素;
- 当用户复制组件时,体现为从 Schema 中复制指定的元素并插入到该元素后方,同时重新生成组件的唯一标识 UID;
- ......
类似地,应用的流程(如有),也采用 JSON 的形式保存在 Schema 里。
Schema 的整体结构如下所示:
{
// Schema 版本,不是应用的版本。出于设计器与渲染器的
// 迭代升级和版本兼容性考虑设置
"version": "1.0",
// 应用对应的表单的 Schema
"form": {
// 表单中的所有组件
"widgets": [
// 组件的配置
{
"type": "input",
"uid": "si2mu93jas",
"props": {
"field": {
"label": "输入框",
"name": "user.name"
}
}
},
// 其他组件...
],
// 表单整体配置
"labelWidth": "120px",
"labelPosition": "vertical",
// 其他表单配置
},
// 应用的流程配置
"flow": [
// 应用的流转流程任务节点配置
{
"type": "audit",
"props": {
"strategy": "30",
"actor": [20, 10]
}
},
// 其他任务节点...
],
// 应用的数据配置
"dataSource": {
// 应用关联的数据表
"tables": [
"business_common",
"business_example_table1",
"business_example_table2",
],
// 应用的初始 Schema 渲染信息
"paginated": "tabs",
// ...
}
}
感想1:数据驱动视图的(又一个)典型案例
当整个 FusionX 架构设计结束之后,我们发现这是一个典型的数据驱动视图的典型案例。用户通过一些事件触发了对 Schema 的修改,而 Schema 的内容是渲染视图的唯一依据。
FusionX 预览
FusionX 目前划分为若干个包,在内网 GitLab 上托管在同一个群组内:
- @fusionx/admin:【前端】管理后台统一开发模板;
- @fusionx/uc:【前端】用户中心统一开发模板,uc = user center;
- @fusionx/utils:【前端】前后台通用工具类库;
- @fusionx/server:【后端】服务端;
- @fusionx/core:【前端】低代码引擎;
- @fusionx/doc:在线文档。
除 @fusionx/core 目前仍未开放(只能由开发人员访问),其他包均可自由克隆、试用和提请 PR。
使用 FusionX 的开发流程
在低代码开发时代,开发一个应用的流程有些许不同。我们不再需要按照申报端、审核端的方式进行分工,而只需要进行一次开发,即可实现前、后台,前、后端逻辑的自动实现。
FusionX 生态体系建设构想
完全建成后的 FusionX 低代码引擎具备扩展和集成插件的能力。
我们会支持自定义组件的入料,并允许使用低代码平台开发/封装低代码组件。
在渲染方面,我们将支持通过独立的pnpm add @fusionx/core
的方式引入渲染器和设计器,并支持渲染到第三方组件库(例如 element-plus 等)。此外,我们将开放低代码协议的全文内容,有些同时负责使用较老的技术栈开发项目的同事可以自行实现不基于 Vue 的渲染器,从而渲染到类似 Bootstrap 等库。
在设计方面,组件的配置将支持更多类型的设置方式,同时所有输入型设置器(例如默认值等)将全部支持使用和解析表达式。
在理想情况下,组件的动作设置将不再需要编写 JS 代码。这意味着实现字段联动的功能可以通过更直观的方式实现。表单组件的校验等规则允许通过同事们共建共享共同贡献的方式扩充一组常用于业务中的校验规则,而无需手动编写。
最终,包括插件等能力的引入将会使得低代码引擎真正成为一个引擎。
感想2:代码永存
很多人说,程序员将会很快消失。经过长达半年的 FusionX 开发历程,我认为这是一个伪命题。
让我们回顾一下程序员与编程之间的关系。
首先我们的讨论需要建立在一个基础共识上,即程序员的工作是编程,而编程的目的是为了实现需求。
一名软件工程师在真正进行系统设计与开发之前,需要先了解需求,进行需求管理与开发。我们产出了需求文档,进行无数次调整最终实现产品——产品稳定后将不再进行调整,它 100% 契合了需求。
所以我们得到一个推论:
代码是用于描述需求的语言。
是的,所有语言在描述需求上都无法和代码的精准度相比。代码是唯一能够 100% 还原需求的语言。
在最初,程序员通过编写代码还原需求。我们称这个是编程。换句话说,编程就是还原需求的过程。
而现在,借助 FusionX,我们通过在低代码平台中拖拽配置的方式开发产品,以此还原需求。那么套用刚才的定义,拖拽和配置就是编程,是还原需求的过程。
而假设在未来,人们已经完全可以通过 LLM 实现产品开发,而不需要再手写哪怕一行代码,那么那个时候,我们给 LLM 描述的自然语言就是编程,因为这就是我们在未来还原需求的过程。
所以我们看到:代码永存。程序员将始终存在,程序员为了实现需求也将始终从事编程的工作。但编程的工作内容却可能发生变化,从编写机器代码到高级语言,到低代码编排,到最后的自然语言。我们不断探索更加声明式和更高级的描述需求的方式,为了更准确、快速地还原需求。
就像会计师的工作始终都是“算账”,但工作内容从使用算盘到使用计算器、计算机和财务一体化软件。我们的工作也始终是编程,但科技的发展要求我们适应新的开发方式和流程,实现我们行业内的“流程再造”。
感想3:在开发时重构
我的第三点感想,就是要在开发时重构。
在 FusionX 第一个版本为期半年的开发过程中,前端进行了两次较大规模的重构。我不会深入设计模式和整洁代码这类技术细节来探讨重构的内容和最终成果。但我们要问一个问题:为什么要在开发时重构?
很简单,因为我们不会在“重构时”重构。我们平常经常说的“先这样吧,有空再改”是一句彻头彻尾的谎话。根本不会有单独的时间用于重构——在项目中时间紧迫,我们会抱有侥幸,认为时间这么紧张,不是重构的时机;而当项目的冲刺期过去,我们会想已经过去的事情不必再次提起,因而就让往事随风而去。
所以,永远不会有重构的时机。
那么为什么一定要重构呢?只写一遍代码会存在什么问题?
因为外部环境和自身原因导致了我们编写的第一遍代码永远是稀烂的。如果我们只编写一遍代码,那我们将始终与垃圾代码相伴。
有的同事可能会说:“可是我真的很忙”!
相信我,我也是,我们都是。但时间紧张并不是进行妥协的借口,因为进行妥协并不能够真的缩短工期。即便可以,面对几乎 100% 需要调整的需求,所节约的时间将在日后的修改和维护中因为技术债务的存在而加倍偿还。
我们作为专业的技术人员,不能够因为妥协而丧失我们的专业性。
对于如何在开发中重构,根据 FusionX 的经验,我可以给出以下几点:
- 让营地比来的时候更干净。不留下垃圾的同时,随手带走一点前人留下的垃圾。这是露营的时候的良好道德要求,可以借鉴到编码上。我们在 push 代码时,始终让代码比 pull 的时候更干净,就能逐渐重构我们庞大的代码库,而不用付出过多的经历;
- 统一的格式是头等大事。我们使用 ESLint 和 Prettier 对代码进行统一格式化。统一的格式比争论谁的习惯好更有利;
- 有变得更好的意愿;
- 保持专业。有的时候我们的任务需要更多的时间保持代码清洁和易于维护,那么我们需要鼓起勇气向经理和客户说“不”,因为我们并不是对立关系,而是向着共同的目标努力,大家都想要产品变好,那么保持自己作为开发人员的专业性就是我们的职责所在;
- 牢记妥协并不能缩短工期。
关注开发者体验
FusionX 是一个开发平台,其用户——与终端软件最大的不同之处就在于——都是开发人员。因此,这个时候,我们需要关注的用户体验 UX 就变成了开发者体验(DX)。