一、我接盘了一个没人想接的项目
同事离职了。他维护的一套QT后端服务,落到了我头上。
我是做Java的,之前没有接触过QT。
这套服务是模拟数据管理平台的一部分——实验数据,数据从现场硬件(CAN 总线、Modbus、TCP)采进来,同步到数据库,再供前端和仿真系统调用。
它由 5 个模块拼成:一个 Vue 前端、两个 Java 后端(Spring Boot),还有两个 C++/Qt 后端——一个跑 Windows,一个跑麒麟 Linux。
没错,同样的业务,写了两遍。
我拿到的是 Linux 那份。规模:
| 指标 | 数字 |
|---|---|
| 业务代码 | 约 5.4 万行(不含第三方库) |
| Controller | 29 个 / 14,925 行 |
| Service | 93 个 / 7,677 行 |
| DAL(数据访问层) | 70 个 / 11,208 行 |
| 数据库 | 达梦 + MySQL 双库 |
| 技术栈 | C++17 / Qt 6 / oatpp / WebSocket / Modbus / CAN |
打开代码的第一天,我看到的是一片"只有写它的人才懂"的风景:
| 乱象 | 实锤 |
|---|---|
| 同一个业务三个名字 | DataKzg1、DataKzg2、kzgController——KZG 到底是什么?离职了,没人能问了 |
| 临时代码直接留在主线 | TempExpertScore、TempSimulationPredict、TempStatisticalEvaluation、TempGroupCourse 四个 Temp 前缀类 |
| 拼写错误 | ExternalFeatureRelation**Servies**、data**DisPatCher**、token**creatro**andverifier |
| 架构失衡 | Controller 1.5 万行,比 Service(7.7k)多一倍——典型的"写满 Controller"风格 |
| 死代码不清理 | main.cpp 里 kzgController、autoRun、TcpCanClient 整块注释掉,还留着 |
| 手动注册一切 | main.cpp 前 260 行:30 行 include + 80 行逐个 addController |
这就是第一反应:这代码,扔给谁都没法直接干。
但接下来我做的事,跟过去不一样了——我没有硬着头皮人肉啃,而是先想了一个问题:
这套代码扔给 AI 之前,它需要知道什么?
二、扔给 AI 之前,我先给它写了张"入职地图"
AI 再强,它对这个世界一无所知。它不知道:
- 这个项目有哪些模块、代码都在哪
- 技术栈是哪个版本、用的什么框架
- 哪些红线碰都不能碰
- 项目自己的编码规范长什么样
不告诉它这些,扔进去的每一份代码它都会用"标准做法"去理解——而离职代码恰恰最不标准。
所以第一步,我写了一份 CLAUDE.md,相当于给 AI 的入职文档。里面写了这些:
1. 模块地图(这个项目是干什么的、有哪些部分)
vue/ 前端(Vue 3 + TypeScript)
SyncServer/ Java,硬件数据同步(CAN/Modbus → MySQL)
relap/ Java,数据估算、专家评分、综合评价
war/DataProcessingApi/ C++/Qt 后端(Windows)
war/kylin/DataProcessApiLinux/ C++/Qt 后端(麒麟 Linux)
2. 技术栈(AI 乱猜的根源,都钉死)
C++17 / Qt 6 / CMake 3.16+
Web 框架:oatpp + oatpp-websocket
数据库:Qt Sql(达梦 + MySQL),连接池 DatabasePool
通信:WebSocket / TCP / Modbus TCP / CAN / SSE
JWT Token 拦截器(interceptor/)
3. 红线(这些写清楚了,AI 才不会乱动)
- 领域:实验数据管理,准确性至关重要
- 生产代码路径中不使用 mock 数据
- 数据库 schema 变更需用户明确确认后方可执行
- 仿真集成:未经明确指令不修改仿真调用逻辑
- 未经明确指令不修改 JWT 拦截器(interceptor/)和 CAN 总线通信逻辑
4. 编码规范(让 AI 的产出和现有代码一个风格)
- C++17,controller → service → dal 三层架构,不跨层调用
- 数据库操作通过 dal/DatabasePool 连接池,不直接创建连接
- Windows/Linux 平台差异隔离在各自目录,共用逻辑不重复实现
- 未经明确批准不引入新依赖
这份地图的价值,是让 AI 从"一个什么都不知道的实习生"变成"一个看过入职手册的新员工"。它还是不会写项目,但至少不会在红线边上乱踩了。
三、然后,我才开始扔:一个任务走完全流程
地图画好,开始干活。这个项目里我推进过的改造任务都按同一套工作流走——每个任务三个文件,按版本管理,提交 SVN:
需求提示词/
├── 同步数据改造V1.0.md # 需求文档
├── 同步数据改造V1.0-执行计划.md # AI 生成,我确认
├── 同步数据改造V1.0-测试用例.md # 测试角色产出
├── 数据上报改造V1.0.md
├── 数据上报改造V1.0-执行计划.md
├── 预测数据调整V1.0.md
├── 预测数据调整V1.0-执行计划.md
├── 查询改造V1.0.md
└── 查询改造V1.0-执行计划.md
流程是固定的:
1. 需求文档(我写:要改什么、为什么改)
↓
2. 项目经理角色 → 读需求 → 生成执行计划
↓
3. 我确认:改哪几个文件、有没有风险、会不会碰到红线
↓
4. 全栈开发角色 → 按执行计划改代码
↓
5. 测试角色 → 生成测试用例 → 执行 → 出报告
这套工作流跟我在前两篇里讲的是同一套——提示词不只是写,要管。在这个项目里它的意义尤其大:因为接盘的是离职代码,改动必须可追溯。需求 → 执行计划 → 测试用例 → 测试报告,一条链下来,出了问题知道是谁改的、为什么改的、当时测过什么。
四、AI 干得好的三件事
4.1 快速梳理三层架构
离职代码最让人头疼的是"不知道从哪看起"。Controller 1.5 万行,70 个 DAL 类,调用链盘根错节。
但 AI 读代码的速度是人类的几十倍。给它一个入口文件,它能快速画出 controller → service → dal → 数据库 的调用链,还能标出哪个 Controller 调了哪些 Service、哪些 DTO 是共享的。
我做的: 确认它画的链路对不对。AI 看代码不会漏,但它不理解业务——所以"这条链路合理吗"还是要人来判断。
4.2 严格按规范改代码
有 CLAUDE.md 之后,AI 的产出是"这个项目的代码",不是"标准 C++"。
- 让它加一个接口,它会自动走 controller → service → dal 三层,不会把业务逻辑堆在 Controller
- 数据库操作走
DatabasePool连接池,不会自己new一个连接 - Windows/Linux 的差异代码分开放,不会写个
#ifdef糊在一起
这些不是 AI 天生会的,是 CLAUDE.md 里写死的。没有这份规范,AI 给你的是"看起来没错但风格完全不一样"的代码——在离职代码里混进这种代码,以后没人看得懂。
4.3 把测试补上了
这个项目以前是没人写测试的。改代码靠人肉点。
用上 AI 之后,每个改造任务都带测试用例。测试角色会对着执行计划生成用例,覆盖正常路径 + 边界。在一个数据准确性至关重要的项目里,这是实打实的价值——你永远不想看到改完数据同步逻辑后,某条数据悄悄错了。
五、AI 干不了的四件事
说完了快,说笨。这些是接盘离职代码时,AI 最让我失望、但也最让我清醒的地方。
5.1 它判断不了哪些是死代码
TempExpertScore、TempSimulationPredict——这些 Temp 前缀类,到底是"临时代码,验收后删"还是"临时先用,其实生产在跑"?AI 分不出来。它只看到"这个类被 include 了,有路由,能编译",就会老老实实维护它。
删不删,只有你问过离职同事、或者翻了业务确认过,才知道。 AI 不敢删,你不敢不查。
5.2 它理解不了业务潜规则
DataKzg1 和 DataKzg2 的区别是什么?为什么 ExternalFaultData 要单独一个 Controller 而不是复用现有的?为什么某些数据要用 SSE 推送而不是轮询?
这些问题的答案不在代码里,在业务里。AI 能告诉你"这两个 Controller 结构高度相似",但它不会告诉你"其实应该合并成一个"。
5.3 它不认国产化的坑
达梦数据库、麒麟 OS、国产化替代——这套环境里有大量"标准做法之外"的坑:
- 达梦的 SQL 方言和 MySQL 有差异,同样的语句两个库行为不同
- 麒麟上的 CMake 交叉编译、动态库路径、
dexp备份工具的参数
AI 按标准做法生成的代码,在这套环境里可能直接编译不过、连不上库。这些坑只有在这套环境里踩过的人知道。
5.4 它会被命名误导
ExternalFeatureRelationServies(拼错的 Service)、dataDisPatCher(大写 C)、tokencreatroandverifier——AI 会把它们当成独立的新模块去理解,而不是"一个拼写错误的既有类"。
这不是 AI 笨。是命名没有规律可循的时候,再强的模型也只能瞎猜。你不可能靠 AI 弥补命名的混乱,这需要人来定规范、做一次清理。
六、接盘离职代码,AI 是加速器,不是导航仪
第三篇里我说过:AI 能覆盖标准场景的 70%,剩下 30% 的坑,是你的价值。
接盘存量代码,这个比例要倒过来看:
- AI 帮你兜住的是那 70% 的体力活——读代码、画调用链、按规范改、写测试
- 但那 30% 的决策,全是你——哪个
Temp类能删、Kzg1和Kzg2是不是一回事、达梦的坑怎么绕
接盘离职代码,最难的根本不是看懂代码,是知道哪些能删、哪些不能动。AI 能帮你改代码,但"敢不敢删"这件事,只有你能决定。
离职代码的混乱不是 bug,是历史。AI 可以接管代码,但接管不了离职同事脑子里那 30% 的上下文。
所以别再问"能不能把离职代码扔给 AI 让它全自动接手"了。答案是:
能扔,但得先把入职地图画好,然后你自己得坐稳驾驶位。
一句话总结:AI 是工具,不是独立的开发人员。能不能用好工具,关键还是在人。
上一篇:第一次把整个项目交给 AI:比我想的快,也比我想的笨
下一篇预告:【我让 AI 写测试,结果它比我还会偷懒】