DOCAI · 课程 · L3 · 20 分钟 · 基础入门
代码修改与优化
改代码之前先摸清影响面,把「不能动什么」写进需求;重构、提速、补类型都拆成小步,每步用测试证明原有行为没被破坏。
你将学会
- 能在动手前问清调用方与影响范围
- 能把兼容性约束写进修改需求
- 能把重构与性能优化拆成可验证的小步
改之前,先问影响面
新增代码只影响自己,修改代码却牵动所有调用方。所以第一步不是下命令,而是摸底:
先别动手。这个邮箱校验函数被哪些地方引用、改动后哪些入口会受影响、现有测试能覆盖到什么程度,把这三件事列清楚再说话。
拿到调用清单,你再决定哪些行为必须保留。看不见的依赖,往往是线上事故的来源。清单列完再动手,能避免改到一半才发现方向错了。
把限制写进需求
改动的质量,取决于你有没有说清「不能动什么」。三条约束最常用:旧参数必须保留、接口签名不能变、不新增依赖。
给现有的搜索接口加一个排序参数,默认按相关度排序。 旧调用不传这个参数时,返回结果与现在完全一致。 不改返回结构,不新增第三方依赖。
这样写,它会在兼容的前提下扩展,而不是顺手把接口重设计一遍。加字段、加方法、加可选参数,都适用同一套说法。约束不是不信任,而是把返工挡在提交之前。
重构:一次只做一件事
重构最容易失控的地方,是「顺手」:拆函数时顺手改名,改名时顺手改逻辑。改完测试挂了,你都不知道是哪一步惹的。
| 目标 | 这一轮只做 | 留到下一轮 |
|---|---|---|
| 拆长函数 | 把代码搬进小函数,逻辑原样 | 改名、改判断顺序 |
| 消除重复 | 抽出公共处理 | 统一各处细节行为 |
| 改善命名 | 换名字,保留行为 | 调整结构 |
| 压平嵌套 | 把不满足的情况逐个提前挡回 | 合并条件、换算法 |
最后一项值得单独说:三层嵌套的判断,重构成「先挡掉不满足的情况,最后只剩成功路径」,读起来会顺很多。但这一步只调整结构,不改变任何分支的结果。判断条件本身是否合理,是另一件事,别在同一轮里改。
还有一个常被忽略的约束:改动的范围要和需求对得上。让它修一个空指针,结果它顺手重排了整个文件,diff 里几十行无关变化,审查的人根本看不出哪一行是关键。需求里写明「只改这一个函数」,diff 才会干净。
每一轮结束都跑一次相关测试。测试通过,再进入下一轮。
性能:先测量,再动手
没有测量数据的「优化」,多数只是换个写法。先定位瓶颈,再选手段:
- 循环里反复查库,改成一次批量查询;
- 热点数据加缓存,同时想清楚键名、过期时间和更新时怎么失效;
- 列表渲染开销大,只在输入变化时重新计算;
- 首屏图片太多,进入视口再加载。
每次只处理一个瓶颈,改完复测同一组指标。快了多少要有数字,不能凭感觉。
质量和安全:让验证可重复
补错误处理时,把行为写成清单:失败重试几次、间隔怎么增长、最终抛什么错、请求能不能中途取消。重试与退避的取舍见退避与重试。
把模糊类型换成具体类型、按项目配置统一格式、清理调试输出,这些都属于低风险改动,但同样要跑测试。大改造则拆成小步:先抽出一块,验证,再抽下一块,任何一步都能单独回滚。
改完做两件事:跑与该模块相关的测试,看输出而不是听话术;再看一遍改动范围,确认没有夹带无关修改。把这两件事变成习惯,修改才敢交给它做。
扩展与迁移:两类改动的固定动作
给现有函数加参数。 新参数一律可选,默认值等于旧行为。比如日期格式化原来只输出年月日,现在要支持三种格式:
formatDate(value) // 旧行为,保持 YYYY-MM-DD
formatDate(value, 'datetime') // 带时分秒
formatDate(value, 'relative') // 显示相对时间
指令里把三种取值和默认值写全,再补一句「不传第二参时,输出与现在逐字符一致」。接口加筛选参数同理:role、status、createdAfter 各自可选、可以组合,不传时结果集不变。
迁移到新格式。 依赖升级、第三方响应改结构、JavaScript 换 TypeScript,都走三项固定动作:先找全调用点,再机械替换,最后跑类型检查和测试。比如响应从 { data: { user } } 变成 { result: { userData } },先让它列出所有读旧字段的位置,确认清单完整再动手;缺一个,线上就多一个空值。
改完怎么判断有没有把握,见评估改动。三类症状对应三种处理:
| 现象 | 为什么 | 怎么办 |
|---|---|---|
| 单测全绿,线上仍报错 | 测试没覆盖真实调用方 | 先列调用点,补一条走真实入口的测试 |
| 优化后反而更慢 | 没有改前基线,凭感觉选手段 | 先记录耗时和次数,改完复测同一组指标 |
| 差异里混着大量格式变化 | 指令范围太宽,顺手格式化了整个文件 | 限定「只改这个函数」,提交前逐行看差异 |
改得动,还要讲得清。下一节看怎么把改动变成团队能接手的提交与审查:基础代码协作。
自测
先自己回答,再展开对照;答不上来就回到对应小节。01为什么修改前要先问调用方有哪些?看答案
同一个函数往往被多处复用,参数含义或返回结构一变,受影响的不只是你眼前这个页面。先列出调用点,才能判断哪些约束必须保留。
02重构和性能优化为什么不适合放在同一次改动里?看答案
两者的验收标准不同。混在一起,一旦测试失败就分不清是结构问题还是性能改动引入的,回滚也会牵连无关部分。