技术圈一直有个不能大声说、但大家心里都在盘算的问题:坐在你对面的这个人,到底比我强还是比我弱?我见过太多人用极不靠谱的方式去衡量这件事——背的 API 多不多、快捷键溜不溜、代码写得炫不炫,最后得出结论要么是过度自卑,要么是盲目自信,都对协作和成长没有任何帮助。我自己在这个行业泡了十几年,面试过几百个候选人,带过团队,也被不同水平的人 review 过代码、评审过方案,年轻时候的判断标准和现在完全不一样。这篇文章想聊的就是我怎么判断一个程序员的技术水平,哪些信号值得信,哪些表面功夫纯属噪音,以及判断完了以后,拿这个结论去干什么。
判断"谁更强"不是为了给任何人打分定级,而是要回答几个非常实际的问题:我该放心把哪个模块交给他?他 review 我的代码时,我该重点听什么?我和他协作时,用什么样的姿态才能得到最多的东西?下面这些内容,是我在真实项目里反复验证过、也交过学费之后沉淀下来的经验,希望能帮你省掉那些不必要的内耗。
1. 别用"看起来很强"代替"真的强":四种典型的误判
1.1 快捷键、API 和"肌肉记忆"都是廉价能力
我遇到过不止一个这样的同事:Vim 用得行云流水,IDE 快捷键按得跟弹钢琴一样,连写正则都是闭着眼一次成型。坐在他旁边听键盘声,你会天然产生一种"这人好强"的压迫感。直到有一天我接手了他负责的模块,才发现里面的逻辑烂得像一团乱麻,函数动辄几百行,变量名叫data1、tmp2、res,没有任何注释,线上问题靠重启解决。
键盘打得快、命令记得多,本质上只是"肌肉记忆",属于熟练工种能力。API 记性再好,也架不住搜索引擎和文档一秒钟就能查到。判断一个程序员是不是真强,要看他在脱离这些工具之后,脑子里还剩下什么:一个清晰的问题模型、一条严谨的排查思路、一套稳定的判断标准。这是工具给不了的东西。
同样的道理,一个人如果只会在自己熟悉的框架里打转,换个技术栈就手足无措,那他的"强"也很可能是环境给的。真正的技术能力应该具备可迁移性。你把一个 Spring 玩得滚瓜烂熟的人扔到 Go 项目里,看他一周之内能不能上手,比看他 Spring 注解背得有多熟,要有价值得多。
1.2 炫技代码和可维护代码,是两种物种
还有一种特别容易误判的情况——代码写得"很高级"。有个真实案例,团队里一位同事特别喜欢用各种语言特性炫技:三目运算符套三目运算符、lambda 里面再传 lambda、泛型约束绕了三层,还有一些只有他自己才看得懂的流式操作。第一次见他的代码,你会觉得简直是个天才;等你自己要在这份代码上改需求的时候,你只想问候他全家。
能写出复杂到别人看不懂的代码,从来不是本事;能把复杂的需求用简单的方式表达出来,才是真本事。代码的本质是写给"下一个维护者"看的人类语言,编译器只是顺带执行一下而已。所以我判断一个程序员水平,会特别看重他代码的可读性和可维护性:变量名有没有表达意图,函数拆得是否合理,有没有把复杂的业务抽象成了清晰的概念。
这里也有一个反直觉的点:真正的高手其实敢写"笨"代码。就是那种只要条件分支就能解决的问题,绝不用什么设计模式;明确用 for 循环更清晰的地方,绝不会硬套 stream。因为他知道,花里胡哨的代价是后续每个人都要花更多时间去理解,而一个合格的资深工程师,最讨厌的就是浪费别人的时间。
1.3 产出速度快,不等于系统稳定性好
以前和我搭档过一位同事,出活特别快,需求排期出来他永远能提前三分之一时间交代码。开始时所有人都觉得他是团队的效率标杆。后来数据打脸了:他负责的模块线上 bug 率是同组其他人的好几倍,他提的代码频繁触发回滚,长期下来他的"快"反而拖慢了整个迭代节奏。
我后来复盘这件事,发现一个规律:高水平的"快"和低水平的"快"完全不是一回事。高手说的快,是在需求理解清晰、方案设计到位、边界条件都想明白的前提下,一次性把代码写对的那个快;而有些人所谓的快,是跳过思考、不考虑异常、不做防御性编程、上线了再说的那种快。这两种快,在代码评审和线上稳定性面前,会现出原形。
所以判断一个人强不强,不能只看某一个短周期里的产出速度,而是要把时间拉长,看他线上出问题的频率、处理问题的速度、以及他写出的代码让团队后续维护花了多少成本。真正的高手会把"可维护性"当成自己交付的一部分,而不是只管"跑起来"。
1.4 能吵赢方案的人,不一定是技术上对的人
技术讨论里有一种常见场面:两个人围绕一个架构方案争论不休,其中一方口才极好,引经据典,各种论文级术语张口就来,最后把对方说得无言以对,赢得了会议室里所有人的信服。但过了几个月再看,那个方案上线后问题频出,当初的"输家"提出的风险点全都应验了。
表达能力和技术能力是两种不同的维度,但我见过太多人被"能说"迷惑。尤其在大厂评审会上,气场强、语速快、敢于打断别人的人,天然更容易占据上风。判断一个人技术强弱的正确姿势不是看他辩论赢了,而是看他说完之后,技术方案是不是经得住时间的检验。
一个真正厉害的程序员,遇到不同意见时的第一反应通常不是急着反驳,而是试图快速理解对方的逻辑,在自己的心智模型里跑一遍,然后指出"在哪些条件下你是对的,在哪些条件下我是对的"。那种一上来就全盘否定、语气上压倒对方的,往往水平不怎么样。技术判断力的核心是对"不确定性"的认知和包容,而不是非黑即白的争吵。
2. Code Review 是最好的试金石:看他 review 时盯着哪里
2.1 高手看数据流、边界和失败路径,普通人看风格和命名
如果你想在最短时间内判断一个程序员的真实水平,我强烈建议你看他做 code review 的时候都在评论些什么。这是最骗不了人的场景,因为他必须针对别人的代码给出具体的反馈,没有废话的空间。
初级水平的 reviewer 通常会把注意力放在代码风格上:函数命名是不是符合规范、有没有多余的空行、要不要提取个常量。这些不是不重要,但它们是"机器也能做的事",靠 lint 工具就能解决大半。如果你发现一个人 review 半天提的全是这类意见,那说明他心里对"这段代码到底要解决什么问题"其实没有特别深的理解。
真正的高手,review 的时候会自然而然地盯着这几件事:
- 数据流:上一个函数产生的数据,到这里格式还对不对?这个参数传进来有没有可能是空值?会不会出现类型在流动中悄悄被吞掉的情况?
- 边界条件:数组为空、并发冲突、缓存穿透、超时、幂等等情况有没有处理?还是只把"正常路径"跑通就交了?
- 失败路径:如果第三方接口挂了,这段代码的兜底是什么?失败之后是有日志、有告警,还是直接被吞进了黑洞?
- 可测性:这段逻辑是不是好写测试?里面是不是藏了很多隐藏依赖?
如果一个人 review 时,每次都能从这几个角度问出你自己没想过的问题,那他就是真的比你强,而且强在点子上。
2.2 一条 review 评论的含金量:从"建议"到"问对问题"
同样是给一段代码提意见,平庸的意见和高水平的意见差别非常大。我整理了一下自己参与过的真实 review 场景,常见的意见大概有这几种层次:
| 类型 | 典型评论 | 暴露的水平 |
|---|---|---|
| 风格层 | "这个变量名建议改成userName" | 刚入行或工具型选手 |
| 实现层 | "这里建议用 HashMap 替代 List,查询复杂度从 O(n) 降到 O(1)" | 有基础但停留在局部 |
| 设计层 | "这个函数同时做了校验和转换两件事,不如拆开" | 有全局意识 |
| 问题层 | "如果order在这个时间窗口内被重复提交,这段逻辑会出现什么情况?" | 真正的高手 |
| 目标层 | "我们这次改造的目标是降低超时率,这个方案会不会引入额外的依赖调用链路?" | 极少数,能对齐目标 |
这个表格不是我编的,是我在实际工作中见过的真实评论样本的抽象总结。你可以发现,意见的水平是层层递进的:越往上,越不关心"代码长什么样",越关心"代码在什么情况下会出问题"以及"这段改动到底服务于什么目标"。
2.3 一段真实代码:高手的提问式 review 拆解
拿一段简化的 Python 代码举例。假设有人提交了这样的函数:
def parse_config(data): try: return data["config"]["timeout"] except Exception: return 30普通人 review,可能只会说"这个常量 30 建议提成配置项"。说得没错,但也就到这里了。
高手会怎么 review?他不会只盯着那行 return,他会沿着数据流和失败路径连续提问:
- 你这里
except Exception把所有异常都吞了,那如果data不是 dict、data["config"]不存在、或者data["config"]["timeout"]的值本身是字符串,这三类错误现在全部被当作"用默认值 30"处理了。那线上如果出现了数据格式异常,我们是不是完全感知不到? - 默认值 30 是从业务上怎么定出来的?如果业务方改到 60,是不是还得改代码发版?是不是应该从配置中心读?
- 如果
data["config"]["timeout"]本身就是0,这个 0 是"合法的配置"还是"没配置"?现在这段逻辑会把 0 也直接返回吗?还是会被except拦掉?
你看,这三问没有一句在说"排版"和"命名",但每一问都在逼提交代码的人重新审视自己的逻辑边界。真正的高手,在 code review 里很少直接动手帮你改,他更习惯用提问的方式帮你把漏洞自己找出来。这个过程既是把关,也是教学。反过来,你自己在 review 别人的代码时,如果能自然而然地问出这种问题,那说明你的技术水平也已经不低了。
3. 故障处理和方案评审现场:三个场景看穿水平
3.1 线上告警响的那一刻,行为会暴露训练痕迹
技术判断力有个很残酷的特征:平时可以伪装,一上故障现场就容易原形毕露。所以我看人,特别喜欢观察他处理线上告警时的状态。这里的区别不在于"慌不慌",新手和老手都会紧张,区别在紧张之后的第一动作。
水平一般的人,第一反应通常是去告警群里复制报错信息丢给运维,或者直接在代码里搜这个报错文本,试图找到那段抛异常的代码,然后开始瞎试——加日志、重启、回滚,像无头苍蝇一样试一遍,运气好碰对了,运气不好就把故障时间拉长。
有经验和有方法的人,第一反应是先把"影响范围"框出来:这个报错影响了多少用户?是所有请求都失败,还是只有某台机器、某个参数、某个入口失败?是刚发版之后出现的,还是系统已经跑了很久突然出现的?这几个问题一问完,排查空间往往已经被压缩掉了一大半。这就是我说的训练痕迹,他脑子里有完整的排查流程,遇到问题时不是应激反应,而是按流程推进。
3.2 排查路径是"试"出来的,还是"推"出来的
我判断一个程序员强弱,特别爱看他在复杂问题前的排查路径。水平低的人靠穷举,水平高的人靠排除。
举个例子,一个接口突然大面积超时,低水平的排查思路是:看看代码、猜是不是数据库慢、重启试试、加缓存看看,每一步都是"试一下,不知道行不行"。高水平的人会把问题当成一个逻辑题来解:先确认超时的阶段,是网络层、网关层、服务层、还是数据库层;再确认超时的时间分布,是持续性的还是偶发的;再看变更与时间的相关性,最近半小时内有没有发版、有没有改配置、有没有流量波动。这种二分定位的思路,本质上是在把"未知"快速切成两半,每一轮操作都在收敛问题的范围,而不是随机试探。
判断一个人是"试"还是"推",你可以注意他描述问题的语言。如果他总是说"我当时就把某个服务重启了一下,就好了",大概率是靠运气和肌肉记忆;如果他能说清楚"我通过什么指标,排除了什么可能,最终定位到哪一层哪一段逻辑",这才是真正把技术内化成了能力。后者解决过的每一个问题,都会变成他未来处理新问题的背景知识。
3.3 复盘报告和方案评审的措辞,暴露思维方式
除了故障现场,还有一个非常隐蔽的观察窗口:复盘报告和方案评审文档。这里面藏着的思维方式,比面试时聊技术栈要真实得多。
差的复盘,通篇都在描述操作时间线:"12:01 收到告警,12:10 重启服务,12:30 恢复。"最后归因一句"由于网络抖动导致超时"。这种复盘的潜台词是——我们没有问题,问题都是环境的,而且我们也没什么可改进的。
好的复盘,会有几个标志性的特征。第一,它能讲清楚根因链路,不是停在"数据库慢了"这种表面层级,而是继续往下挖——为什么数据库会慢?是不是有慢查询?为什么慢查询没有被发现?是监控缺失还是阈值设置不合理?第二,它的改进措施是具体的、可验证的:"给某张表增加索引并设置慢查询告警阈值 500ms"好过"加强性能监控";第三,它会承认自己在某一步的判断失误,并解释下次如何避免。
有意思的是,方案评审也遵循同样的逻辑。高手写的技术方案不只写"我准备怎么做",还会写"我为什么不这么做"——他把备选方案列出来,讲清楚每个方案的优缺点,以及什么条件下他可能会改变主意。一个敢把"我放弃了什么"写进文档的人,通常是对问题理解得最透的人。
4. 三个高信息量的问题,快速判断一个程序员的段位
4.1 让他讲一次最复杂的线上问题排查
如果你没有太多时间和一个人共事,又想快速摸清他的段位,我建议你问一个开放式的问题:"你最近解决过的最复杂的线上问题是什么?从头到尾讲一遍过程。"
这个问题的信息量非常大,因为它的答案很难编造。一个真正解决过复杂问题的人,讲出来的故事一定是有结构的:一开始现象是什么,他当时有哪些猜测,怎么验证猜测,中间走错过哪条路,最后怎么定位到的根因,以及事后做了哪些改进。故事里会有犹豫,会有"我当时也卡了很久",会有具体的命令和指标名。
而那些没有实战经验、或者参与度不高的人,讲出来的故事往往非常顺滑,没有波折,没有"我当时判断错了"的时刻,听来听去都是"我们团队定位到根因然后修复了"这种非常概化的表达。细节是伪装不出来的,这也是为什么这种开放式问题在面试中会被反复使用——不是因为它难,而是因为它足够开放,能让人讲出自己真实的工作方式。
4.2 追问"你放弃了哪些方案,为什么"
第二个我特别喜欢问的问题是:"这个技术方案你当时考虑了哪些备选方案?为什么最后放弃了它们?"
为什么这个问题有效?因为它同时检验了知识的广度、理解的深度和决策的逻辑。一个人只会说"我们用 Redis 做缓存肯定没问题"的时候,他可能只是个使用工具的搬运工;而一个人能说出"我们考虑过本地缓存、Redis、以及纯数据库查询,最终选 Redis 是因为数据量级在 10w 以下、QPS 峰值 2000、缓存一致性要求不高,而纯数据库查询在高峰时会打满连接池,本地缓存又会导致多实例之间的一致性问题"——这个人在脑海中是有一张完整的决策地图的。
更关键的是,放弃方案的逻辑比选择方案的逻辑更能看出水平。一个成熟工程师会非常清楚每个方案的适用范围和代价,他知道不存在完美的技术选型,只存在"当前条件下最不坏的选择"。如果一个人说起技术选型时全是优点、没有任何代价和风险意识,那让他独立负责一个重要系统,你会睡得不安稳的。
4.3 让他给一个新人讲他熟悉的模块
第三个问题,我自己带团队的时候经常用:"如果这周有个刚入职的新人分到你们组,需要了解你这个模块,你会怎么给他讲?"
这个问题能考察一个人的"知识结构是否被真正消化"。
还停留在搬运阶段的人,往往只能按代码行文顺序讲一遍,相当于把文档朗读了一遍;有一定理解的人,能画出模块的架构图,讲清楚数据是往哪个方向流的;而真正的专家,会先讲这个模块存在的目的、它要解决的问题、它的核心约束,然后再给你一个最小的认知模型,告诉你先把哪个文件读完就能理解八成。
能在几分钟内把复杂的东西讲得让别人听懂,是技术理解力的一种高级表现。这背后要求的不仅仅是对自己代码的熟悉,更是对本质的抽象和取舍。注意,我强调的不是"讲得全面",而是"讲得让新人能上道"。那些试图把什么细节都塞给你的人,往往自己也没理清哪些是重点、哪些可以忽略。这个筛选能力,恰恰是资深工程师和普通工程师的分水岭。
5. 对方确实比你强:怎么把"压力差"转化为"学习红利"
5.1 偷师的高级姿势:读他的 diff、设计文档和 review comment
行,假设你已经通过上面这些方法确认了一件事:这家伙确实比我强。接下来怎么办?很多人会陷入两种特别不健康的情绪——要么自卑,觉得对方是天才自己这辈子追不上了;要么酸,嘴上不说但心里各种挑对方的毛病。这两种情绪都浪费了身边最宝贵的资源。
我的建议是,把比自己强的人当成一个"活体知识库",有意识地偷师。最直接的偷师渠道有三条:第一,主动订阅他的代码提交,去看他的 diff 是怎么写的,注意他改了哪些文件、怎么组织的提交,一个好的提交本身就是在教你如何拆分逻辑;第二,翻看他写的设计文档,重点看他怎么描述问题、怎么对比方案、怎么评估风险,这些写作结构其实就是他的思维方式;第三,去翻他过去在 code review 里留下的所有评论,一条一条地看,这等于你在读一个高手的思维流。
偷师的时候有个心态技巧:不要想着"我要立刻达到他的水平",而是想"我能不能从他的每一个决策里学到一个有点意思的思路"。把大目标拆成每天都能消化的微量学习,一年下来积累的量会非常惊人。
5.2 该不该当面承认他比你强
诚实地说,我在团队里见过太多因为"面子"而错失成长机会的例子。两个水平有差距的人,如果差距没有被坦诚地承认,协作就会变得很别扭:较强的一方不好意思提意见,较弱的一方不敢暴露自己的盲区,最后两人各干各的,还互相觉得对方有问题。
如果你判断出对方确实比你强,我建议你敢于直接承认。你不需要到处宣扬,只需要在具体的场景里表态:"这个方案我没想明白,你能再给我讲讲吗""你刚才说的那个点我确实没考虑到"——这些话不仅不会让你掉价,反而会让真正强的人愿意教你。因为高手最怕的不是别人承认差距,而是明明不懂还硬撑的人。你越坦诚,你能从对方身上吸收到的东西就越多。
顺便说一句,强的人通常也经历过从弱变强的阶段,他们其实很愿意分享。前提是你得让他们的分享产生价值感,而真诚求教就是最好的价值感来源。
5.3 自测信号:你正在变强的几个迹象
天天盯着别人很强,容易忽略自己也一直在往前走。我总结了几个自己用来衡量"是否变强"的信号,分享给你作为参考:
- 你能看懂高手为什么那么写了。以前可能只觉得人家的代码"看起来好高级",现在你能说出他这样设计的理由、权衡和代价。
- 你能预测他的 review 评论。提交代码之前你大概能猜到高手会在哪个地方挑出毛病,并且你已经提前处理掉了。这说明你开始用他的思维方式思考。
- 你能在他没想到的地方提出补充。不一定是推翻他的结论,而是发现他分析中一个小小的盲区。这通常标志着你已经快到达他的水平了。
- 你开始觉得很多以前"很厉害"的代码其实可以不那么写。这不是傲慢,而是你终于理解了可维护性的价值。
这几个信号只要出现其中两三条,就说明你和那位"更强的人"之间的差距在缩小。判断别人技术强弱的终极意义就在这儿:拿高手当参照系,校准自己的位置,然后朝更远的方向前进。
6. 我的偏见:比到最后,比的是"责任半径"
技术圈里关于"强弱"的标准众说纷纭,有说算法能力的,有说架构视野的,有说工程效能的。作为一个在业务代码里摸爬滚打多年的人,我最后的判断标准其实非常朴素:一个人愿意背着多大的责任,决定了他的技术能走到多高。
我见过一些技术水平很高、但只愿意对自己手里那一小块代码负责的人。接口写得很漂亮,但线上出了问题他第一反应是"这不是我这边的问题,是网关/数据库/运维的问题";方案评审时只关心自己的模块能不能做完,不关心整条链路是否因此变得更脆弱。时间长了你会发现,这类人的技术始终停留在局部,很难成长为真正能独当一面的技术负责人。
反过来,那些我认为真正"强"的程序员,哪怕职位只是普通开发,他也会把"这件事能不能成"而不是"这段代码能不能跑"当成自己的责任。接口出问题了,他会从入口到出口追一遍链路,而不是急着划清边界;需求不清晰时,他会主动问清楚背后的业务目标,而不是等着别人喂需求;线上系统半夜报警,只要与他相关,他不会当作没看到。这种责任感,会倒逼着一个人去理解更多的上下文、接触更多的领域知识、掌握更广的技术面。所谓的技术成长,本质上就是责任半径不断扩大的过程。
如果你现在还在为"判断别人是不是比你强"而内耗,我的建议是换一个角度:不要执着于给自己排位,而是先把自己手头的事做到"出了任何问题都愿意负责"的程度。当你真的能为你负责的系统、模块和团队承担起全部责任时,你自己就是那个别人眼中的"更强的人"。技术强弱这件事,比到最后不是智慧的比拼,而是肩膀能扛多少的分量。