做个平台这件事,最初是被一套没人维护的模板逼出来的。某个周一早上,线上一个订单服务突然报错,查了大半天,根因是两周前初始化新服务时,从旧脚手架复制来的配置里带着一个已经被移除的扩展点。那条配置在旧项目里没有触发问题,换到新项目就成了定时炸弹。复盘会上大家沉默了很久,因为类似的“复制粘贴事故”已经不是第一次了。也就是从那天起,我决定认真想想 HagiCode Soul 应该怎么设计。
HagiCode Soul 的定位,在我看来不是低代码平台,也不是什么业务中台。它更像一层“工程生成底座”:当你准备开发一个新模块、一个新微服务,或者一套标准化的 API 工程时,它能帮你把骨架代码生成、依赖版本锁定、基础设施配置注入这些事,从“靠记忆复制”变成“靠模型生成”。服务端、前端、平台工程师都能在这套流程里找到适合自己的部分,前提是你愿意花一两天时间,把最初散落的模板整理成可生成的结构。
这篇文章适合谁看?一句话:如果你现在还在用“把上次那个项目拷过来改一改”的方式搭工程,或者团队里已经有多个脚手架但没人维护,那这篇文章应该能给你一条相对清晰的演进路线。我会从最初的需求萌芽讲起,把平台化过程中最关键的技术决策、踩过的坑、以及能直接落地的实操路径都摊开来说。
1. 需求萌芽与平台化的动机
1.1 模板维护不下去,是平台化最真实的起点
我以前也觉得,项目初始化不就是复制个模板吗?直到团队里同时存在 Go、Java、Node.js 三套服务端模板,再加上一个 React 前端模板,问题才彻底暴露出来。
先说依赖版本。每套模板都由不同的人维护,维护者离职后模板几乎进入冻结状态。新项目初始化时,大家默认“模板里的依赖应该是公司统一标准”,实际上模板可能已经落后生产环境一年甚至更久。Go 模板里有同学手动升级过 gin,Java 模板里还在用老一套配置,Node 模板生成的工程 lint 规则和另外两套风格不一致。代码评审的时候,最耗费精力的往往不是业务逻辑,而是“这个依赖版本是谁定的、为什么模板里是这样”。
更隐蔽的问题是约定没有文档。早先约定所有服务必须实现统一的 health check 接口,但代码模板不强制,新服务忘写的概率极高。平台化不是为了让代码生成得更多,而是为了让“默认约定”真正变成“默认被强制执行”。这一点在我后来的架构设计里反复出现过:先保证默认动作正确,再考虑提供灵活覆盖。
1.2 从“复制粘贴”走向平台化的三个核心目标
当时我们定了三件事,作为后续所有技术决策的判断标准。
第一,统一入口。不管创建什么类型的新服务,不能再靠“问老员工要模板”。必须有唯一入口,进去之后通过选择或参数配置拿到工程,模板的版本、更新记录、变更内容全部可见可回溯。
第二,结果可审计。代码生成器很容易变成一个黑盒:输入几个参数,吐出一坨代码。一旦生成的代码有问题,你根本不知道是哪条规则、哪个模板片段导致的。所以平台生成的内容必须能对应到具体的模板文件和元数据定义,发现问题能顺着链路定位。
第三,不被锁定。生成工程之后,开发者应当能自由修改生成结果,平台不能搞“二次生成覆盖代码”的骚操作。我们只负责生成初始骨架和提供增量升级能力,一旦进入正常开发阶段,项目就是开发者的,平台不介入也不限制。
1.3 Soul 这个名字背后,平台到底在解决哪一层问题
HagiCode 早期只是我一个内部脚本工具的名字,后来拆成两个概念:HagiCode 是代码生成引擎本身,Soul 是围绕引擎建立的“服务定义与编排层”。为什么需要单独一层 Soul?
因为大多数团队的代码规范问题,根源不在“代码怎么写”,而在“服务边界不统一”。同样一个订单服务,A 同学重构了项目结构,B 同学按自己的习惯加了一层 repository,C 同学把配置全塞在 application.yml 里。每个都合理,但放在一起,整个团队的知识传递成本就很高。Soul 层做的事情,是用一整套领域描述规范,把服务对外暴露的接口、依赖的外部组件、环境配置项、监控告警方式都结构化地表达出来。代码可以由模板生成,但服务定义先于代码存在。这个“定义先行”的思路,直接影响平台后续形态。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心架构设计:HagiCode Soul 为什么采用元数据驱动
2.1 字符串拼接式的生成器,为什么走到头就会崩
很多人第一次写代码生成器,都是拿模板引擎拼字符串:把变量塞进一个写死的模板文件里,循环输出 controller、service、repository。早期我也这么干,确实很爽,一天就能拼出一个能跑的生成器。
但等到模板数量变多,你会发现一个致命问题:模板之间是有依赖的。比如生成一个带数据库表的 CRUD 服务,涉及实体类、Mapper 接口、建表 SQL、API 路由、配置项五处改动。用字符串拼接,你等于手工维护五处关联规则的同步。今天加一个字段,明天可能就忘了改建表 SQL。代码里数量少的时候勉强能靠人肉盯住,一旦出现几十个不同业务模型,维护量直接爆炸。
从这个角度看,纯粹的模板字符串拼接不是“简单”,而是“把问题延期了”。真正该做的,是先把业务模型抽象出来,再基于模型统一驱动所有相关代码的生成。
2.2 三段式流水线:Metadata → IR → 目标代码
HagiCode Soul 的核心引擎参考了编译器设计里非常经典的三段式思路,把生成过程拆成三个层级。
- Metadata(原始描述):开发者或平台界
