1. 为什么“有经验”和“没经验”一看便知
做了这么多年开发,面试过不少人,也带过不少新人,我越来越发现一个事实:程序员有没有经验,其实从日常行为里一眼就能看出来,根本不用等到绩效考核或者代码评审。
有些人写的代码能跑,功能也实现了,但总让人觉得不对劲。不是说他能力不行,而是他踩坑的方式太“标准”了——标准到和当年刚入行的我一模一样。我复盘了一下这些年观察到的现象,整理了程序员缺乏经验的7种常见表现。如果你刚入行,或者感觉自己成长遇到了瓶颈,建议对着看看,中了几条就得引起重视了。
这篇文章适合所有阶段的开发者,尤其是工作1到3年的初级工程师。它会告诉你这些表现背后的逻辑、它们会导致什么问题,以及最关键的——怎么改。因为很多问题不是靠“多写代码”就能解决的,而是思维方式的转变。
2. 七种典型表现,逐个拆解
2.1 接到需求第一反应是“怎么写”,而不是“为什么写”
这是最常见的一种。需求评审会上,产品经理刚讲完一个功能,有经验的程序员会先问“这个功能要解决用户的什么问题”“数据量大概多大”“有没有类似的旧逻辑可以复用”,而没经验的程序员脑子里已经开始想“这个表该怎么建”“这个接口怎么调”了。
我见过太多新人接到需求后吭哧吭哧写了两天,结果做完才发现产品和预期完全不是一回事。为什么?因为他根本没弄明白需求背后的逻辑。比如做一个列表页,产品说“按时间倒序”,新手就直接ORDER BY create_time DESC了,但老手会追问:是按下单时间还是支付时间?要不要考虑退款订单?时间字段是字符串还是时间戳?需不需要分页的深分页优化?这些追问背后,是把“功能描述”翻译成“技术方案”的能力,而这种能力恰恰来自对业务的理解和经验积累。
这个问题真正严重的不是多花几天工时,而是方向错了,做得越多浪费越大。如果你发现自己接到需求就兴奋地打开IDE,建议先强迫自己在需求文档上写出三个问题:这个功能服务谁、解决什么痛点、我打算怎么验证做对了。
2.2 拿到任务就写代码,不思考整体设计
如果说第一种表现是“不追问业务”,那第二种就是“不思考结构”。很多人喜欢在一个文件里堆函数,一个方法写几百行,变量命名随便用a、b、tmp,功能确实实现了,但代码成为了一团谁都不想维护的乱麻。
我在团队里经常遇到情况:一个新人花一天写完一个模块,代码能跑,但让他解释“这段为什么放在这里”“这个函数是做什么的”,他自己都要研究半天。这和街边临时搭的违章建筑很像:能住人,但经不起风雨,也没法扩建。
有经验的程序员写代码前会先花时间设计。哪怕是实现一个简单接口,他也会想清楚:这个模块未来可能怎么扩展、参数校验放哪一层、异常怎么处理、日志该打在什么位置。这些思考在单次开发中看不出优势,但放到项目迭代的维度,好的设计让每一次新增功能和修Bug都变得轻松,坏的设计则让代码越来越僵硬,直到有一天只能推倒重来。
2.3 从来不主动优化和重构,代码只求能跑
这是我在很多初级工程师身上看到的通病:只要功能正常,就绝不碰代码。测试通过了就提交,代码评审完全被动——指哪改哪,绝不多做。
有一次我让一个新同事优化一个报表查询的SQL,他说“这个SQL执行要3秒,但功能正常呀,为什么要改”。我说“如果数据量翻十倍呢?”他沉默了。这就是典型的缺乏经验:意识不到代码的生命周期远比“写完能用”要长,它还要经历性能测试、异常流量、功能迭代、接手维护等无数关口。
有经验的开发者通常对代码有“洁癖”,看到重复代码会主动抽个公共方法,看到循环里的无效查询会加个缓存,看到接口缺乏校验会顺手补上。这不是强迫症,而是吃过亏之后的肌肉记忆——线上事故往往就藏在那些“看着不对劲”的代码里。养成这个习惯不容易,但它是从“能用”到“好用”、从“工程师”到“优秀工程师”的关键分水岭。
2.4 遇到问题第一件事是问别人,而不是自己排查
带新人最累的不是他们问问题,而是他们问的问题实在太“基础”了——比如“这个报错是什么意思”“为什么这里报NullPointerException”“这个依赖怎么引入”。这些问题的答案,只要把报错信息复制到搜索引擎,或者耐心看JDK文档就能解决。
缺乏经验的程序员遇到报错的第一反应往往是求助,而有经验的人第一反应是自己排查。这不是什么高深的差别,而是解决问题的习惯不同。有效的问题排查路径是:看报错日志定位异常位置 → 梳理相关调用链路 → 猜测可能的原因 → 写demo验证 → 定位并修复 → 总结并记录保证下次快速识别。这个流程里,每个环节都可以通过刻意练习来掌握。
恰恰是那些自己苦苦排查过的问题,收获最大,因为你对它的理解是整个系统层面的。那些张口就问的人,得到的只是一个答案,而答案背后的逻辑、排查的方法、对系统的理解,全都错过了。如果你现在遇到问题第一反应是“问谁”,不妨先自己卡一个小时,再带着你已经尝试过的方案去问别人,收获会完全不一样。
2.5 只顾自己的一亩三分地,缺乏全局视野
很多新人会犯一个错误:把自己当成“写代码的”,产品、测试、运维的事一概不管。做后端的人觉得页面样式是前端的事,做前端的觉得接口字段是后端的事,从来不去想自己写的代码在整个系统里扮演什么角色。
我特别认同一个观点:程序员的价值不在于“会写代码”,而在于“用代码解决业务问题”。而解决业务问题,必须有全局视野。比如你在一个订单系统里负责支付回调,你没有去了解这个接口被哪些服务调用、调用方对返回值的期待是什么、如果超时会发生什么,那你大概率会写出一个“自以为正确”但线上极易出Bug的接口。
有经验的开发者拿到一个任务,会习惯性地问:我的上游是谁、下游是谁、我在系统里处于什么位置、我的变更会影响谁。这些思考听起来“不是必需的”,但正是它们决定了一个人能不能从“写了一个功能”成长为“设计了一个系统”。
2.6 不写测试、不写文档、不做版本管理
这三个“不写”放在一起说,是因为它们的根源是一样的:缺乏对代码“可维护性”的理解。
刚入行的程序员通常认为,把功能写出来交付就算完事。至于测试,那是测试部门的事;至于文档,需求都做完了还要什么文档;至于版本管理,我能保证提交到Git仓库就行。然而真实情况是:没有测试的代码就像没有安全带的车,看起来跑得欢,一出事故就是大事;没有文档的代码就像没有说明书的电器,只有原作者能勉强用,换个人就茫然无措;没有规范的版本管理就像没有路标的迷宫,谁也不知道最新的稳定版是哪一版。
有些参与开源项目的同学可能深有体会:一个优秀的PR,不仅包含功能代码,还包含单测、注释、变更日志和清晰的Commit Message。这背后不是“形式主义”,而是对代码库负责、对团队负责的职业习惯。
2.7 犯过的错误一犯再犯,不做复盘
我让团队里的新人每解决一个线上问题,就写一篇简短的事故分析:问题现象、根因、处理过程、后续如何预防。愿意认真写的人,过一两年成长速度非常快;而觉得这是浪费时间、应付了事的人,三年后还在踩同样的坑。
缺乏经验的人有个特点:对问题只停留在“解决”层面,从不进入“理解”层面。今天遇到了线上内存溢出,重启了一下,就完事了。下次线上又内存溢出,他还是一脸茫然。而有经验的工程师会去深入分析:为什么内存会溢出?是哪块代码的什么问题导致的?线上监控和告警能否更早发现?有没有办法在编码阶段就避免?这个复盘的过程,是把“事故”转化为“经验”的过程。
一个人的经验并不等于工作年限,而等于从经历中提炼出来的有效模式的数量。如果不做复盘,工作10年和重复1次完全相同,经验值没有本质区别。
3. 有经验的人和没经验的人,思维到底差在哪里
上面这7种表现,表面上是行为差异,本质上其实是思维模式的差异。要想真正摆脱“没经验”的标签,不能只靠“别这样做了”的外力约束,还得理解背后的思维转变。
3.1 从“任务视角”转向“项目视角”
没经验的人看待一个需求,就是一个任务:拿到需求、估算工时、写代码、提交、交付。有经验的人看待一个需求,是一个项目:需求背后的业务目标是什么,实现方案有哪些选择,每种选择的成本收益如何,上线后如何监控和验证,以及未来如何迭代。
这个转变直接决定了你看问题的颗粒度。任务视角让你只关心“做没做完”,项目视角让你关心“做得好不好”“有没有更好的方式”“如果中途需求变了怎么办”。我面试的时候特别喜欢问“谈谈你最近做的一个项目”,候选人如果只讲功能实现,没有提到业务背景、方案选型和踩坑复盘,那多半还是任务视角。
3.2 从“代码思维”转向“工程思维”
代码思维关注的是:怎么写能让这段代码正确运行。工程思维关注的是:怎么设计能让这个系统长期稳定地运行、高效地迭代。这完全是两码事。把代码交给机器执行是计算机科学,把代码变成团队可持续维护的产品是软件工程。
在工程思维下,写代码只占工作的一部分,还有一部分是需求分析、系统设计、测试用例、性能评估、监控告警、文档沉淀、协作规范。缺乏经验的人只看到第一层,所以他的成长速度会非常慢。想加快成长,最有效的做法是在日常工作中主动涉足那些“代码之外”的环节,别只等着别人安排。
3.3 从“单点解决”转向“系统预防”
没经验的人是在不断“救火”:这里有个Bug改这里,那里性能慢优化那里。有经验的人做的是“防火”:设计阶段就想到了可能的风险,编码阶段就埋好了监控点,测试阶段就覆盖了边界场景,Review阶段就堵住了常见隐患。
说一个我自己的例子。早期我做支付系统,有一次因为上游回调重试导致订单状态被覆盖,排查了一个通宵才解决。后来我总结了一套方案:给核心状态变更加版本号控制,用幂等表防重,监控推送增加告警维度。从那以后,这类问题再没有出现过。单点解决只能让你“晚上睡得着”,系统预防才能让你“长期睡得安稳”。
4. 如何摆脱这些“缺乏经验”的表现
说完了表现和思维差距,如果这篇文章就停在这里,那价值就不够了。分享几个我实践过、也带新人验证过的方法,可以直接拿来用。
4.1 建立自己的“问题-方案”清单
准备一个笔记软件,专门记录自己遇到过的报错、踩过的坑、找到的解决办法。别小看这个动作,它是在建立你的个人知识库。当一个问题你记录过一次,大脑就会对它形成更深印象;当你记录的足够多,就拥有了一个可以随时查询的“排错手册”。每次排查问题后花十分钟记录,长期积累下来的价值远超你的想象。
4.2 写代码前强制自己写设计要点
哪怕是很小的功能,也要求自己用5分钟写下:我要改动哪些文件、数据流是怎么走的、有没有边界条件需要处理、上线后怎么验证。写不写得出来是一回事,但写的动作本身会逼着你思考,而不是直接冲向键盘。
我见过很多新人,写需求文档觉得浪费时间,但事实证明:文档写得越清晰的模块,开发中返工越少;代码注释越到位的地方,出问题后的排查越快。这真的是投入产出比最高的习惯之一。
4.3 主动给自己找一面“镜子”
经验说白了就是信息输入和有效总结的产物。想快速积累经验,有个偷懒的办法:参加代码评审,多看别人写的代码和评审意见。好的代码和自己写的代码放在一起对比,经验和差距立刻显现。这也是为什么很多公司推行结对编程、定期代码Review。
如果你想加速这一过程,可以找一位比你资深、又愿意真实反馈的同事,定期请他看看你的代码和设计,问一句“如果是你,会怎么处理”。我自己的很多技术习惯,就是这样从前几任导师身上“偷”来的。表达感谢的方式也很简单:等你有了能力,也做别人的镜子,在Review里认真指出问题,客气地讲明白背后的思考。
4.4 用“复盘”把经历变成经验
推荐一个轻量复盘模板,四个问题就能写清楚:
- 这次遇到的问题,根因是什么?
- 最开始哪里没做好,才导致这个问题暴露?
- 下次遇到类似情况,第一反应应该是什么?
- 有没有更根本的机制或工具能防止这类问题?
关键是坚持。一个月写四个小复盘,半年后你回头看,会发现自己的判断力和敏锐度提升得远超想象。
5. 写在最后的一点体会
说句实在话,这7种表现我几乎全部经历过。刚工作的第一年,我接到任务就写,遇到报错就问组长,代码能跑就交付,从不写文档和测试。后来被一个资深同事狠狠批评了一回,我才开始反思这些问题。
成长不是一个瞬间的事情,而是一个个选择叠加的结果。你选择接到需求先问“为什么”,选择写代码前先想设计和边界,选择遇到报错先自己排查,选择每次Review认真对待,选择为犯过的错误做复盘——这些选择和代码能力无关,却决定了你三年后、五年后站在什么位置。
如果你看完发现自己中了好几条,不用焦虑,这是大多数程序员的必经阶段。意识到问题已经是改变的开始。接下来要做的只有一件事:把文章里的这些“不该做”换成“该怎么做”,然后从下一个需求开始实践。
最后分享一个小技巧:每完成一个迭代或项目,都可以给自己做一个“最满意的一件事”和“最后悔的一件事”的复盘。前者是给自己正反馈,后者是给自己找改进方向。几年下来,这个动作比任何技术培训都更值钱。希望你在编程这条路上,越走越清晰,越走越有底气。