什么才算是真正的编程能力?
编程能力是一种解决问题的能力。如果问题没能被很好地解决,知道再多也没用。编程能力是一种运用机器解决问题的能力。首先是要判断问题在什么程度上可被机器解决,比如理论计算机科学会告诉我们什么可做、什么理论上不可做、什么理论上可做实践上不可做。然后是让机器更好地理解问题,比如计算机都是(图灵-冯诺依曼模型)等价,但不同的问题可能会适用不同的编程语言。再后是让机器能更高效率地解决问题,比如同样的问题可能会有效率差别巨大的算法。编程能力是一种抽象问题的能力。借用轮子是很好的办法,省力省时间。今天任何软件工程师都会有意无意地使用很多轮子,从操作系统编译器数据库网络到算法数据结构。想高效地借用轮子,就需要将问题分解再分解,抽象再抽象。任何一个实用的系统(不包括教科书上的示例程序和简单的脚本程序)都需要进行大量的分拆和组合。所以系统设计是编程能力里的高级技能,加合理的假设简化问题尤其有难度,此处不展开讨论。高手和新手的区别在于新手往往不知道轮子的适用范围,而高手的手上轮子数量多且熟知各种轮子的差异,所以对不同的问题可以轻松地找到合适的轮子,当实在找不到合适的轮子时可以自己动手改造现有的轮子。
没有严格意义上的真正编程能力,只有解决问题的能力。你解决的任何问题都依赖于别人解决过的子问题,所以不存在绝对的原创还是复用。这个问题就有点像 XKCD 某漫画,生物学家笑社会学家不纯粹,化学家笑生物学家不纯粹,物理学家笑化学家不纯粹,数学家笑物理学家不纯粹。其实大家工作在不同的维度,不能说一个维度的工作足够成功别一个维度就可以被取代了。化学足够好就能解决所有生物学问题吗显然不是的。你用开源项目来搭应用,你有你的上游和下游。上游是要有人去写开源项目,里面有些很多的算法是很多人长期优化的结果。没有这些人专注于细节,就没有那么好的开源项目给你直接拿来用。你的下游是更大的软件项目。你一个人的输出能写一个小应用,但在一个大应用里只能算是个功能。在公司里会有高级工程师用你写的功能来搭大应用。再下流而有公司的高管负责用多个应用来组合出公司的战略。在这过程中,真正有趣的问题是如果你的上游不存在了,你还能解决同样的问题吗?如果你依赖的开源项目不存在,你怎么办?如果存在但 bug 很多,你会选择怎样解决?分析和解决这种问题的 meta 能力很重要。你能做好的话,换不同的具体问题你都能有一套方法解决。
计算机科学有两类根本问题。一类是理论:算法,数据结构,复杂度,机器学习,模式识别,等等等。一类是系统:操作系统,网络系统,分布式系统,存储系统,游戏引擎,等等等等。
理论走的是深度,是在追问在给定的计算能力约束下如何把一个问题解决得更快更好。而系统走的是广度,是在追问对于一个现实的需求如何在众多的技术中设计出最多快好省的技术组合。搞ACM的人,只练第一类。像你这样的更偏向于第二类。其实挺难得的,但很可惜的是第二类能力没有简单高效的测量考察方法,不像算法和数据结构有ACM竞赛,所以很多系统的苗子都因为缺少激励和正确引导慢慢就消隐了。所以比尔盖茨才会说,看到现在学编程的人经常都把编程看作解各种脑筋急转弯的问题,他觉得很遗憾。做系统,确实不提倡“重复发明轮子”。但注意,是不提倡“重复发明”,不是不提倡“重新制造”。恰恰相反的,我以为,系统的编程能力正体现在“重新制造”的能力。能把已有的部件接起来,这很好。但当你恰好缺一种关键的胶水的时候,你能写出来吗?当一个已有的部件不完全符合你的需求的时候,你能改进它吗?如果你用的部件中有bug,你能把它修好吗?在网上繁多的类似功能的部件中,谁好谁坏?为什么?差别本质吗?一个开源代码库,你能把它从一个语言翻译到另一个语言吗?从一个平台移植到另一个平台吗?能准确估计自己翻译和移植的过程需要多少时间吗。