拒绝内卷!为什么我们应该抵制用 LeetCode 考查真实的工程师?
如果你要招募一位主刀医生,你会让他当场默写《人体解剖学》的第一章吗?如果你要找一位米其林大厨,你会蒙住他的眼睛,让他比赛在一分钟内切出多少根标准厚度的土豆丝吗?
显然不会。但在如今的软件工程招聘中,我们却在做着同样荒谬的事情:让那些在复杂的业务泥潭中摸爬滚打、主导过千万级并发系统、熟练操纵复杂云原生架构的资深工程师,站在白板前,徒手写出一个“翻转二叉树”或者“接雨水”的最佳时间复杂度解法。
不知从何时起,“刷 LeetCode”已经从一种思维训练,演变成了一场病态的军备竞赛。是时候戳破这个泡沫了:LeetCode 根本选拔不出优秀的软件工程师,它正在毁掉我们的行业生态。
一、 真实的工程世界,从来不是一道“闭卷考试”
让我们先来看看,一个现代软件工程师的真实一天是怎样度过的。
你可能会花一整个上午,在一堆没有注释的“屎山”代码中追踪一个诡异的内存泄漏问题;你可能会在下午和产品经理反复拉扯,确定一个新功能在微服务架构下的 API 边界;你可能会在排查为什么 Kubernetes 集群里的 HPA(水平Pod自动扩缩容)没有按预期触发,或者研究 Istio 网关的流量路由策略。
如果你身处最前沿的 AI 领域,你可能正在评估是用 LangGraph 还是 AutoGen 来构建多 Agent 协同流,或者在调试大模型 API 的 Top-p 采样参数,试图让生成的回答既准确又具有随机性。甚至,在业余时间,你可能在设计一款解决自己痛点的小工具——比如一个用来清理、分类和管理繁杂书签的浏览器插件。
这些工作有一个共同点:它们都是极其复杂的、高度依赖上下文的、开放性的问题。
而在真实的工作环境中,我们解决这些问题依靠的是什么?
- 查阅文档与搜索能力: 我们有 Google、有官方文档、有开源社区,甚至现在还有 AI 助手。
- 调试与试错能力: 我们通过打日志、单步调试、看监控指标来定位问题。
- 架构视野与经验直觉: 我们知道什么时候该用单例模式,什么时候该用工厂方法;我们知道在高并发下如何设计缓存策略,如何保证数据一致性。
- 沟通与协作: 我们需要阅读别人的代码,也需要让别人看懂我们的设计。
反观 LeetCode 面试,它创造了一个极其不真实的无菌实验室环境:
- 题目边界清晰,输入输出明确。
- 只有单一的“最优解”(通常是时间复杂度和空间复杂度的极限)。
- 不允许查阅文档,甚至不允许使用趁手的 IDE(有时只能在网页的纯文本框里写代码)。
- 偏离日常使用的技术栈(你可能用 Python 写了十几年业务,却要用 C++ 的思维去考虑指针和内存管理)。
这就像是要求一个现代战争中的王牌飞行员,在面试时去比拼谁的射箭准头更好。它考察的不是“解决问题的能力”,而是“在极其受限条件下的默写能力”。
二、 刷题面试,正在惩罚真正有经验的“老兵”
在软件开发领域,经验是一笔巨大的财富。一个拥有 10 年、15 年工作经验的研发架构师,他最大的价值并不在于写代码的速度有多快,而在于他踩过足够多的坑。
资深工程师知道,一个系统最大的危机往往不是算法复杂度从 变成了 (很多时候硬件资源和缓存机制完全能弥补),而是:
- 数据库连接池配置不当导致的雪崩。
- 缺乏熔断降级机制导致的服务级联故障。
- 领域模型设计错误导致的后续需求无法扩展。
- 业务逻辑耦合过深导致的测试困难。
然而,当这位资深架构师带着一身的实战本领走进面试房间时,等待他的却是一道“动态规划(DP)”的 Hard 题。
这是一种极大的资源浪费。一个能在生产环境中稳稳掌控全局、能设计出高可用 AI 基础设施、能带领团队攻坚克难的资深人才,仅仅因为最近几个月忙于项目交付、或者忙于应对生活中的变故(比如寻找新机会、照顾家庭),没有抽出几百个小时去死记硬背算法题库,就被无情地贴上“技术不过关”的标签淘汰出局。
这种现象导致了一个极其荒谬的倒挂: 那些刚刚毕业、没有写过一行生产环境代码、不懂得什么是持续集成、不知道如何进行线上排障的学生,只要花三个月把 LeetCode 刷个滚瓜烂熟,就能在面试中大杀四方;而那些真正在一线扛过枪、打过仗,能够解决复杂工程灾难的老兵,却在白板前因为忘记了一个状态转移方程而涨红了脸。
企业以为自己招到了“绝顶聪明”的天才,结果新人一入职,面对极其复杂的微服务依赖和一团乱麻的业务逻辑,立刻束手无策。因为真实的业务系统里,没有人会为你准备好整洁的 ListNode 或者 TreeNode。
三、 算法题面试的本质:一场低效的“智商服从性测试”
为什么即便怨声载道,这么多公司依然痴迷于 LeetCode 面试?很多面试官会辩解说:“算法题能考察候选人的聪明程度和逻辑思维。”
这其实是一个伪命题。
1. 算法题早就不测智商了,它只测“准备度”。 在互联网早期,用算法题面试确实能筛选出一些思维敏捷的人,因为那时没有题库。但现在,LeetCode 已经有上千道题,“面经”满天飞。面试不仅变成了开卷考试的闭卷化,更变成了一门应试产业。能解出 Hard 题,往往不意味着你绝顶聪明,只意味着你刷到过原题,或者你花了大把时间去背诵套路。这充其量是一场“服从性测试”——看候选人愿不愿意为了这份工作去吃毫无意义的苦。
2. 忽视了工程中最关键的“可维护性”。
在 LeetCode 的评价体系里,“代码跑得快”是唯一的真理。哪怕你的代码里全是 i, j, k, dp, res 这种毫无语义的变量名,哪怕你的逻辑晦涩难懂如天书,只要能 AC(Accepted),你就是赢家。
但在实际工程中,这种代码是灾难。好的工程师写出的代码是给人看的,其次才是给机器执行的。如果你的代码在生产环境中出了 Bug,同事半夜被叫醒排查,看到满屏追求极致技巧却毫无注释的“炫技代码”,他大概率会在心里把你骂上一万遍。LeetCode 培养出的“做题家”思维,与团队协作所需的工程素养往往是背道而驰的。
3. 面试官的“安全牌”与偷懒。 其实,很多面试官也根本不知道该怎么面试。对他们来说,从题库里随机抽一道题扔给候选人,是最省事、最没有风险的做法。如果你没写出来,那是你不行,面试官不需要承担招错人的责任。这种做法掩盖了面试官自身架构视野和识人能力的匮乏。要深入了解一个人的项目经验、技术深度和系统设计能力,需要面试官投入极大的精力和极高的技术水平去进行深度的技术探讨,而“考一道题”则轻易地把压力全抛给了候选人。
四、 如何打破僵局:回归工程本质的面试方法
批判之后,我们需要建设。如果不考 LeetCode,我们该怎么筛选优秀的软件工程师?真正的面试,应该是一场对日常工作的高度模拟。
1. 结对编程 (Pair Programming) 不要让候选人在白板上写代码,给他一台配置好 IDE 的电脑。面试官准备一个真实但简化过的业务小项目,或者直接在公司的一个开源代码分支上,两人结对协作。
- “我们现在有一个 Python 的服务端,用 FastAPI 写的,现在需要增加一个中间件来做简单的限流,你打算怎么做?”
- 允许候选人查阅文档,允许使用 Google。
- 观察他的编码习惯、他对框架的熟悉程度、他如何拆解问题,以及更重要的——他如何与你沟通和协作。
2. 代码审查 (Code Review) 给候选人一段存在各种“坑”的代码(可以是以前团队写出的真实烂代码,隐去敏感信息)。这段代码可能存在并发竞争、内存泄漏、或者设计模式的滥用。 让候选人进行 Code Review。优秀的工程师能立刻嗅出代码中的“坏味道”,并提出合理的重构建议。这比让他默写快速排序要有效得多。
3. 深度系统设计与项目复盘 抛弃那些假大空的“如何设计一个推特”的八股文。让候选人深度讲解他简历中最自豪的一个项目。
- “你在简历中提到主导了容器化改造,能画一下当时的 Kubernetes 架构图吗?”
- “在使用 Ingress 和服务网格(比如 APISIX 或 Istio)时,你们遇到了什么性能瓶颈?是如何排查的?”
- “你提到在做 AI 相关的研发,在整合底层大模型接口时,你们是如何处理长上下文带来的延迟问题和 token 消耗的?” 通过深度的追问,直到触及他的知识边界。真正的行家,在谈论自己亲手一砖一瓦建起来的系统时,眼里是有光的,细节是经得起推敲的。
4. 聊聊他创造的“小玩意儿” 一个真正的工程师,往往是对技术充满热情的创造者。与其问算法,不如问问他平时都在折腾什么。如果他告诉你,他因为受不了浏览器书签太乱,正在自己设计开发一个管理书签的插件;或者他为了解某种新技术栈,自己搭了一个爬虫和数据展示网站。请让他展示一下!这种对痛点的敏锐察觉和动手解决问题的能力,是任何算法题都无法衡量出的核心特质。
五、 结语:放过工程师,也放过企业自己
技术招聘走到今天“无算法不面试”的地步,是整个行业的悲哀。它消耗了工程师们原本可以用来学习新框架、钻研底层原理、甚至陪伴家人的宝贵精力;它也让企业错失了大量踏实肯干、经验丰富的实战派人才。
编程,是一门结合了逻辑、工程、设计甚至艺术的创造性活动。它不该被简化为一场机械的背诵比赛。
作为面试官,下次当你准备掏出一道 LeetCode Hard 题时,不妨停下来问问自己:“这道题,真的能帮我找到那个能和我并肩作战、一起扛住双十一流量洪峰、一起在深夜排查诡异 Bug 的可靠队友吗?”
如果不能,请放下那道该死的算法题,和候选人像真正的工程师一样,聊聊真实的架构,看看真实的代码。
把时间还给工程,把尊严还给工程师。