ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

老系统迁移无文档?逆向工程生成PRD实战指南

老系统迁移无文档?逆向工程生成PRD实战指南 1. 接手一个没有文档的老系统到底难在哪接手一个跑了五六年甚至更久的老系统最让人头疼的从来不是代码本身有多复杂而是你根本不知道它到底在干什么。需求文档没有。接口文档过时了。数据库设计说明当初那个人可能早就离职了。你面对的是一堆能跑但没人敢动的代码以及业务方一句轻飘飘的“你先熟悉一下”。我最近就接了这么一个活。一套基于 Spring Boot 和 Vue 的前后端分离系统后端大概有十几个模块前端页面五六十个数据库表两百多张。业务方说要迁移到新的技术栈让我先出一份迁移 PRD。问题是原系统连一份像样的需求说明都找不到只有代码和数据库还在老老实实地跑着。这种情况下代码本身就是最可靠的信息源。代码不会撒谎它忠实地记录了业务逻辑、数据流向、边界条件和历史遗留的各种补丁。逆向出一份能用的迁移 PRD本质上就是通过代码、数据库、运行日志、前端交互这些“物证”反推出系统到底在做什么、为什么要这么做、迁移时哪些必须保留、哪些可以优化。这件事适合谁来参考如果你正在接手老系统、准备做系统迁移、需要补全缺失的文档或者单纯想搞清楚一套陌生代码的业务全貌那这套方法应该能帮到你。我不打算讲什么高大上的理论就说说我实际是怎么一步步把代码“翻译”成 PRD 的。2. 逆向 PRD 的整体思路与拆解策略2.1 为什么不能直接照着代码写文档很多人第一反应是既然有代码那就照着代码把每个接口、每个方法都写一遍不就行了我试过这条路走不通。代码是给机器执行的它关注的是实现细节PRD 是给人看的它关注的是业务规则和用户价值。你照着代码写出来的东西顶多算一份“代码说明书”业务方看不懂开发看了也没法判断迁移时哪些逻辑必须保留。逆向 PRD 的核心目标不是复述代码而是还原业务意图。比如代码里有一段复杂的折扣计算逻辑嵌套了七八层 if-else你要输出的不是“当 A 且 B 且 C 时执行 D”而是“该商品在特定促销场景下的折扣规则优先级从高到低依次为……”。前者是代码逻辑后者是业务规则。2.2 逆向工程的三条主线我习惯把逆向工作分成三条并行推进的主线每条线解决不同维度的问题。第一条线是数据主线。数据库是系统最底层的真相来源。表结构、字段类型、索引、外键、触发器、存储过程这些能告诉你系统管理了哪些实体、实体之间是什么关系、哪些数据是核心资产。我一般会先从数据库入手把 ER 图大致画出来心里有个底。第二条线是接口主线。后端对外提供的 API 是业务能力的直接体现。通过分析 Controller 层的路由、请求参数、响应结构可以快速梳理出系统对外暴露了哪些功能。这里要注意区分对内接口和对外接口有些接口是给前端页面用的有些是给第三方系统调用的迁移时的处理策略完全不同。第三条线是交互主线。前端页面是业务人员每天实际操作的界面它反映了真实的用户旅程。通过 Vue 的路由配置和页面组件可以还原出用户从登录到完成核心业务的完整路径。这条线能帮你验证前两条线梳理出来的业务逻辑是否符合实际使用场景。2.3 工具选型与准备工欲善其事必先利其器。我用的工具组合比较简单都是日常开发中顺手能拿到的。工具用途备注IntelliJ IDEA代码分析、调用链追踪社区版够用配合插件看 Spring 注解Navicat / DBeaver数据库结构导出、数据采样导出建表语句和样本数据Postman / curl接口探测与验证对关键接口发请求观察真实响应Chrome DevTools前端交互分析、网络请求抓取看页面实际调了哪些接口PlantUML / draw.io画流程图、ER 图、状态图用于 PRD 中的可视化表达注意如果系统还在运行尽量在测试环境操作避免对生产数据造成影响。如果只有生产环境任何数据库查询都要加 limit不要跑全表扫描。3. 从数据库反推业务实体与核心规则3.1 表结构分析先找核心表再看关联表拿到数据库后不要一上来就一张张表看。先按数据量排序数据量大的表通常是业务核心表。比如订单表、用户表、商品表这些往往是系统的骨架。然后再看关联表也就是那些只有几个字段、主要用来维护多对多关系的表它们能告诉你实体之间的业务关系。我一般会执行这样几条 SQL 来快速摸底-- 查看所有表的数据量MySQL 示例 SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema your_db ORDER BY table_rows DESC; -- 查看表的注释和引擎 SELECT table_name, table_comment, engine FROM information_schema.tables WHERE table_schema your_db; -- 查看字段注释 SELECT table_name, column_name, column_type, column_comment FROM information_schema.columns WHERE table_schema your_db ORDER BY table_name, ordinal_position;字段注释非常关键。很多老系统虽然文档缺失但数据库字段的注释往往还在这些注释就是最原始的需求描述。如果连注释都没有那就只能靠字段名和实际数据来推断。3.2 从状态字段反推业务流程老系统里最常见的业务逻辑载体就是状态字段。比如订单表里有个status字段取值可能是 0、1、2、3、4。你要做的就是搞清楚每个状态代表什么以及状态之间是怎么流转的。我的做法是先查这个字段的所有 distinct 值然后结合代码里对这个字段的判断逻辑还原出完整的状态机。比如SELECT status, COUNT(*) FROM orders GROUP BY status;假设结果是 0 有 100 条1 有 5000 条2 有 30000 条3 有 200 条4 有 50 条。那大概率 2 是正常完成状态1 是进行中0 是初始状态3 和 4 可能是取消或异常状态。再去代码里搜status 或status.equals的相关逻辑就能把状态流转图补全。3.3 数据采样与边界值发现光看表结构还不够一定要看真实数据。我习惯对每张核心表采样 100 条左右的数据重点观察几个东西字段的实际取值范围、空值情况、异常数据、以及那些看起来“不该存在”的数据。比如有一次我发现某个字段叫discount_rate类型是 decimal(5,4)注释写的是“折扣率”。但实际数据里既有 0.85 这样的值也有 85 这样的值。这说明系统在不同时期对折扣率的存储方式不一致迁移时必须做数据清洗和统一。实操心得采样时特别关注那些有默认值、允许为空、或者取值分布很奇怪的字段。这些往往是历史遗留问题的重灾区也是迁移 PRD 里必须单独说明的风险点。4. 从后端代码提取业务规则与接口契约4.1 Controller 层梳理对外能力清单Spring Boot 项目的 Controller 层是最容易入手的地方。每个RestController或Controller类基本对应一个业务模块类里面的RequestMapping、GetMapping、PostMapping方法就是具体的业务能力。我一般会写个简单的脚本把所有的路由信息提取出来整理成一张接口清单表# 在项目根目录下搜索所有 Controller 的映射注解 grep -r RequestMapping\|GetMapping\|PostMapping\|PutMapping\|DeleteMapping \ --include*.java src/main/java/然后把结果整理成表格包含模块、路径、HTTP 方法、请求参数、响应结构、以及初步判断的业务含义。这张表就是迁移 PRD 里“系统功能清单”的雏形。4.2 Service 层挖掘真正的业务逻辑Controller 层只是入口真正的业务规则在 Service 层。这里要重点关注几个东西事务边界、业务校验、计算逻辑、以及对外部系统的调用。事务边界能告诉你哪些操作必须原子性完成。比如“创建订单”和“扣减库存”如果在同一个Transactional方法里那迁移后也必须保证在同一个事务中否则会出现数据不一致。业务校验是 PRD 里必须写清楚的规则。比如“用户下单时如果账户余额不足则不允许下单”这种规则在代码里可能就是一个 if 判断但在 PRD 里要明确写成业务约束。计算逻辑是最容易在迁移中出错的地方。我遇到过一段运费计算代码里面用了大量的 BigDecimal 运算还涉及不同地区的费率表。这种逻辑在 PRD 里必须用公式和表格完整还原不能只写一句“按规则计算运费”。4.3 接口契约的逆向补全老系统的接口文档往往缺失或过时但接口契约是迁移时前后端联调的基础。我的做法是对每个核心接口用 Postman 或 curl 实际发一次请求把真实的请求参数和响应结构记录下来。# 示例探测一个查询接口 curl -X POST http://localhost:8080/api/order/query \ -H Content-Type: application/json \ -d {userId: 123, pageNum: 1, pageSize: 10}然后把响应 JSON 的结构整理成字段说明表标注每个字段的类型、含义、是否必填、以及可能的取值范围。这份表就是迁移 PRD 里“接口规格说明”的核心内容。注意有些接口有权限校验或签名验证直接请求可能返回 401 或 403。这时候需要从代码里找到鉴权逻辑构造合法的请求头或 token。如果实在无法直接调用就通过阅读代码来推断接口契约但要在 PRD 里标注“待验证”。5. 从前端交互还原用户旅程与页面逻辑5.1 Vue 路由分析还原功能入口Vue 项目的路由配置是还原用户旅程的最佳起点。打开router/index.js或router.js你能看到系统所有的页面入口和层级关系。// 典型的 Vue 路由配置 const routes [ { path: /order, component: Layout, children: [ { path: list, component: () import(/views/order/list), meta: { title: 订单列表 } }, { path: detail/:id, component: () import(/views/order/detail), meta: { title: 订单详情 } }, { path: create, component: () import(/views/order/create), meta: { title: 创建订单 } } ] } ]通过路由的meta.title和组件路径可以快速梳理出系统的功能模块和页面清单。如果路由配置里还有权限相关的meta.roles或meta.permissions那还能还原出不同角色的功能权限。5.2 页面组件分析提取表单字段与操作按钮每个 Vue 页面组件里表单字段和操作按钮直接反映了业务人员能做什么。我一般会重点看几个东西el-form或类似表单组件里的字段定义、el-table里的列定义、以及各种按钮的点击事件。表单字段对应的是业务实体的属性表格列对应的是业务人员最关心的信息按钮对应的是可执行的操作。把这些整理出来就是 PRD 里“页面功能说明”的素材。5.3 网络请求抓取验证前后端契约前端页面实际调用了哪些接口最准确的方式是用 Chrome DevTools 的 Network 面板抓取。打开页面操作一遍核心业务流程把所有的 XHR 请求记录下来。然后对照后端 Controller 的接口清单看看哪些接口被前端调用了哪些没有。没有被前端调用的接口可能是给第三方系统用的也可能是废弃的接口。这两种情况在迁移时的处理策略完全不同。实操心得抓取网络请求时注意区分开发环境和生产环境的接口地址。有些老系统在代码里硬编码了接口地址迁移时需要统一配置化。6. 常见问题与排查技巧实录6.1 代码与数据库不一致怎么办这是老系统逆向时最常见的问题。代码里写的字段和数据库实际字段对不上或者代码里的枚举值和数据库里的实际取值不一致。我的处理原则是以数据库的实际数据为准以代码的逻辑为参考。因为数据库是系统运行的结果代码可能改过但数据库没同步也可能数据库改过但代码没更新。遇到不一致的地方先在 PRD 里标注出来然后通过实际运行系统来验证哪个是正确的。6.2 接口无法直接调用怎么排查有些接口有复杂的鉴权、签名、或者依赖特定的请求上下文直接调用会失败。这时候可以分几步排查先看 Controller 方法上的注解有没有PreAuthorize、Secured之类的权限注解再看拦截器或过滤器里有没有全局的鉴权逻辑最后看请求参数里有没有必须的 token 或签名。如果实在无法直接调用就通过阅读代码来推断接口契约但在 PRD 里要明确标注“该接口契约基于代码分析未经实际验证”。6.3 业务规则藏在存储过程或定时任务里有些老系统会把核心业务逻辑放在数据库的存储过程里或者通过定时任务来执行。这些逻辑在代码里是看不到的必须单独排查。排查存储过程SELECT routine_name, routine_type, routine_definition FROM information_schema.routines WHERE routine_schema your_db;排查定时任务搜索代码里的Scheduled注解或者查看是否有 Quartz、XXL-JOB 等调度框架的配置。6.4 常见问题速查表问题现象可能原因排查方向处理建议接口返回 401缺少鉴权信息检查拦截器、过滤器、注解构造合法 token 或从代码推断数据字段对不上代码与数据库不同步对比代码实体与表结构以数据库实际数据为准业务逻辑找不到逻辑在存储过程或定时任务查 routines 表和调度配置单独整理成 PRD 附录前端页面报错接口地址或参数不匹配看 Network 面板和 Console记录实际请求与响应状态流转不清晰状态字段无注释查 distinct 值 代码判断还原状态机图避坑技巧逆向过程中一定要边分析边记录不要想着“等全部看完再写”。老系统的信息量很大看到后面很容易忘记前面的细节。我习惯用 Notion 或语雀建一个页面随时把发现的问题、疑点、待验证项记下来最后整理 PRD 时直接汇总。7. 迁移 PRD 的组装与输出要点7.1 PRD 应该包含哪些章节逆向出来的迁移 PRD和正常的需求文档结构不太一样。它更侧重“现状还原”和“迁移影响分析”。我一般会包含这几个章节系统概述用一段话说明系统是做什么的面向哪些用户核心价值是什么。功能清单按模块列出所有功能点标注优先级和迁移必要性。业务规则说明把从代码和数据库中还原出来的业务规则写清楚特别是计算逻辑、校验规则、状态流转。数据模型说明核心实体、表结构、关键字段、数据量级、数据清洗要求。接口规格说明核心接口的请求响应契约标注对内还是对外。页面功能说明主要页面的功能、字段、操作按钮。迁移风险与待确认项所有不确定的地方都要列出来标注需要业务方确认。7.2 如何标注迁移优先级不是所有功能都值得原样迁移。我一般用三个维度来评估使用频率、业务价值、迁移成本。使用频率高且业务价值高的必须优先迁移使用频率低但业务价值高的要重点保障使用频率低且业务价值也低的可以考虑废弃或重构。在 PRD 里我会给每个功能点标注 P0、P1、P2 三个优先级。P0 是核心链路迁移时必须保证功能一致P1 是重要功能可以适当优化P2 是边缘功能可以评估是否保留。7.3 待确认项的处理方式逆向出来的 PRD 一定有很多不确定的地方。这些地方不要自己拍脑袋决定而是整理成待确认清单让业务方或原系统负责人来确认。待确认项一般包括代码和数据库不一致的地方、无法直接验证的接口契约、疑似废弃但不确定的功能、以及迁移后可能影响用户体验的变更点。实操心得待确认清单最好在 PRD 评审会上逐条过当场确认的当场记录不能当场确认的指定负责人和截止时间。不要指望业务方能自己看懂技术细节你要用业务语言把问题描述清楚。8. 一些个人体会和后续扩展思路这套逆向方法我用了不止一次每次都能在两周左右把一套老系统的业务全貌摸得七七八八。最关键的心得就一条不要试图一次性把所有细节都搞清楚先搭骨架再填血肉。骨架就是核心实体、核心流程、核心规则这些搞清楚了剩下的细节可以在迁移过程中逐步补充。另外逆向出来的 PRD 一定要和业务方反复确认。代码能告诉你系统在做什么但告诉不了你业务方真正想要什么。有些老系统的功能可能早就没人用了有些业务规则可能已经过时了这些都需要业务方来拍板。后续如果还要扩展可以考虑把逆向出来的 PRD 直接转换成迁移测试用例。每个业务规则对应一条测试用例每个状态流转对应一组测试场景。这样迁移完成后直接用测试用例来验证新系统是否和旧系统行为一致比人工点点点靠谱得多。
返回列表