TL;DR 程序员不是吃青春饭,关键是每3-5年完成一次技能跃迁,用稀缺性换取选择权

工作这些年来,一直在思考着程序员这个职业究竟是在做什么,随着经验增多,其实也一直在刷新着认知。现在写这篇文章,一方面是为了分享,另一方面也是想留下一份记录,过两年再回头来看看自己的认知又有了什么更新。

程序员职业的本质

我想从两个方面来说。一是从做的事儿上,在我看来,程序员的工作就是发现问题、分析问题、解决问题三类。事实上,世界上绝大多数工作都可以囊括进这三类事中。二是从能力上来看,我把能力分为两种:对现实世界的认知能力,和将现实世界映射成程序语言的能力。

对于三种类型的事,按发现问题,分析问题,解决问题的顺序,是从宏观到细节的区别,平时做的事,肯定是以解决问题为主,各种琐碎的事,也都是在解决问题。发现问题和分析问题对人的思维深度会有更高的要求,不过对于工作来说,我倒并不觉得这三类事有什么高下之分。如果对确定的问题,总能给出恰当的解决方案,这也是职场上非常硬核的核心竞争力。而对于两类能力,一般还是更关注第二种。但是我觉得对现实世界的认知能力,对于程序员的职业发展是非常重要的。就像抠业务,抠CRUD这事,有门槛吗?我觉得是有的,至少把业务做的很好门槛非常高。有些人总是以非常奇特的方式去实现业务,然后赖产品经理需求描述不清楚,很可能就是缺少对现实的认知。

接下来,就按发现问题、分析问题、解决问题的顺序,分别详细说一下。

发现问题的能力,对程序员来说,其实不是必需的。很多问题,即便你发现不了,或者发现了然后假装它不存在,系统一样可以运行的很好。但是,逐步的累积这种问题,最终必然会导致代码不可维护。下面,我拿一个自己的实际经历来举个例子。之前做过一个旅客飞行记录的项目,国内航班的数据,我们几乎都能拿到。数据存储的时候,主键是用的证件号,为什么呢,因为所有的订票系统,都是用证件号去做key的。但是我们的产品形态并不是这样,而是以用户的维度去显示,一个用户会有多个证件。这样就导致了一个问题:任何一个非常简单的问题,比如要查用户最近一条飞行记录,最近十条飞行记录,都会有一套复杂的处理流程。更不用说随着数据量增加,要分库分表,但同一个用户的证件没法往一张表上落,逻辑复杂度再提升一级。在这个时候,不发现这个问题,其实业务也完全开展的下去,但是很显然,做这块业务就会做的很难受。而意识到这是个问题,再做相应的调整后,才会发现原来这一块的业务如此简单。

那么,怎么才能发现问题呢。这需要我们有对现实世界的认知能力,也需要对设计模式等基础知识有足够的理解。要发现问题,我们首先得有“正常状态”是什么样子的概念,与正常状态不一样的,就是问题。比如前边的例子,一个“正常状态”是查询用户最近的飞行记录,这个需求应该非常简单,还有一个“正常状态”是我们的用户是一个人,而不是一个证件,发现了和政策状态不一致,也就发现了问题。再举一些例子,写单元测试应该是很简单的,当发现单元测试不好写的时候,就需要考虑一下是不是代码的设计出了问题;mysql的一次batch请求,耗时的数量级应该在毫秒级, 而且数据量不应该严重影响耗时,当发现数据量和耗时的关系成了一个非常陡的线性关系,就要考虑一下是不是真的做了次batch(参考 https://lichuanyang.top/posts/63688)。

接下来是分析问题。对于分析问题,我觉得说白了就是把一个表现出来的问题,拆解成一个或若干个“指标”出了问题。这些“指标”,可以是内存、cpu这样实际的指标,也可以是一些基本的概念理解、设计思路。还是上一个例子,我们发现的问题就是一些很简单的需求实现起来很难,最后拆解出来的出问题的“指标”就是存储记录主键的选择。

对于分析问题,要会做合理的可能性推测,然后多利用工具验证或者推翻猜测。之前有一次发现数据存不进数据库,这时候就可以做出若干个合理的推测:数据库本身有问题;和数据库的连接有问题;事务未能正常提交;逻辑错误导致数据未能生成;等等。然后去翻日志,看有没有报错,看Mysql监控,有没有大量未能提交的事务。逐步就定位到问题了。

技术深度 vs 技术广度

最后说解决问题,对大部分程序员来说,这个一直会是做的最多的事。而程序员的解决问题,也就是把现实中的概念在计算机中表示出来。其中最关键的,我理解有两个,一是分解任务,把一个大任务拆分成若干个独立的子任务;二是迅速的理解并使用新工具能力,也就是持续学习的能力。很多人会经常抱怨程序员要学的东西太多了,学不过来了。不过一定要注意哪些东西是值得花费大量时间去学的,哪些东西是简单看看就足够了的。发现有很多人热衷于工具的学习,喜欢写各种版本的Hello World, 这个在我看来就是无效的学习。编程方面的学习,需要兼顾深度和广度,深度,是需要非常透彻的研究一些技术,这个看了一些之后,你会发现各种技术,看起来可能没什么关系,比如数据库和消息队列,但是其中就是会有非常多相似的概念和思想。学过一些之后,就可以建立起自己的知识体系了,然后再去学其他的东西,就会非常快。

因为一个新技术的产生,必然是迫切的要解决一些实际问题。比如为什么会有clickHouse, 因为mysql等的按行存储不适合数据分析,而市面上又没有性能、稳定性都比较好的列存储数据库。再比如jedis直接连redis-server, 在多线程环境下表现不好,所以有了Lettuce。当知道要解决什么问题后,就可以先试着想一下换成你的话,有什么解决方案。然后再去看看人家实际的解决方案。如果方案很接近,那么恭喜你,你对技术的理解已经又上了一个高度。如果不一样,那也恭喜你,又学到了一种新的思想。这些思想,在以后做业务的时候,随时都可以化用。

我的职业观

共勉。

原文地址: https://lichuanyang.top/posts/27398/

常见问题

Q: 程序员是吃青春饭吗?35 岁后做什么?

把程序员看作”吃青春饭”是一种误解。作者认为程序员的本质是发现问题、分析问题、解决问题这三种能力——这些能力是随经验增长的,绝非青春饭。35 岁后的出路取决于你在前十年积累了什么:如果只停留在”被告知需求 → 编码实现”的层面,年龄确实会成为劣势;但如果积累了对现实世界的认知能力将现实映射为程序的能力,35 岁后恰恰是价值最高的阶段。解决中年危机的唯一方式是在每一份工作中持续获得可以带走的能力。

Q: 技术转管理好不好?什么时候该转?

这个问题文章没有直接回答,但从作者的能力模型框架可以推导:技术和管理只是解决问题的不同手段,核心问题始终是”你最有信心的能力是什么”。如果对现实世界的认知能力(理解业务、沟通协调、资源整合)强于将现实映射为程序的能力,管理方向更适合;反之则继续深耕技术。不必把两者对立起来——很多技术 Leader 本质上是在用技术视角做管理,而纯管理岗位如果没有技术判断力,在技术团队中很难真正发挥作用。关键不是”该不该转”,而是”转之前有没有积累足够的技术深度”。

Q: 技术深度和技术广度哪个更重要?如何平衡?

作者的观点是:深度先行,广度在后。先深入研究几个核心技术,建立起知识体系后,再去看其他技术会发现有大量相似的概念和思想(如数据库和消息队列中都有 WAL、分区、复制等模式)。作者的判断标准很实用:当你学一个新技术时,先想”如果让我来解决这个问题我会怎么设计”,再看实际方案——如果方案接近,说明理解已到新高度;如果不一样,就学到了一种新的思想。至于”写各种 Hello World”式的学习,在作者看来是无效的

Q: 如何发现代码或系统中的”隐性”问题?

作者给出了一个判断准则:知道”正常状态”应该是什么样子,与正常状态不一致的就是问题。具体信号包括:1) 单元测试很难写 → 代码设计可能有问题;2) MySQL batch 请求耗时就应毫秒级,如果数据量轻微增加耗时陡增 → 可能没真正做批量;3) 一个语义上很简单的需求(如”查用户最近十条飞行记录”),实现却很复杂 → 数据模型或主键设计可能背离业务本质。这些判断力来源于对现实世界的认知(知道什么是”正常”)和对设计模式等基础知识的理解(知道”正常”在代码中应该长什么样)。