程序员要掌握的知识,要具备的能力实在太多,多得头发都不够掉。

大体有两大方向。一是对工具的熟练掌握,如操作系统、网络、IO、编程语言等;另一个是用代码为现实问题生成解决方案的能力,这其中最重要的是抽象能力。

前一个方向是很容易意识到的,很多现象可以说明这一点,比如,世面上介绍如何使用语言、框架的书汗牛充栋;比如,很多人眼里进这一行的门槛是上1个月的语言培训课。

工具的意义不容否认,为此我还写过一篇《工具优先》。但工具的生命周期其实很短,从个人发展角度看,把过多时间投入到半衰期很短的事物上,并不划算。我入门时接触的是Pascal, BasicScript, ASP, IIS,不知道现在还有没有人用这些。很多程序员也赶时髦,本来写java的,golang流行了,python流行了,学!本来搞业务开发的,大数据火了,机器学习火了,学!打的旗号自然很鲜明:持续学习。几次之后,却怅然若失,貌似没一个是拿得出手的,不过是低水平重复,换个工具,继续做原来的事而已。充其量效率提高了,但效率型工作是可替代性最强的,被其它人替代,被机器替代。

一颗上进爱学习的心,怎么就被辜负了呢?因为核心能力没有提升。人的能力好比电子围绕原子核旋转,大部分情况下处于巡航状态,在这过程中不断积蓄能量,始终向核心方向用力,就会跃迁到更高级轨道(这里指更靠近核心的轨道,实际电子是更远离核心的道)。“一万小时理论”和“10万行代码理论”只片面强调了量,如果没有聚焦核心,刻意练习,只能是低水平重复,甚至轨道降级。

核心是抽象能力。这个世界的运行,有讲逻辑的,也有不讲逻辑的。程序员要处理的事是讲逻辑的那部分,因为你所依赖的计算机是讲逻辑的,要让它意气用事,感情用情,目前还很困难。通过抽象,我们识别并保留逻辑部分,抛弃其它内容,然后用计算机语言翻译、实现这个逻辑,进而解决问题。

抽象这个词,本身就挺抽象的。到底什么是抽象?

抽象是去除多余和细节。比如下面这个标志,一看就懂是座拱桥,但并没有显示拱桥的幅度、宽度和长度,因为这些数据对于你意识到这是一座拱桥并没有帮助。

什么是多余信息,取决于目的。考虑地铁换乘图,其目的是告诉乘客该搭哪条线,在哪里换乘,所以保留了结构关系:站点的分布,以及线路的汇合点,但忽略了物理关系:站点的地理位置、相对距离,甚至扭曲了线路的方向。而如果是开车用的导航图,则必须保证比例尺和实际情况一致,方向也不能有差错,以免误导。

抽象是建立模板或蓝图。不少公司里有邮件模板、文档模板、PPT模板、报销单模板,等等,它们规定好了结构、风格,并留出一个个空白,使用的时候填空就好。模板描述不变的内容,变量则延迟到使用场景中确定。Java编程时,经常要应用各种设计模式,其实质是通过抽象,固化不变的,封装变化的。比如,很常用的模板方法,流程和步骤无论什么场景都不变,已经在父类写好了,将具体场景的方法在父类里声明,但延迟到子类实现,封装的是方法实现。又比如,创建对象时,不常写new Tesla(),而是运用简单工厂模式,写成TeslaFactory.create(),因为对象的创建是易变的。与其在特斯拉多一个型号时,把所有new的地方都改一遍,不如在create方法里集中改。

总之,抽象是应对变化,或者说寻找不变性的手段。既可以是不同事物之间的不变性,也可以是同一事物不同历史时间的不变性。虽然这里讲的是编程,但其应用远不止于此,看看贝索斯是怎么说的:

我常被问一个问题:“在接下来的10年里,会有什么样的变化?”……但我很少被问到“在接下来的10年里,什么是不变的?”我认为第二个问题比第一个问题更加重要,因为你需要将你的战略建立在不变的事物上。

有了上面的解释,便不难理解面向对象编程的原则:依赖接口而不是实现,依赖抽象类而不是具体类。它让代码的适应性更强,将来少改代码,少出错。同时,做一些参数设定时,更加有理有据,而不是trial and error。线程池大小怎么定?不用关心具体工作,分析阻塞和非阻塞的时间比例,应用Amdahl’s law搞定。队列大小怎么定?不管究竟放的是什么,确定你期望的排队时长,用Little’s law算下。

世面上鲜有讲如何培养抽象思维的书,设计模式一类的,算搭一点边,但那是人家抽象的结果,而不是关于抽象的方法。也许我们在运用这些模式,或浏览一些工具和类库的代码过程中,偶有灵光一现,能从这些结果中反推作者的设计思想和精妙之处,毕竟它们也是抽象的结果。

学习使用工具时,如果多个心眼,留意为什么有这个工具,做了什么取舍,工具于你将不仅是效率意义。做业务开发时,如果不是简单地翻译需求,多想一层,哪里易变,哪里不易变,如何隔离变化,再简单的开发,于你也有精进意义。

抽象的层级可以有很多,能做多少层级的抽象是一种能力,而判断需要多少层级的抽象则是一种艺术。

地上一个猴,树上七个猴,一共有几个猴?1+7=8,一共八个猴,用数字符号代替猴子,这是第一层。从对象到数字,大多数人对此熟悉到甚至没有意识到这是一种抽象。再进一层,则有些困难了,当初我理解“加速度”这个概念,就费功。不光是数量,还有结构的抽象,关系的抽象。当然,它们离我们都很远……

可是,真的很远吗?当大部分人在关心如何写程序时,有人开始研究如何用程序写程序,当大部分人在关心如何看书、学习时,有人在教别人看书、学习。