当我们聊技术实力的时候,我们到底在聊什么

聊聊架构 2018-05-09

作者 李运华

点击关注 聊聊架构,置顶公众号

 

作者|李运华
编辑|小智
更多李运华的精彩文章,请关注他的专栏《从 0 开始学架构》,点击文末 阅读原文 即可订购,与一万八千人一起学架构知识。
技术实力的迷思

俗话说“文无第一,武无第二”,技术就是一种“文”的能力,很多时候我们很难直观看出一个技术人员的实力,但不管是公司招聘的面试,还是公司内部的晋升面评,都需要在较短时间内快速判断一个技术人员的实力。正因为技术实力评价本身没有绝对客观的标准,很多时候都会听到类似的吐槽:

“我们组内的 XX 技术实力不如我,竟然他晋升通过了,我却被刷掉了,评委真的是~!@#¥”……

“面试官问的都是什么鬼问题,我知道的基本没问,我感觉他根本不会考察我的技术实力”……

“听说算法和数据结构最能体现程序员的实力,我要好好啃啃《算法导论》”(然而啃完又忘记了)……

……

还有很多类似的问题和吐槽,背后都可以归纳为一个问题:当我们聊技术实力的时候,我们到底在聊什么?

有的人认为:技术实力就是指算法和数据结构很厉害……

有的人认为:研究过 Linux 内核源码和看懂《深入浅出 MFC》的才是技术牛逼的人……

有的人认为:会写 C++ 的才是真正的技术高手,因为 C++ 的对象初始化有 N 种写法……

有的人认为:技术高手必须对业务很熟悉……

有的人认为:贡献了开源项目代码的才是技术牛人……

有的人认为:只有架构师才是技术大牛……

……不一一列举,相信一千个人眼中有一千个哈姆雷特,一千个程序员心中有一千个技术大牛!

技术实力的本质

得益于工作岗位的关系,我在考核技术人员的实力时积累了较丰富的经验(包括踩坑的经验)。首先是招聘,前后面试了几百个人吧,技术范围包括服务器、android、iOS、前端,既包括初出茅庐的应届生,也包括腾讯的 T4 大牛;其次是晋升评委,作为职业等级晋升的评委,面评过几十个晋升的技术同学,各种案例都见过,也与其他评委一起互相交流,有时候甚至是针对某个同学通过还是不通过产生争执。通过这种不断的实践、思考、踩坑、交流的过程,逐步形成了一套完整的方法论,接下来就谈谈我的这套方法论,分享一下我是如何判断技术人员的技术实力的。

简单来说,判断技术实力的一个总的原则就是:技术实力就是指解决问题的能力

我们将这个原则细化一下,可以得到几个细则:

1)不存在放之四海皆准的技术

简单来说,问题是和领域相关的,技术是用来解决问题的,因此技术也是领域相关的,不存在放之四海皆准的技术。

有网友说:高斯林来做 iOS 开发,分分钟秒杀现在所有的 iOS 开发人员,因为目前 iOS 经验最丰富的开发人员,经验也不过 10 年。我认为这是不可能的,iOS 开发领域面临的问题,和开发 Java 编程语言面临的问题差异很大,当然,如果高斯林真的做上几年 iOS 开发,确实可能超过很多 iOS 开发人员,但一开始就秒杀哪些做了 7~8 年的 iOS 程序员,这个是不可能的。

2)技术要能解决具体问题才有价值

技术只有能够解决某个领域的问题才有价值,否则光知道某个技术没什么用;掌握了某个技术但在当前的领域用不上,这个技术对当前领域来说也没有价值。

当然,确实存在某些技术可能在当前看起来对当前领域没有用,但后面可能会用到,因此技术人员需要自己储备一些当前暂时没有用的技术以拓宽技术视野,例如当前大火的人工智能和区块链技术,但要注意“可能”这个词,这需要技术人员自己进行判断和平衡,不能拿技术储备作为托词一股脑的什么都储备,例如数据库开发工程师至少在这几年是不需要储备 VR 知识的。

3)问题的复杂度决定技术实力的高度

问题的复杂度不同,复杂度越高,解决起来越困难,相应的技术实力要求也越高。

我们拿这个原则去分析一下前面提到的各种技术实力的理解:

“技术实力就是指算法和数据结构很厉害”

很多面试官喜欢让面试者现场手写冒泡排序、快速排序、链表之类的代码,以此来判断面试者的技术实力,但我们用这个原则去分析一下就可以发现,这样并不能考核技术实力,假如招聘了一个会手写快速排序的面试者,招进来后你会让他用自己写的快速排序解决什么问题?貌似绝大部分场景下都不可能让一个新来的员工自己写个快速排序来解决某个问题吧?

当然,肯定还是有人会说“我考核的是面试者的技术基础和思维能力”,这个说法没错,但如果是这个目的,现场手写快速排序这种面试方法就是错误的,如果是考察技术基础,考核的范围应该是算法的基本逻辑,优缺点、适用场景,因为这些技术点在后续具体应用中选择合适的算法来解决问题的时候很有用;如果是考察思维能力,考核的方式应该是给一个具体的算法应用题,来看看面试者的分析和思考过程,例如我在知乎上给了一道我们业务上曾经用到的“如何快速计算你好友的好友和你的共同好友数”,没想到引起了评论里面的大讨论,有兴趣的朋友也可以尝试一下。

“研究过 Linux 内核源码和看懂《深入浅出 MFC》的才是技术牛逼的人”

国内技术人员(不知道国外是否类似)对于底层技术有一种偏见,认为只有懂底层才是真正的技术高手,否则都只是简单的调用 API 完成功能。我当年也不例外,我曾经说过“程序员的三个大坑:Linux 内核源码、编译原理(龙书)、深入浅出 MFC”,我每个都跳过,而且还花费了大量时间却收效甚微。其实用原则去分析一下就可以发现这个说法也站不住脚,如果我们从事 Linux 内核开发,编程语言开发,MFC 框架开发,这些技术确实能解决问题;但如果做得不是这些领域的开发,这些技术并不能帮我们解决什么问题,我还没见过哪个 Java 编程的问题需要我去用编译原理的技术去解决,也没见过哪个数据库的问题需要我去研究 Linux 内核源码才能解决,当然并不是说这些问题一定不存在,Java 语言本身肯定也有 bug,但这些问题是需要 Java 官方去解决,我们在应用中无需亲自去解决,否则的话,效率会非常低,个人爱好无可厚非,但团队必须考虑效率。

“会写 C++ 的才是真正的技术高手,因为 C++ 的对象初始化有 N 种写法”

这是程序员群体里面永恒的一个话题,哪个语言才是最好的最牛逼的,其中两个著名的梗:PHP 是世界上最好的语言,C++ 是世界上最牛逼的语言。C++ 确实语法复杂,功能强大,真正能完全掌握 C++ 的程序员应该屈指可数,但这是否意味着掌握 C++ 就牛逼了呢?并不尽然,我们拿原则来分析一下,如果用 C++ 做游戏引擎,或者高性能中间件,C++ 确实能解决问题,但如果我们做的是 android 手机资讯 app,C++ 能解决什么问题呢?自己写个加密库可能比系统带的库漏洞还多,自己用 C++ 写个 SQLite 好像没什么意义。

“架构师才是技术大牛”

架构师几乎是每个程序员的技术梦想,能够成为架构师(真正的架构师,不是 PPT 架构师),技术实力肯定很强,这点是没有争议的,但问题是当不上架构师就不是技术大牛么?我们用原则来分析一下就会发现并不是这样的,架构师并不是全能的,他解决的主要问题是系统的结构设计,还有一些问题是架构师不能解决的,例如 MySQL 5.6 版本通过优化一个 false sharing 问题,性能提升 50%,

(http://www.cis.upenn.edu/~delozier/docs/tmi_micro_2017.pdf)

这种问题点的发现和处理并不比架构设计简单,能发现和解决这个问题的技术人员实力非常高。

以上分析了几个典型的误区,其它的观点,这里只贴一下简单的答案,大家有兴趣也可以套用这个原则去分析一下具体的原因,基本上八九不离十:

技术高手必须对业务很熟悉” —— 正确

“贡献了开源项目代码的才是技术牛人”—— 错误

技术实力详解

理解评估技术实力的基本原则后,我们知道了需要解决的问题复杂度越高,技术实力就越高。在这个基础上,我把技术实力分为两大类 6 分类:

  • 硬实力:真正解决问题的能力,别人可以看出来的能力,技术实力按照“点、线、面、体”的 4 个分类逐层上升;

  • 软实力:比硬实力更厉害但也更虚的能力,简单来说,要想解决问题首先得发现问题,但很多时候问题并不是一目了然的,需要有一定的技术洞察力。软实力主要包括 2 个核心能力:发现问题、技术创新。

硬实力

我把技术硬实力分为四个等级:点、线、面、体,技术等级依次提升,解决的问题复杂度也越来越高,下面详细解释一下。

 技术点

“点”就是某个具体的技术,用来解决某个具体的问题,例如使用 JDBC 从数据库读取数据,目的是解决数据掉电丢失的问题;使用 Java 多线程,目的是为了解决大量用户并发访问的吞吐量和时延问题。掌握了技术点,就可以开始基本的业务功能开发了。

 技术线

“线”就是一系列相关的技术点组成,每个技术点都是为了解决某个问题。例如:

  • 为了完成一个用户请求,开发框架首先要有路由 router 功能,路由到具体 Controller 后,Controller 进行业务逻辑处理,处理过程中可能会使用 JDBC 来读取数据,访问 Redis 读取缓存等,这一连串的技术每个都解决了一个问题点,串起来就完成了一个业务功能的处理过程。

  • 为了定位一个线上 Java 服务器响应慢的问题,需要用到 tcpdump 抓包,使用 Java 工具查看 jvm 的状态,使用 mysql 命令行或者工具查看数据库状态,使用 explain 分析可疑 SQL 语句。

掌握了技术线,就可以完成某个业务功能的全流程设计和开发了。

 技术面

“面”就是某一类相关技术线的综合。例如:

  • Java 开发是一个技术面,包括多线程、JDBC、文件读写、JVM 调优、JVM 工具等多个技术线;

  • 高性能开发是一个技术面,包括:数据库分库分表、缓存、多线程、HTTP 优化等;

  • 数据库维护是一个技术面,包括:数据库调优、数据库问题定位、高性能数据库表设计等;

掌握技术面,已经是某个领域的专家了,简单来说就是这个领域的问题找你都可以搞定。

 技术体

“体”就是多个技术面的综合。

最常见的“体”就是架构设计,对于一个大型业务或者系统的架构师来说,需要掌握多个技术面,然后进行设计和取舍。例如,一个后台架构师需要掌握 Java 的技术面、数据库的技术面、网络的技术面等,以及业务领域知识。

架构设计是横向技术面的综合,我称之为广度技术体;还有一种纵向技术面的综合,我称之为深度技术体。例如 Java 的开发工程师,当达到技术面的水平时掌握了“多线程、JDBC、文件读写、JVM 调优、JVM 工具等”,如果需要进一步在 Java 这个领域提升技术,就需要向下了解操作系统、硬件(CPU、内存、磁盘等),从而更好的解决某些复杂的问题,例如 Disruptor 高性能并发框架的设计。掌握了技术体,就可以进行架构设计,或者成为某个领域的资深专家了,解决领域级的复杂问题

软实力
 发现问题

有的问题很明显,例如线上出故障,系统性能不达标,系统性能需要达到 5W QPS;但有的问题并不那么明显,并不能一眼看出是问题在哪里,是技术问题还是管理问题。

例如我们曾遇到团队间协作开发效率很低,每次开发一个业务功能,都需要几个系统的研发人员来讨论接口协议、接口数据格式、接口安全加密、业务逻辑等,大家都不厌其烦,但好像又都必不可少,团队间为了提高效率,项目经理制定了规范、流程、模板等,但作用最终都不大。那后来是怎么解决的呢?通过引入服务中心来完成系统间同步接口调用,通过引入消息队列来完成系统间异步消息通知,系统间协作效率大大提高,以前要开会讨论几个小时的事情,现在只要明确接口传输的数据内容即可,甚至都不用开会,两个研发一讨论就差不多了。

除此以外,问题的根源往往掩盖在很多问题表象之下,如果不解决根源问题,解决一个表象问题,获得一时安宁,一段时间后又发生另外的问题,长此以往反反复复。

例如我们曾有个系统,今天交换机故障导致业务问题,明天系统 bug 导致业务问题,后天机柜断电导致业务问题,还被黑客攻击过,这些问题看起来都很独立,问题的发生也感觉都是偶然的,按照出一个问题解决一个问题的方式也没什么问题,但全年来看,业务就是出了很多问题,怎么解决?我们经过分析,发现根本原因是业务需要异地多活,而架构是双机房单中心的,我们需要做到的不是避免每个问题的发生(事实上也不可能避免),而是应该做到问题发生后能够快速处理,于是通过将架构重构为异地多活,重构完成后还是有各种偶发问题发生,但对业务的影响就很小了。

发现问题的能力主要来源于经验,包括成功的经验、踩坑的经验、参考别人的经验,因此如果要培养自己这方面的能力,多思考、多总结、多学习、多参加行业交流。

 技术创新

达到这个级别基本都是业界大神一般的级别,说实话我也没什么经验,只能仰慕这些大神。

例如:

  • 当年贝索斯要求亚马逊公司内的系统都服务化,后来是哪位大神想到可以把这个能力开放出来转换为“云计算”?

  • 阿里云王坚博士当年在众人都不看好的情况下为何坚持云计算是未来?

  • Google 在解决大数据问题时,如何能够提炼出三篇论文,开启了一个大数据时代?

技术实力案例点评

一个面试者面试 Java 技术专家岗位,其中有一项项目经验很牛逼:XX 架构重构,性能提升 10 倍。于是,我针对这个项目经验进行了深入的考察,结果……

下面是我们大概的对话过程:

我:请简单介绍一下这个项目重构

面:我们某个业务和比赛有关,每次关键比赛前业务访问量是平时的 10 倍以上,原来的系统量一大就卡死了,用户体验很不好,需要重构。

我:具体怎么做的呢

面:我通过引入 mc 缓存,将原来直接访问数据库的操作改为先访问缓存,性能比原来提升了 10 倍。我:为何你想到了引入 mc?

面:(卡了一下,有点惊讶我的问题)……我上网查了一下资料,很多都说 mc 能够大幅提升性能,并且使用后确实效果很好。

[点评 1] 这是典型的“代码靠抄,方案靠搜,效果靠试”,面试者看到了一个问题,但没有分析和思考,然后上网搜方案,看到了好像很多人都说引入 mc 都能解决问题,于是尝试引入了 mc,最终确实好像解决了,这让面试者自我感觉良好。

为何我在面试的时候问“为何引入”,这是不是一种“面试造航母,入职拧螺丝”的装逼面试呢?其实不然,我们的业务中遇到性能瓶颈的问题是非常常见的,而简单的“性能瓶颈”只是一个表象,我们看看可能的原因有哪些:

  1. 数据库慢查询,例如不合理的查询、没有索引、表数量太大等;

  2. 并发设计不合理,例如多线程锁设计不合理,采用了不合理的 Reactor 模型等;

  3. 代码逻辑不合理,例如本来可以异步处理的也采用了同步处理,某个循环里面重复访问数据库,某个接口打印了大量日志等;

  4. 外部系统性能低,例如依赖的某个系统性能低,太多无效的外部接口请求等;

  5. 数据访问不合理,例如没有用缓存,没有分页等;

  6. 非核心业务和核心业务互相影响

以上仅仅是举例,还有更多可能的原因,如果一个技术专家不具备“面”的技术,只知道 mc 可以提升性能这个“点”的技术,是远远不够的,一次运气好能解决问题,但不可能次次都运气好。

当然,如果面试的是“Java 高级开发工程师”,面试重点和面试问题又不一样了。


我:mc 能大幅提升性能的原理是什么?

面:缓存访问快,数据库访问慢。

我:那 mc 性能多高,数据库性能多高?

面:……(想了 10 秒)抱歉,没有研究过。

[点评 2] 这是典型的知其然不知其所以然,开源方案拿来就用,基本的测试和原理研究都没做过。大部分人对于很多概念的理解都是“性能高”,“可靠性好”,“听说很厉害”,但在具体设计的时候,这个理解是远远不够的,一定要量化,例如:同样是负载均衡,Nginx 的性能量级是万级,LVS 是 10 万级,F5 这类设备是百万级(具体数值和硬件以及数据包大小相关,这里只给量级)。

为何要研究原理呢?以 mc 为例,一致性 hash 和扩容相关,内存分配方式和缓存容量有关,如果这些都不清楚,实际应该部署多少 mc 节点,每个节点应该分配多少内存,这些都没法确定。


我:没关系,那我们换个问题,重构后你们的系统用到的机器数量是多少?相比重构前减少了多少?

面:机器数量是 100 台,相比重构前没有减少。

我:哦,100 台机器,QPS 每台才 300 多,我看你们的业务也不是很复杂,为何这么低?

面:……(卡住 10 秒)这……300 多 QPS 好像也不低吧?

我:那你有没有分析过每次请求全流程每个阶段的性能耗时?瓶颈在哪里

面:(卡住 5 秒)没有分析过呢?

我:那为何就认定引入 mc 就有效果?

面:……(卡住 10 秒)我看大家都说引入缓存能大幅提升性能,而且最终效果确实很好。

[点评] 这就是知道技术点,不知道技术线和技术面,按道理对于系统性能问题的分析,至少是技术线级别的,需要分析每个请求每个阶段的耗时和原因;也可以是技术面级别的,例如分析数据库的设计、服务器的负载均衡等,还可以是技术体级别的,例如架构是否合理,是否可以将某个子系统拆分,引入消息队列等。

我:好吧,换个问题,如果让你再一次优化系统,你觉得可以怎么做?

面:……(思考 20 秒)我觉得目前的系统性能已经足够,应该不需要优化了。

[点评] 考察的是发现问题的能力,但他发现不了问题,其实前面已经都提到了,100 台机器就是问题,QPS 过低也是问题,但由于他没有经验,是看不出这些问题的。

很遗憾,最终这个面试者没有通过面试。

写在最后

对于技术人员实力的判断,并不存在完全客观和可量化的标准,多少都带有评判者的主观判断,这也是最容易产生争议的地方,本文也是我自己的一个思考和总结,一家之言,抛砖引玉,欢迎大家探讨交流。