# 低代码平台的两种路线:生成代码还是协议驱动?我们选了后者 > 低代码喊了这么多年,很多人还是没搞清楚:有的平台"生成一坨代码",有的平台"运行时渲染配置"。这不是技术选型的差异,是产品哲学的差异。这篇讲清楚两种路线的本质区别,以及我们为什么选了协议驱动。 低代码平台看着都差不多:拖拽表单、配置字段、生成页面。但如果你扒开底层,会发现两种完全不同的技术路线。 一种是**代码生成**:你配的东西,最终变成一堆代码文件,下载、合并、部署。 一种是**协议驱动**:你配的东西,最终变成一份 JSON 协议,运行时引擎按协议渲染页面。 这两种路线看起来都能"搭页面",但长期演进下去,差别巨大。这篇就把这两种路线彻底讲清楚。 --- ## 一、代码生成路线:产物是代码 ### 怎么工作的 代码生成路线的核心流程: ```text 在线配置表单/页面 ↓ 模板引擎渲染(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 ### 怎么工作的 协议驱动路线的核心流程: ```text 在线配置表单/页面 ↓ 保存为 JSON Schema 协议 ↓ 运行时引擎读取协议 ↓ 动态渲染页面 ↓ 用户直接使用 ``` 你配了一个客户管理页面,平台保存的是: ```json { "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 的协议分两层: ```text modelSchema(数据模型协议) ├── 字段定义:name、type、label、validation ├── 字典关联:dictType └── 约束:required、unique、length pageSchema(页面协议) ├── searchSchema:搜索栏配置 ├── columns:表格列配置 ├── editSchema:表单配置 └── apiConfig:接口配置 ``` 运行时引擎(`AiCrudPage` 组件)读这两层协议,动态渲染出完整页面。 ```text modelSchema + pageSchema → AiCrudPage 组件 → 完整 CRUD 页面 ``` 改一个字段标签?改 `pageSchema` 里的 `label`,保存,页面立刻变。不用改代码,不用发布。 ### 代码生成作为补充 纯协议驱动做不了复杂业务。所以 Forge 也支持**下载代码包**: ```text AI 生成配置 JSON(AiCrudConfig) ↓ Velocity 模板渲染 ↓ 规范代码包下载 ↓ 二次开发 ``` 但这里的代码生成和传统代码生成有本质区别: | 对比 | 传统代码生成 | Forge 的代码生成 | |------|-------------|-----------------| | 生成时机 | 配完就生成 | 简单业务不生成,复杂业务才下载 | | 生成目的 | 生成即最终代码 | 生成是二次开发的起点 | | 和协议关系 | 无 | 先有协议,协议可继续用,代码是补充 | | 改字段 | 改代码 | 改协议,协议驱动页面;下载的代码另行维护 | **简单业务走协议,复杂业务走代码**。两者不冲突,按业务复杂度选。 --- ## 六、协议驱动的工程挑战 选了协议驱动不代表万事大吉,它有自己的工程难题。 ### 1. 协议设计要稳定 协议是所有页面的基础。协议改了,所有页面都可能受影响。 所以协议设计要: - **向前兼容**:新增字段不能破坏旧协议 - **版本管理**:协议要有版本号,支持灰度升级 - **文档完善**:每个字段什么意思、什么类型,要写清楚 ### 2. 运行时引擎要强大 协议驱动的能力上限 = 运行时引擎的能力上限。 引擎支持什么组件、什么交互、什么校验,决定了协议能表达什么页面。引擎做不了的,协议再怎么配也没用。 所以引擎要: - **组件丰富**:输入、下拉、日期、开关、上传、富文本…… - **扩展机制**:业务自定义组件能注册进引擎 - **事件系统**:字段联动、显隐控制、异步数据源 - **性能可控**:大表单、大表格不能卡 ### 3. 调试要可视化 协议是 JSON,出问题排查比代码难。 所以要有: - **预览能力**:配完即看效果,不用发布 - **协议对比**:改了什么,前后对比 - **错误提示**:协议哪里配错了,引擎要报出来 ### 4. 降级方案 引擎挂了怎么办?协议解析失败怎么办? 要有降级: - 协议解析失败 → 显示原始 JSON 或错误提示 - 引擎组件缺失 → 显示占位符 - 接口超时 → 显示重试按钮 --- ## 七、协议驱动的多租户优势 多租户场景下,协议驱动有一个代码生成做不到的优势:**不同租户不同的页面配置**。 ```text 租户 A 的客户管理页面 → 使用协议版本 1 租户 B 的客户管理页面 → 使用协议版本 2(加了自定义字段) ``` 如果用代码生成,不同租户要不同的代码分支,维护噩梦。 协议驱动下,协议是数据,按租户存不同版本,运行时按租户加载。代码只有一份,页面因租户而异。 这是 SaaS 产品选协议驱动的核心理由之一。 --- ## 八、总结:选哪种路线,取决于你的产品定位 | 你的产品定位 | 建议路线 | |-------------|----------| | 短期交付外包项目 | 代码生成 | | 开源脚手架(用户要源码) | 代码生成 | | 长期企业后台产品 | 协议驱动 | | 多租户 SaaS 平台 | 协议驱动 | | 低代码平台(业务人员使用) | 协议驱动 | | 混合场景 | 协议驱动为主 + 代码生成为辅 | 代码生成和协议驱动不是对立的,是互补的。Forge 选了"协议为主 + 代码为辅"的混合路线,是因为它的定位是长期演进的企业后台。 **选路线时别问"哪个更好",要问"我的产品 3 年后会变成什么样"。** 如果 3 年后你的页面会从 10 个涨到 100 个,每个页面都要频繁调整,协议驱动大概率更适合。如果 3 年后你的项目交付完就走,代码生成就够了。 --- **体验协议驱动的低代码页面**: - 后台演示:http://www.dlforgelab.com:8084/forge/login (admin / 123456) - Gitee:https://gitee.com/ForgeLab/forge-admin - GitHub:https://github.com/yaomindong1996/forge-admin > 你们公司的低代码平台是生成代码还是协议驱动?踩过什么坑?评论区聊聊。