平台 · 架构
快速开发平台不是脚手架:我们做了三年后的取舍
快速开发平台最容易死在「能生成」和「能维护」之间。渤溢云拓 CTO 曹昕讲企业级快速开发平台的架构取舍、三个关键决定与四种绝不能自动化的能力。
“帮我快速生成一个后台”——这个需求我们做了三年,前后重构两次。
第一次做成了脚手架:命令行跑一下,生成 CRUD 代码,改改就能用。前两个月很爽,第六个月开始失控:每个项目都在脚手架基础上魔改,升级一次要合并几十个项目的差异。
第二次做成了平台:模块化、可插拔、有明确的扩展点。今天回头看,真正的难点从来不是“怎么生成代码”,而是“生成之后怎么活下去”。
一、先分清三个东西
行业里把很多概念混在一起,我们内部先做了切分:
| 概念 | 解决什么 | 典型形态 |
|---|---|---|
| 脚手架 | 项目从 0 到 1 的骨架 | 模板工程、代码生成器 |
| 组件库 | 重复 UI / 通用能力 | 基础组件、工具类 |
| 快速开发平台 | 长期演进下的一致性 | 模块体系 + 扩展点 + 治理规则 |
前两个是效率工具,第三个是架构资产。把三者混为一谈,就会出现“每个项目都能跑,但没有一个能一起升级”的局面。
二、我们的分层
平台分五层,越往下越稳定:
业务模块层 ← 各业务线自己的模块,允许差异
通用能力层 ← 权限、文件、消息、支付、字典
框架层 ← 统一响应、异常、事务、多租户、审计
网关层 ← 路由、鉴权、限流、日志
基础设施层 ← 缓存、搜索、任务调度、存储
原则:上层可以依赖下层,下层绝不知道上层。 这条规则听起来理所当然,但真正守住它的团队很少——最常见的破口是“框架层里加了一个业务判断”,从此框架不再通用。
三、三个关键取舍
取舍一:生成“接口和骨架”,不生成“业务逻辑”
我们最早尝试过连业务逻辑一起生成。结论是错的。
生成的 CRUD 逻辑一旦被改,就和生成器脱钩了:下次重新生成会覆盖掉改动,不重新生成又拿不到修复。最后变成了一个没人敢碰的黑盒。
现在的做法:生成器只生成确定的、机械的部分——实体、表结构映射、基础接口、权限声明、前端表单骨架。所有带业务判断的地方留空,并加注释标明“此处需人工实现”。
能被重新生成而不丢失任何东西的代码,才值得被生成。
取舍二:模块之间只通过 API 通信,不共享表
同一个数据库里,模块 A 直接查模块 B 的表,是埋给未来的雷。
我们强制约定:跨模块只走 API 接口(哪怕是单体部署,也走内部 API 门面)。这样做有成本——多一层调用、需要定义 DTO、要处理事务边界——但换来的是模块可以独立演进、独立拆分、独立测试。
一个真实的收益:后来要把某个模块拆成独立服务时,改动量比预期小了将近一半,因为边界本来就是清楚的。
取舍三:升级靠“向后兼容”,不靠“重新生成”
平台迭代必然带来框架升级。我们给自己定的规则:
- 框架层只增不改,破坏性变更走大版本号;
- 提供迁移脚本而不是“请手动改”;
- 每个大版本维护一个官方示例工程,用来验证升级路径。
升级这件事,必须在设计阶段就想好。事后补的升级方案,基本都等于重写。
四、绝对不能自动化的四件事
平台越强,越要清楚它的边界。我们明确不做自动化的四件事:
- 数据权限模型:谁能看哪些数据,涉及合规与业务判断,必须人工设计;
- 事务边界:一个业务动作跨几个聚合,必须由懂业务的人定;
- 状态机:订单、审批、工单的流转规则,生成器给不出正确答案;
- 对外接口契约:一旦发布就是承诺,不能由工具随意改动。
这四件事恰好是最容易出错、也最难排查的地方。平台的价值是让人把精力放在这四件事上,而不是把人从这四件事里解放出来。
五、度量:怎么判断平台是不是真的有用
不要用“生成了多少行代码”衡量。我们用三个指标:
| 指标 | 含义 |
|---|---|
| 新项目启动耗时 | 从建仓到第一个业务接口跑通 |
| 升级冲突率 | 框架升级时每个项目需要人工改动的文件数 |
| 重复实现率 | 同一能力在多个模块被重复实现的比例 |
第一个指标看效率,后两个看债务。平台做得好,第二个和第三个应该是持续下降的。
六、最后
三年下来,我最大的体会是:
快速开发平台的成功标准,不是“开发得多快”,而是“三年后还能一起升级”。
效率是当下的,架构是未来的。只追求前者的平台,最后都会变成一堆各自为战的项目;把后者做扎实,前者的收益才是可持续的。
快速开发平台和低代码平台是一回事吗?
不完全。低代码面向业务人员,强调可视化配置;快速开发平台面向研发团队,强调架构一致性和工程效率。两者可以共存,但目标用户和能力模型不同。
小团队需要自建快速开发平台吗?
不需要,直接用成熟框架。等你出现“多个项目重复实现同一能力”和“升级互相牵制”这两个信号时,再考虑抽象。
代码生成会不会让程序员能力退化?
取决于生成什么。生成机械劳动不会;如果连业务判断都生成,那确实会。所以边界要划在“确定的部分”。