任何一位工程师都不可能了解所有领域的技术知识;任何一个团队也不可能包含所有类型的专业人才。而一个完整的产品被开发出来,或者一个系统被构建出来,这个过程都会用到种类繁多的技术,一般来说总会有一部分超出当前团队所能掌握的现有经验。这个矛盾怎么解决呢?这就需要工程师来进行技术攻关了。
没错,工程师的真正价值就是把未知变成已知的能力。
现在假设你的leader交给你一件你从来没接触过的任务,比如,它可能涉及到研究若干框架以及系统架构,优化某些算法,设计和实现某一类型的网络协议,对音视频进行处理,研究系统底层,甚至这个过程可能会涉及到一些复杂的数学知识。总之,这项任务对你来说有点复杂,你从来没有接触过,所以完全没有概念。
你之所以领到这样一项任务,首先,是因为项目在当前或者未来需要解决这样的技术问题,而团队中没有人有现成的经验能够应付。另一方面,你肯定是在以前的工作中表现出了过人的学习和研究能力,你的leader才敢把这个工作交给你。
我在上篇文章《
马拉松式学习与技术人员的成长性
》中提到过,按技术领域来划分,编程可以分为「一般性」和「专业性」两大类。作为一件需要进行技术攻关的任务来说,它有可能会涉及到一些「专业性」的领域了。我相信,每一位执着于技术的工程师,在他成长的过程中,总会碰到类似的经历,去挑战一些自己未知的东西。在这个过程中,既为团队解决了眼前的问题,也为自己打开了一片新的技术天地。这也是技术小白进阶到专业人才的必经之路。
今天,我就根据自己的经历和体验,说一说从零开始进行技术攻关的一系列过程,以及可能碰到怎样的一些问题。希望你看完能有共同的感受。
有些情况下,你的leader没法告诉你具体应该做什么,他只是告诉你问题是怎样的,比如,视频播放总是卡顿,或者,用户总是说丢消息,再比如,用户反馈说搜东西的时候结果给的不准,打语音或视频电话总是接不通,总是有些图片访问不到,诸如此类。
我们第一步应该做的,就是先研究问题本身是怎么产生的。首先试图从用户的角度去理解问题,然后从技术的角度去了解现有的实现,包括细节。这时候,全局的视角变得非常重要,你如果既能理解服务器的逻辑,也能理解客户端的逻辑,那么解决问题的思路会大大开阔。有些“系统性”的问题,属于设计缺陷,并不是做局部改动就能解决的。这种问题,对于只接触客户端编程或只接触服务器开发的工程师,解决起来就有难度,他们考虑问题的思路容易被见到的东西限制住。所以,适时扩大自己的知识域,永远都有好处。
如果问题足够复杂,我们可能还需要增加跟踪日志,便于在出现特殊的问题时能够分析它发生的过程;并定义性能指标,对现有系统的总体状况有一个量化的度量。它们一方面有助于我们更深入地理解当前系统,另一方面也为后面的优化和重构过程提供了方向。
通过对问题本身的研究,我们知道了系统的瓶颈或问题症结在哪里。如果我们发现只有推翻现有系统完全重构才能根治问题,那么接下来就跟从头开始设计一个全新系统的过程一样了。
在接触一个新领域之前,对它进行一个总体的概览是很有必要的,这让我们对后面整个的精力投入做到心中有数。
这个阶段的目标是,花最短的时间快速了解相关的各个概念,不求深入理解,只求了解技术概况。所以,这个过程怎么快就怎么来,选择自己熟悉的方式。可以去你自己喜欢的技术社区搜索相关的文章,或者通过百度搜索一些概念。很多人不建议用百度来搜索技术问题,但了解一些概况还是没有问题的,不过要适可而止。等到真正需要系统地研究技术细节的时候,还是应该直接阅读更规范的资料(后面我们还会提到)。
在当今的技术条件下,几乎什么技术领域的问题都有开源的软件可以借鉴。如果针对我们要解决的问题能找到开源项目,那么非常幸运,我们探索的过程会大大缩短。
很多技术领域都存在众多抽象的概念,通过前面Overview的阶段,我们一般只能了解到这一层。而开源项目能帮助我们快速地将抽象的概念具体化,获得感性的认识。下载一份代码,编译通过,然后运行起一个简单的Demo,从API层面去理解它(内部的实现尚不是重点)。
很多情况下,开源的实现不止一个,这就面临一个选择的问题。人们对于开源项目的第一印象一般来源于项目的入门教程(tutorial),可见一份好的文档对于一个开源项目来说多么重要。根据我个人的经验,文档是否健全,也是选择开源项目的重要依据。
当然,在这个阶段,我们要解决的主要还不是选择开源项目的问题,而是要通过快速Run起一个相关的实例来达到对技术获得感性认识的目的。注意这种感性认识是技术层面的,是至少基于API层面的。我们经常看到,对于一些热门的技术领域,很多非技术人员也能略知一二,甚至对一些技术概念有所了解,但是,技术人员与非技术人员的区别,应该说,从这个阶段开始就有所不同了。
能够Run起一个实现,并从API层面粗略地了解一项技术之后,在这个认识的基础上,我们就差不多可以找同行交流一下了。如果在我们正要涉足去研究的领域里,我们恰好认识一些这方面的专家,那么无疑是非常幸运的。逻辑清晰的技术高手,一般用不了几句话就能把某项技术的关键问题描述清楚了。从这种交流中,我们受益匪浅。
但要注意,我们一定要在对该项技术有所了解之后,再去找专业人士交流。否则这种交流建立在信息严重不对称的基础上,就是极其低效的。对该项技术的初步了解,也是让我们能问出真正有效的问题的基础条件。
我曾经写过一篇关于如何学习新技术的文章《
技术的正宗与野路子
》,在文中提到的一个重要的观点,就是一定要找到能称得上Spec的文档去阅读。所谓Spec,是集中体现该项技术的设计思想的东西,是高度抽象的描述,一般也是一份完备的、系统性的描述。它的存在形式有很多种,可能是一份官方文档,也可能是一份公开的技术标准,比如RFC或者W3C的规范,还可能是以论文的形式,甚至与其它技术资料混杂在一起。
总之,你应该设法识别出哪些文档是Spec,然后在需要的时候通读它们。有些涉及到抽象概念的技术,你不读通这么一份Spec,有可能后面是看不懂代码的。这确实是比较费力的一个过程,但也正是这个过程,才真正开启了从门外汉向技术专家迈进的征程。
假设我们找到了开源代码可供参考。前面我们已经能Run起来一些小的Demo了,并且基本通读了一份大而全的Spec,现在需要研究的就是再深入一层,看看这份Spec中的关键点是如何实现出来的。你前面已经花了很多时间来调研,这中间肯定产生了很多疑问,比如有些抽象的概念以及相似概念之间的联系还是难以理解,有些过程的实现初看起来并不是那么地显而易见,而现在就到了该解决它们的时候了。头脑中的疑问和关键点,要自己总结出来,然后在代码中去找到答案,这是把抽象概念最终落地的一个过程。
如果有多个开源的实现,那么就涉及到如何选择的问题。有很多因素需要考虑:
-
文档是否健全。
-
提供的特性能否满足要求。
-
API层面逻辑是否清晰。很多代码在你初步接触了API这一层之后就大概知道自己是不是喜欢它了。
-
模块化和抽象层次是否足够好。这决定了你把这份开源代码集成到自己项目中的难易程度。
-
是否仍然有人维护。你当然希望在提issue和pull request的时候有人能够响应。
有可能我们要实现的东西其他家的线上产品已经提供类似的功能了。我们有必要在实现自己的方案之前研究一下他们的做法(逆向工程),对比之后从而做出一个更优的实现。
具体怎么研究呢?两种常见的方式:一种是反解客户端的包,看看里面引用了什么,是不是在我们调研过的那些技术范围之内;另一种当然就是抓包,从网络通讯上猜测他们用了哪一类技术。
经过前面的调研,我们基本上已经在头脑中产生了自己的方案了。但在真正实现它之前 ,我们一般还想做一件事,就是「循证」。