实习笔记写到第11篇,坐在工位上回想这十几周的变化,最明显的一点反而不是我写了多少代码、掌握了多少框架,而是我开始习惯性地停下来问一句:“为什么这样做?”前10周的我,基本处于接到任务就动手的状态,能跑通就算完成任务;第11周发生了几件小事,让我发现自己终于开始用“做项目”而不是“做练习”的方式去理解工作内容。这篇笔记不打算写成流水账,挑几个这周最有价值的片段:一次需求理解偏差引发的返工、一次排查到深夜的接口超时问题、一场把我问得哑口无言的代码评审,以及我顺手整理下来的工作习惯清单。如果你也在实习,或者刚入行不久,这些场景你大概率都会遇到。
1. 从“照做”到“追问”:第11周的状态分水岭
前10周我给自己定的目标是“更快地完成分配给我的任务”,TypeScript、数据库、后端框架这些新技术学得飞快,但大部分时间我都是拿到需求就开始设计表结构、写接口。当时我有个习惯——从需求描述的字面意思直接推导实现方式,从来不觉得这有什么问题,直到这周翻车了。
1.1 前10周的惯性:接到单子就动手
事情是这样的:某模块需要给运营同学做一个数据导出功能,需求描述里写了一句“用户可能按批次选择大量数据”。我看到“批次”两个字,下意识理解成“分批导出,每批一个文件”,于是花了两天时间设计了一个带批次参数的任务队列,支持分批导出多个压缩包。
做完之后拿去对接,运营同学看到页面时的表情已经说明了一切。他们要的是:一次性勾选大量数据,系统自动按数据量拆分成多个文件,但对用户来说,始终是“一次操作、一次下载”,后台怎么拆是他们的事。我理解反了——我把“分批选择”做成了“分批导出”,把内部实现细节暴露给了用户。
带教人看完代码没有直接批评,只问了一句:“你当时为什么没问?”我愣在工位前,回忆了一下整个过程:需求文档写得确实模糊,但里面有几个关键词完全可以触发追问,比如“后台自动拆分”“用户无感”。而我当时默认了“按照字面意思理解,先做出来再说”。
1.2 “先确认再动手”到底帮我避开了什么坑
这周开始,我给自己立了一条规矩:拿到任何需求,动工之前先把“我打算怎么做”用三五句话写在文档里,发给需求方或带教人看一眼再开工。不是做一个完整设计文档,而是描述方案要点,让对方确认“你说的就是我要的”。
就拿导出功能举例,如果当时我在文档里写清楚两句话:“系统会把用户勾选的所有数据按每5000条一个文件拆分,用户只需点击一次导出”,对方一眼就能看出来我理解错了,这比我埋头写完整个功能才被纠错省了不止两天时间。
这事的本质是:沟通成本在与返工成本的对比中其实非常低。很多初入职场的同学怕“问问题显得自己笨”,但在实际协作关系里,带着理解去确认,恰恰是专业的表现——因为这说明你在思考,而不是在复制。
另外我还学到一个表达技巧:确认需求时不要问“是这样吗”,而要问“我准备这么做,你看对不对,有没有补充”。前者是把判断责任交给别人,后者是亮出你的方案,让讨论有焦点。从这一周开始,我所有的需求确认都改成了第二种问法,错位的次数明显变少了。
2. 一个接口超时问题的完整排查链路:从猜网络到定位数据分布
第11周还遇到一个让我熬夜到凌晨一点的问题。起因是我们系统里一个“结算单查询”接口,联调阶段大部分请求都正常,但偶发会卡到两秒以上,调用方设置的超时时间是一秒,于是不断报错。第一反应是网络波动,我和另一个模块的同学反复调大超时参数、加日志,折腾了一个下午,问题照旧。
2.1 现象与第一反应:先怀疑网络和超时参数是治标不治本
这里要先说一个我在排查初期犯的典型错误:没有收集足量信息就直接动手改。我们加的第一批日志只记录请求入口和出口的时间,没有记录参数,导致日志堆了一大堆,却无法判断问题请求到底有什么共性。这就是个典型的反面教材——日志不加关键参数,等于带了个睁眼瞎上路。
后来我在入口日志里追加了”状态类型““机构编号”“请求ID”三个参数,再去复现,很快发现慢请求几乎集中在状态为“已完成”且机构编号为某几个特定值的查询上。到这里我才有把握说,问题大概率不在网络,而在数据库或者数据量的分布上。
2.2 一步步缩小范围:日志、复现与参数验证
复现之后的做法其实很简单:我把慢请求的SQL语句直接在测试库执行了一遍,第一次耗时1.8秒,第二次0.4秒。这个波动让我意识到事情没那么简单——同样的SQL耗时不一致,说明执行计划可能在变,或者数据分布在两个时间段内差异很大。于是我先查了数据量,发现测试库里“已完成”状态的行数是“待处理”状态的二十多倍,再一看执行计划,状态字段没有索引,数据库只能走全表扫描。
加了一个状态字段的联合索引之后,慢请求直接降到几十毫秒。整个过程回顾下来,核心教训有三个:第一,日志记录必须带上下文参数,否则无法定位共性;第二,遇到偶发问题不要急着改超时参数,改完你能看不出来,但它背后的隐患还在;第三,性能问题排查要按“现象分类→数据验证→执行计划查看”的顺序来,而不是上来就猜是网络还是代码问题。
提示:排查接口偶发超时时,先在日志里把“参数、耗时、时间戳”三样对齐,再谈优化方向。如果连参数都没有,后面的一切分析都是空中楼阁。
3. 代码评审中被问住的那一刻:边界情况的系统性思考
周中的一次代码评审,给我上了一课。我提交了一个导出接口的改动,自认为已经处理了权限校验、参数校验、空列表判断,应该没什么可说了。结果会议刚开始,某同事连续问了三个问题:“数据为空的时候接口返回什么?并发导出同一个任务的请求怎么办?生成的文件什么时候清理?”
我当时的反应是语塞。这三个问题我一个也没系统性想过,代码里只简单返回了一个空数组,完全没有考虑任务可能同时被触发两次的情况,临时文件也只写了“用完之后删除”,但没有定义删除的时机和失败兜底。这不是我不会写代码,而是我压根没把这类边界当一回事。
3.1 评审现场被问住的瞬间,反而是最有价值的时刻
现场当然很尴尬,但冷静下来之后,我把这次评审当成了难得的查漏补缺机会。评审结束后,我一口气梳理出了边界场景清单,列了十几条:空数据集、超大输入、重复提交、未登录、权限不足、外部依赖超时、结果集截断、文件清理失败、并发写同一批数据等等。
梳理完之后才发现,代码评审里讨论边界情况,其实是在逼你把“功能代码”变成“产品代码”。功能代码只需要在正确输入下返回正确结果,产品代码要考虑调用方会怎么误用、系统处于什么异常状态时还能不能给出合理的反馈。我把这个观点写进了笔记,从此每次写完代码都对照一遍这个清单再提评审。
3.2 边界处理的三点原则:快速失败、语义清晰、可观测
这次评审之后,结合带教人给的建议,我沉淀了一套做边界处理时的思路,免得以后每次都是从零开始想:
- 对于参数错误、未登录、权限不足这类“调用方出了问题”的情况,应该快速失败,直接返回明确的错误码和错误信息,不要在后续逻辑里继续执行无意义的操作。
- 对于空数据、超大输入这类“业务本身处于特殊情况”的情况,不要用报错表达,而应该返回一个语义清晰的空态响应,让调用方知道“查询成功,但没有数据”。
- 对于并发、超时、文件堆积这类资源层面的问题,要做可观测处理,宁可多打日志、多加计数,也要让问题出现时能第一时间定位到原因。
好的边界处理不一定代码量更多,而是想要把每一种情况都当作一个有语义的“路径”,明确该路径下的行为。错误码要可读、日志要可检索、响应要自解释——调你的接口的人不需要看你的代码就能知道发生了什么,这才叫做好接口。
4. 环境与流程上的沉淀:联调检查清单和自测用例表
如果说前面几周是在学写代码本身,那第11周我真正意识到:实习阶段最容易忽略的,反而是工程师日常工作中的“流程工具”。联调环境到底要检查哪些东西?自测要到什么程度才算敢提测?这些问题没有标准答案,但每个人心里都应该有自己的清单。我这周顺手把踩过的坑整理成了两份可实际使用的清单,分享出来供参考。
4.1 联调环境准备的检查清单
最开始的联调很狼狈:服务起来了但配置没加载,依赖的第三方接口没开Mock,数据库是空库导致查不到数据,前端连过来的地址还是上个月的内网IP。后来我固定了一套联调前的准备动作,每次联调前按顺序检查一遍,基本没有再因为这些低级问题卡壳:
| 检查项 | 具体内容 | 检查方式 |
|---|---|---|
| 服务状态 | 本地依赖的所有服务都已启动 | 逐个拉取健康检查接口 |
| 配置中心 | 必要的开关和外部地址加载成功 | 查看环境变量加载日志 |
| 数据版本 | 数据库与需求描述的数据一致 | 导出数据行数和最新记录时间 |
| 外部依赖 | 第三方接口已开Mock或测试通道 | 调用一次冒烟 |
联调过程中最怕的就是“你以为环境是好的,实际上某个服务没起来”。别看这个清单简单,真踩过几次坑之后你就会发现,它比自己凭记忆检查可靠得多。
4.2 自测表:从“能跑”到“敢交付”之间的那道距离
另一个我新增的习惯是写自测用例表。以前我自测就是启动服务,拿Postman调几个接口,感觉差不多就提测了,结果评审同事一测就暴露出一堆我没预想到的边界情况。现在我会在自测之前简单列一张表,分三行:正常路径、边界情况、异常路径。
正常路径写这个功能的核心流程,比如导出功能就是“创建任务→任务完成→下载文件”;边界情况写空列表、超大数据量、重复请求、权限边界;异常路径写外部依赖失败、参数非法、服务重启等情况。不用写得很正式,但要确保自己动手测过每一种情况,而不是只在脑子里过一遍。
这件事最直观的收益发生在这周周五:部署前我按自测表重新测了一遍旧功能,结果发现某个环境变量没配好,导出功能在测试环境可以跑,在预发环境直接报错。如果不是自测表把“配置加载”也列成了前置条件,这个bug就会出现到正式环境里。低级失误最怕的就是靠回忆,检查清单的作用不是限制你,而是替你脑子做那部分容易漏掉的事。
5. 第11周的复盘:从“做过什么”到“沉淀下了什么”
每次写完实习笔记,我都会在末尾盘点一下这周留下的有形产出,这周比之前更多一些,因为我开始有意识地把踩过的坑转化成可复用的东西。这周沉淀下来最实在的几件东西包括:需求确认文档的模板、接口日志的标准格式、边界场景自查清单、联调环境检查清单、自测用例表的通用三段式结构。
这些看起来都不起眼,但正是这些不起眼的清单和模板,最能体现工作方式的进化——第一周的我,只在被动解决问题;第11周的我,开始尝试把偶然学会的东西变成固定动作。
5.1 好的复盘不是写日记,是把碎片经验变成固定动作
我见过一些同学也写实习笔记,但大多是在记流水账,今天修了个bug,明天学了个新组件,内容是很充实,但实际没有转化。真正的复盘动作应该是:从每件具体的事里提炼出一两句可以复用到下一次工作的判断规则,然后将它放进某个清单或模板里。比如“不要直接改超时参数,先拉日志找共性”这句话,不是经验,而是帮助你下次不再犯同类错误的规则。
把这个规则写进笔记后,我每次再遇到偶发超时,都会先给自己定一个步骤:第一次先收集日志带上的上下文参数,第二次再敢动配置。这样做最大的好处是,你不再依赖“灵感”或“直觉”,你的工程能力可以被积累和翻查。
5.2 第11周的小细节:离开工位前把问题清空
最后分享一个很小的个人习惯,是这周养成的:每天离开工位前,把当天遗留的问题列在一个记事本里,哪怕只写一条“明天验证导出拆分的边界”也行,然后给自己留下一句“今天做得最值的一件事是什么”。这个动作只需要两分钟,但坚持下来会让你发现,上班不只是被任务推着走,你开始有了自己主动经营工作的感觉。
实习笔记11到这里就记完了,下周的目标很明确:把新梳理出的清单真正套用到下一个功能开发里,尤其是需求确认环节,争取让“先对齐再做”成为肌肉记忆。