掘金-低代码架构设计协议驱动vs代码生成.md 11 KB

低代码平台的两种路线:生成代码还是协议驱动?我们选了后者

低代码喊了这么多年,很多人还是没搞清楚:有的平台"生成一坨代码",有的平台"运行时渲染配置"。这不是技术选型的差异,是产品哲学的差异。这篇讲清楚两种路线的本质区别,以及我们为什么选了协议驱动。

低代码平台看着都差不多:拖拽表单、配置字段、生成页面。但如果你扒开底层,会发现两种完全不同的技术路线。

一种是代码生成:你配的东西,最终变成一堆代码文件,下载、合并、部署。

一种是协议驱动:你配的东西,最终变成一份 JSON 协议,运行时引擎按协议渲染页面。

这两种路线看起来都能"搭页面",但长期演进下去,差别巨大。这篇就把这两种路线彻底讲清楚。


一、代码生成路线:产物是代码

怎么工作的

代码生成路线的核心流程:

在线配置表单/页面
   ↓
模板引擎渲染(Velocity/Freemarker)
   ↓
生成 Controller / Service / Mapper / Vue 文件
   ↓
手工 Merge 到项目
   ↓
编译、部署、运行

你配了一个客户管理页面,平台给你生成:

  • CustomerController.java
  • CustomerService.java
  • CustomerMapper.java
  • CustomerMapper.xml
  • Customer.vue

这些是真实的代码文件,和手写的一样。

优点

  1. 生成即最终:生成的代码直接能跑,不依赖运行时引擎
  2. 可二次开发:拿到代码后想怎么改怎么改
  3. 无运行时开销:没有解析协议、动态渲染的性能损耗
  4. 对开发者友好:代码在手,心里不慌

问题

  1. 改了再生成要处理冲突:你改了生成的代码,下次再生成,冲突
  2. 代码风格依赖生成器版本:生成器升级了,新生成的代码和旧的风格不一致
  3. 页面和代码死绑定:改一个字段,要动 Entity、DTO、VO、Mapper、Vue 五六个文件
  4. 没法在线调整:想改个字段标签,得改代码重新发布
  5. 代码量膨胀:100 个 CRUD 页面 = 600 个文件,维护成本高

代码生成的本质是"用工具替代打字"——生成的还是代码,你还是得按代码的方式维护它。


二、协议驱动路线:产物是 JSON

怎么工作的

协议驱动路线的核心流程:

在线配置表单/页面
   ↓
保存为 JSON Schema 协议
   ↓
运行时引擎读取协议
   ↓
动态渲染页面
   ↓
用户直接使用

你配了一个客户管理页面,平台保存的是:

{
  "modelSchema": {
    "fields": [
      { "name": "customerName", "type": "input", "label": "客户名称" },
      { "name": "level", "type": "dict", "dictType": "customer_level" }
    ]
  },
  "pageSchema": {
    "search": [...],
    "columns": [...],
    "form": [...]
  }
}

运行时引擎读这份 JSON,动态渲染出搜索栏、表格、表单。没有代码文件生成

优点

  1. 改配置即生效:改个字段标签,改 JSON,页面直接变,不用发布
  2. 页面和代码解耦:一份协议驱动一个页面,改一处即可
  3. 代码量稳定:100 个页面 = 100 份 JSON + 1 个运行时引擎,不会膨胀
  4. 在线可调:上线后业务方自己改配置,不用找开发
  5. 版本可控:协议是数据,可以存版本、对比、回滚

问题

  1. 依赖运行时引擎:引擎挂了,所有页面都挂
  2. 复杂业务受限:引擎能力有限,超出能力范围的交互做不了
  3. 性能有开销:每次渲染要解析协议、动态构建组件
  4. 黑盒感:出问题排查难,因为页面不是代码,调试不直观
  5. 对开发者不友好:没有代码可看,只能看 JSON 配置

协议驱动的本质是"用数据描述页面"——页面是数据驱动的,不是代码写死的。


三、本质区别:产物是什么

一句话总结两种路线的本质:

路线 产物 维护方式
代码生成 代码文件 按代码方式维护(编译、合并、部署)
协议驱动 JSON 协议 按数据方式维护(改配置、保存、生效)

这个区别决定了 everything:

  • 代码生成的页面是"死的"——生成后就是一堆文件,改要改代码
  • 协议驱动的页面是"活的"——运行时按协议渲染,改协议就变

打个比方:

  • 代码生成 = 买精装房,交付后想改要砸墙
  • 协议驱动 = 买可移动隔断,随时调整布局

四、什么时候该用哪种?

两种路线没有绝对的好坏,只有适合不适合。

代码生成适合

  • 短期项目:快速出活,交付后不太改
  • 定制化需求高:生成的代码要大量二次修改
  • 团队有开发能力:能维护生成的代码
  • 对运行时性能要求高:不想要动态渲染开销
  • 交付源码:外包项目要给客户源码

协议驱动适合

  • 长期产品:页面经常调,业务经常变
  • 标准化程度高:大部分页面是 CRUD,交互不复杂
  • 业务人员参与:希望业务方自己配页面,不找开发
  • 多租户 SaaS:不同租户要不同的页面配置
  • 统一管控:所有页面风格、交互一致

五、我们的选择:协议驱动为主,代码生成为辅

Forge Admin 选的是协议驱动为主。但不是纯协议驱动——复杂业务场景下,也支持代码生成下载。

为什么选协议驱动?

因为 Forge 的定位是企业长期演进的后台系统,不是短期交付的外包项目。

企业后台的特点是:

  1. 页面多但模式相似:客户、合同、订单、报销、采购,80% 是 CRUD
  2. 经常调整:加字段、改标签、调搜索条件,几乎每周都在改
  3. 多租户:不同租户可能有不同的页面配置
  4. 统一风格:所有页面交互一致,不能每个开发自己发挥

这些特点正好适合协议驱动。如果用代码生成,100 个页面 = 600 个文件,每次改字段都要动五六个文件,长期维护成本太高。

协议驱动的核心设计

Forge 的协议分两层:

modelSchema(数据模型协议)
  ├── 字段定义:name、type、label、validation
  ├── 字典关联:dictType
  └── 约束:required、unique、length

pageSchema(页面协议)
  ├── searchSchema:搜索栏配置
  ├── columns:表格列配置
  ├── editSchema:表单配置
  └── apiConfig:接口配置

运行时引擎(AiCrudPage 组件)读这两层协议,动态渲染出完整页面。

modelSchema + pageSchema  →  AiCrudPage 组件  →  完整 CRUD 页面

改一个字段标签?改 pageSchema 里的 label,保存,页面立刻变。不用改代码,不用发布。

代码生成作为补充

纯协议驱动做不了复杂业务。所以 Forge 也支持下载代码包

AI 生成配置 JSON(AiCrudConfig)
   ↓
Velocity 模板渲染
   ↓
规范代码包下载
   ↓
二次开发

但这里的代码生成和传统代码生成有本质区别:

对比 传统代码生成 Forge 的代码生成
生成时机 配完就生成 简单业务不生成,复杂业务才下载
生成目的 生成即最终代码 生成是二次开发的起点
和协议关系 先有协议,协议可继续用,代码是补充
改字段 改代码 改协议,协议驱动页面;下载的代码另行维护

简单业务走协议,复杂业务走代码。两者不冲突,按业务复杂度选。


六、协议驱动的工程挑战

选了协议驱动不代表万事大吉,它有自己的工程难题。

1. 协议设计要稳定

协议是所有页面的基础。协议改了,所有页面都可能受影响。

所以协议设计要:

  • 向前兼容:新增字段不能破坏旧协议
  • 版本管理:协议要有版本号,支持灰度升级
  • 文档完善:每个字段什么意思、什么类型,要写清楚

2. 运行时引擎要强大

协议驱动的能力上限 = 运行时引擎的能力上限。

引擎支持什么组件、什么交互、什么校验,决定了协议能表达什么页面。引擎做不了的,协议再怎么配也没用。

所以引擎要:

  • 组件丰富:输入、下拉、日期、开关、上传、富文本……
  • 扩展机制:业务自定义组件能注册进引擎
  • 事件系统:字段联动、显隐控制、异步数据源
  • 性能可控:大表单、大表格不能卡

3. 调试要可视化

协议是 JSON,出问题排查比代码难。

所以要有:

  • 预览能力:配完即看效果,不用发布
  • 协议对比:改了什么,前后对比
  • 错误提示:协议哪里配错了,引擎要报出来

4. 降级方案

引擎挂了怎么办?协议解析失败怎么办?

要有降级:

  • 协议解析失败 → 显示原始 JSON 或错误提示
  • 引擎组件缺失 → 显示占位符
  • 接口超时 → 显示重试按钮

七、协议驱动的多租户优势

多租户场景下,协议驱动有一个代码生成做不到的优势:不同租户不同的页面配置

租户 A 的客户管理页面 → 使用协议版本 1
租户 B 的客户管理页面 → 使用协议版本 2(加了自定义字段)

如果用代码生成,不同租户要不同的代码分支,维护噩梦。

协议驱动下,协议是数据,按租户存不同版本,运行时按租户加载。代码只有一份,页面因租户而异。

这是 SaaS 产品选协议驱动的核心理由之一。


八、总结:选哪种路线,取决于你的产品定位

你的产品定位 建议路线
短期交付外包项目 代码生成
开源脚手架(用户要源码) 代码生成
长期企业后台产品 协议驱动
多租户 SaaS 平台 协议驱动
低代码平台(业务人员使用) 协议驱动
混合场景 协议驱动为主 + 代码生成为辅

代码生成和协议驱动不是对立的,是互补的。Forge 选了"协议为主 + 代码为辅"的混合路线,是因为它的定位是长期演进的企业后台。

选路线时别问"哪个更好",要问"我的产品 3 年后会变成什么样"。 如果 3 年后你的页面会从 10 个涨到 100 个,每个页面都要频繁调整,协议驱动大概率更适合。如果 3 年后你的项目交付完就走,代码生成就够了。


体验协议驱动的低代码页面

你们公司的低代码平台是生成代码还是协议驱动?踩过什么坑?评论区聊聊。