编程水平很高的程序员是如何训练出来的?

231 阅读20分钟

我们首先需要弄明白“程序”究竟是什么。(此文转载自乐字节)

原理很简单:计算机是一种能够在一秒钟内做出数十亿道算术题的设备;程序员可以通过与或非三种逻辑判断影响计算机的做题顺序,这种顺序可归结为顺序、分支、循环三种。

程序员的工作,就是抽取万事万物的数学骨架,把一切一切都归结到一大堆数学题上;然后让计算机通过计算这些题目,在“数学空间”把我们想要的任何东西模拟出来。

有很多东西需要根据情况随机应变,这个“随机应变”就对应于“分支”——情况A这样处理,情况B那样处理,这就是分支。

有很多东西是对海量实体套同一个模子,这个“套模子”就对应于“循环”——反复用同一段代码对排着队的不同实体做同一套操作,这就是循环。

图灵证明,只要有这么个支持,一切可抽象为计算的过程都可以用功能极其有限的一台机器执行。这种机器被称为“图灵机”。

当我们在“数学空间”把任务处理完之后,我们还需要操纵“外设”,比如显示器打印机音箱等等,把结果展示出来——这同样需要先做一套数学变换,然后通过IO口输出信号,就好像扳动了无形的“操纵杆”一样,控制各种外设和人类完成交互。

所谓“程序”,就是程序员们预先安排好的一堆指令;当计算机执行这些指令时,你需要的音乐软件、记事本、ppt等等,就先在数字安排好一切、然后再通过键盘鼠标显示器等等外设和你交互。

被存储在某处的那组指令就是程序;程序每次被CPU执行,就叫一个“进程”。

明白了这个,那么我们就知道了:

1、程序员需要抽取任何现实需求的数学骨架(或者说,理解一切需求内部的数学规律)

2、程序员需要把数学骨架翻译成计算机可以理解的指令

3、程序员需要用指令控制外设,把虚无缥缈的“用户界面”实实在在展示在用户面前、或者控制机器完成各种动作

其中的2、3属于基本技能,做不到就吃不了程序员这碗饭;但这个技能的上限也非常非常高,高到优秀程序员的工作效率可以轻易超过庸手十倍以上的程度。

为什么会有这么大差别呢?

差距主要就在1上。

优秀程序员深刻理解了计算机原理,因此从思路到实现毫无障碍。

优秀程序员规划能力极强,可以把很复杂的工作安排的井井有条、有能力把它分成很多简单单元逐一解决。

优秀程序员理解力极佳,可以透彻理解用户需求,透彻理解万事万物内部隐藏着的数学规律——因此,他们不仅知道自己要做什么、怎样做、为什么,还可以触类旁通,化一切规律为我所用。

当庸手出苦力一行行码代码时,高手早已洞悉了其中的秘密,于是用自行设计的一套算法让计算机自己寻找出路——甚至还可以证明这个算法一定能以最高效率完成工作。这差距,是不是一下子就拉开了?

举例来说,很多低级程序员喜欢吐槽“总是写重复的业务代码”;但是另一位程序员是这么做的……

例如我在乐字节的同事他找了份报社的工作,每天的任务就是把新闻报道整理一下发布到网站上。这显然是个毫无前途的工作,因为你只要每天脚打后脑勺的把稿件拷贝到html页面上就完了。毫无技术含量,只能拼体力出苦力,每天996、007,但总有海量的稿件等着你……而你,甚至都没有权力去改变稿件中的某个错别字!

这工作,到街上找个二傻子都干的了吧?

这人,这辈子,完了。

但是这条咸鱼还是想挣扎下。

他发现,所有的稿件都由几个部分构成,标题、作者、正文、引用,偶尔还有题图/插图。

嗯,标题得居中,用大号黑体字,不能倾斜,不能加下划线;作者用5号字,同样居中……

好嘛,尽是繁文缛节。做多了成了熟练工,一天也用不着干别的了……

但是,等等,重复劳动不应该让电脑做吗?你干嘛要自己做?你的编程学狗肚子里了?

于是,这条咸鱼搞了个“模板”,用{{title}}标记html中应该填标题的地方,用{{author}}标记html中应该填作者的地方……

那么,现在他只要找个地方保存这个“标准html”,然后用程序自动从数据库读取文章标题、作者等内容,把{{title}}代换掉……

你看,现在这条咸鱼彻底闲了:报社的同事们只要把文章上传数据库,他跑一下他的批处理——别说一天的工作,一年的工作他也能用几秒钟时间搞定。

毕竟他只需要敲敲键盘启动程序,剩下的苦活累活全是电脑的事,不是吗。

闲了的咸鱼开始琢磨。他把他这套模板系统进一步扩写、完善,然后作为开源软件发布。

最终,这个系统一炮打响。它就是著名的Django: baike.baidu.com/item/django…

让我们继续对你的惊吓之旅 ^_^

最近有朋友考驾照,特别怕科目三的直线行驶,一走就歪。

怎么办呢?

我告诉他,你往远处看,越远越好。比如直路上你可以看远方的地平线。

好了,问题解决。

你是不是要懵了:这都哪跟哪啊?江湖骗子吧?

放心。我还可以让你更懵:这,可都是三角函数的基本应用啊。你初中咋学的?

抓狂不?

听我解释。

当你操纵的汽车和道路之间存在一个夹角时,车子自然会在行驶一段距离后和道路越分越远;然后你着急一打方向,挂科。

那么,正确的做法是什么呢?

没错,那就是:从一开始就不要让车子行驶方向和道路形成夹角。

问题是,人的感觉是极不精确的。你怎么知道车子行驶方向和道路有无夹角?

所以,你只有紧盯边线,哎呀似乎靠左边了我打点方向……一打就多,一多就要从右边出线。赶紧再打,哎呀,左边又多了……车子喝醉酒一样来回一摇,挂科。

可是,你的“传感器”就这么不精确啊。怎么办呢?

并不是开车会走直线的都是天赋异禀的神仙。

还记得初中学过的三角函数吗?从一个顶点出发、相互存在一个很小夹角的两条射线,会随着距离……怎么样?

越分越远。直到这个距离远大于道路的宽度。

好,道路是一条直线,你的视线是另一条直线;而你端端正正坐在驾驶室里,正常情况下,你的视线和车行方向平行——告诉我,往远处看,当你发现车行方向不正时,你会发现什么?

没错,人的感觉极不精确;尤其道路那么宽,坐在车里时哪里看得见两条线的交叉点?哪里感觉得到这个角度?所以我们无法发现车行方向和道路方向存在夹角。

但往远处看,借助距离,近处的误差就被抹平,而视线和道路不在同一条线上时就会有明显的偏差,于是你是不是一下子就发觉了?

很好,打点方向纠正。

你看,借助距离,我们就加强了我们的感官精确度。

类似的,做自动控制,机器人用的传感器也没那么精确。怎么办?

很简单,“锚定”一个远期目标,不要硬测硬算。

如果列出误差传递公式,很容易发现里面会有个类似的项——这些项决定了若干个周期后,误差会放大到夸张的地步。

你要“锚”的近了,误差就会累积,就会引起震荡,就会造成项目失败;“锚”的远一点,那么误差的累积就很容易发现,就可以更快的回到正轨。

归根结底,这还是能归结到“∠A的两条边在距顶点R处的两个点之间的距离”上,归结到“两条直线的图像”上。

只不过,当年你是死记硬背、混过考试,还是把概念彻底吃透、然后又学出来学到生活中,那么在遇到问题时,你和别人就有了质的差距。

别以为这东西很无聊。知道当年海军测距用的合象式测距仪吗?当年有这玩意儿的英军打的清政府觉得洋人会妖法!

你,能把知识用的如此天马行空、信手拈来吗?

请注意,这个“信手拈来”可不是“随口就能解释清楚合像式测距仪”的工作原理,而是:随便需要一个什么样的需求,你都应该马上就能想到对应的数学原理、然后马上发明一种东西来实现这个需求。

必须注意:发明可比解释难多了。

仍以合像式测距仪为例——它恰恰正是从“专业知识”到“傻瓜式界面”的一个典型案例。

最初,你得到的需求可能是:设计一款测距仪器,要求皮实耐操、使用简便,要求战场上那些文化程度不高、惊慌失措的大头兵也能本能的用对。

面对这样一个需求,你怎样才能让甲方满意呢?

仅从知识储备上说,你需要:

深刻理解三角形测距原理,能够反向思考——什么测角度?什么千分尺?大兵们有那么镇定、有那么清晰的头脑吗?能够在战火纷飞的战场上完成一道三角函数题?还必须精确到小数点后XX位?

显然,在此之前,你必须深刻理解千分尺(螺旋测微器)工作原理,这才能把它和望远镜有机结合,从而直接把“拧旋钮对准某个目标”对应到“测量”——然后旋钮对应的读数就是最终距离。

但要做到这点,谈何容易。

你能让大兵跑这头拧拧镜头、把刻度对准船上某个定点;然后再跑那头拧另一个镜头,把刻度对准另一个定点吗?这段过程中,你自己的船转弯了呢?风吹着走了弧线了呢?对方转弯、看不到之前的标志物了呢?

因此,你必须设计一个机构,使得大兵可以在一个位置同时控制两个镜头、让它们对准同一个标志物。

然后,你还得根据两端测到的不同角度,计算距离……

你看,这难度高出天际了吧?

而“合像”这个思路就是个天才的设计。

它的思路是,两端两个镜头联动,使得当目标在视场中间时,测距基线的垂线恰好对准目标——于是两个镜头到目标的连线再加上基线恰巧构成个等腰三角形。这就使得最终只需考虑单独一个角就能算出距离,从而大幅降低了计算复杂度。

同时,借助“潜望镜”原理(看到没?又一个原理!),把基线两端的两个镜头的视野同时呈现在观察者面前——然后又是一个天才设计:不需要你一个个镜头对准目标上的同一个标志物,而是把两个镜头的视场各截一半;那么当你通过中间的目镜,把左右两边镜头视场对应的、同一目标的上下半拉严丝合缝的对到一起时,你已经完成了这个“对正目标”的操作。

复杂操作就这样被傻瓜化了。

现在,只剩最后一步:怎么把“角度”和“距离”联系起来。

注意这里是利用等腰三角形的底边长和底角角度算三角形中垂线的长度;因此调节旋钮转过的角度并不和垂线长度成正比。所以你不可能用拧一圈100米拧10圈1000米这种简单机构。你需要设计一套指示机构,并做一些稍微复杂的标定——最好还能把它“塞”进视场里去。

不过,相对于其他,这已经是简单的体力活了。

这里面用到了哪些知识呢?

三角形性质,三角函数;轮轴/螺旋;齿轮的啮合;杠杆转动角度如何与螺旋测微器联动;平面镜成像;凸透镜成像(光路分析:“上下视场对齐”是怎么和“角度测量”联系起来的)……

还有无法直观看到、但却必不可少的:机械加工精度、装配精度、温度补偿、战舰本身各种震动的消除(补偿)、润滑、抗(海水/汗液)腐蚀……

看到了吗?

你的几何代数物理化学……只要有任何短板,你做的了这个吗?

想做这个,你必须全能。

别说什么课本没写老师没讲。学以致用,这就是用。这就是要你在掌握了书本知识之后、自己在实践中推广的。

这东西太多太杂,而且会因地制宜、以各种匪夷所思的方式利用任何原理的任何细枝末节——或者说,各种概念的内涵外延你全都必须完全掌握,不允许有任何死角。

而要做到这一点,死记硬背毫无意义;你必须自己学会悟、学会推广——自己会走,才能想去哪就去哪。

——当然,我在这里选了一个物理设备举例。因为它看得见摸得着,没有接触过相关领域的读者多少也能有个感性认识。

如你所见,所谓“工程师”,就是理解很多很多学科的基本原理、能够在实践中恰到好处利用的人。软件工程师也不例外——如果你想要自己“优秀”的话。

拿我们熟悉、同时又总是看不起的美图秀秀来说吧。

我们知道,美图秀秀是个Photoshop的“抄袭品”,它做不了专业软件,只好把专业软件的功能拷贝下来实现个劣化版、然后主打小白市场……嗯,你看,不加掩饰的浓浓鄙夷。

不过……跟着鄙夷之前,你有没有问过自己——美图秀秀的原理是什么?哪本书讲过?你写得出来吗?

我想,如果问过自己,恐怕大多数人都不敢鄙夷了。

为什么呢?

因为哪怕你就是学计算机图形图像的,课本里也没教过你什么叫“肌肤遮瑕”“睫毛浓黑”……

而且……这俩不恰好是相反的吗?一个要去掉皮肤上细微的瑕疵,另一个反而要把皮肤上的黑色丝状物凸出……

所以你还必须继续“活用知识”。比如说,书上教过你“边缘捕捉”,教过你“大面积着色”,教过你“模式识别”……

你必须活用这些知识、用到你那些只会死记硬背的同学目瞪口呆的程度,再结合皮肤/美妆方面的常识,你才能在“浓黑睫毛”的同时,帮小姑娘们把脸上的黑痣自动点掉。

你看,虽说是“五毛钱特效”,可你照样得是个“万事通”——不然哪怕想“抄算法”,你都不知道该抄什么。

——Photoshop当然没开源;但gimp可是开源的,随便你抄。你抄的出美图秀秀吗?

可见,在软件设计中,类似的东西同样会贯穿始终,这才能把复杂繁难的专业技术对应到傻瓜都能掌握的“傻瓜界面”上去。

这就是为什么同样看了C程序设计教程,有的人马上就能上手做一些奇奇怪怪的东西、而另一些人一片茫然的原因。

而这种茫然,在你工作之后,会更加的普遍、更加的具有压迫力——当你的同事可以因地制宜信手拈来一堆解决方案之时,你不仅不知道他们“从哪学来的这些古怪知识”,甚至就连理解他们的思路都极为困难。以致于……就好像我见过的很多同事一样:你别和我说原理!要我做什么,你直接说!

——所以我不仅经常给电脑写程序,我还经常给人写程序:

要部署我这个软件,你要:

1、安装debian 9.10

2、登录debian,执行apt-get install sshd 安装配置ssh服务

3、……

没错。没有我写的一二三四,很多人连安装部署都不会;而且连debian的哪个版本都必须精确到小版本号。不然……他们可没能力随机应变(哪怕这个项目是跨平台设计,但你仍然必须逐个平台指定版本号写一二三四的部署流程:给人写程序比给电脑写程序更麻烦,因为你不能让他们做太多复杂判断、不能给他们太多太复杂的步骤。因为人可能看串行,而电脑不会)。

那么,你猜,如果你学成了这样……还有可能进步吗?

何况,从“提醒一下还是能回忆起学过的知识”到“勉强能明白别人的思路”再到“勉强能跟上别人的思路”再到“可以不费力的跟上别人思路”再到“能和思维跳脱的同事一起纵横捭阖、相互补充相互促进、把一个设计真正做到完美”——这里面,要走的路,可长的很呢。

仍以合象式测距仪举例:我压根没看过它的设计图、原理图;以上大段文字,都是我看到“合像”二字后脑子里一下子涌出来的。但我敢说,我画出来的原理图一定和实物图相差无几。

如果你将来能进入一个不错的公司,你就会发现,那些优秀的同事都可以轻易做到这些。

甚至,你想了很久、绞尽脑汁想出来一个方案(很可能比这个测距仪要复杂曲折的多);结果到了会议上,你才吐露一个词,人家马上就能把你的整个方案彻底领会贯通、甚至还能当即提出一些直击要害的问题来。

如果你也有这种能力的话,和这种同事的交流一定是非常轻松愉快的;和他合作,做任何事都可以很轻松:你稍微一提,他能把任何细节都考虑到,直接给你个成品出来。

而另一些同事,你苦口婆心一遍遍的给他们解释,他们也领会不了这种明明很简单的问题。好不容易把每个要点都提到了,他还能给你做的差三落四,甚至连最最基本的核心功能都没做对。

而实际工作中,“编程水平”恰恰就体现在这里:能够长期、稳定、高效的实现某个具体功能只是个基本要求;更重要的,是能给团队指明方向,让他们知道怎么走才能抢到竞争对手前面、把别人不曾做到也不知道该怎么做的东西带到现实。

你看,当年的每一口夹生饭,你都要在实践中付出代价。

这些东西,会在编程实践中成为常识——理解计算机体系结构、打通数字世界和现实世界的藩篱,这是个很不简单的任务,它把很多很多人拦在了编程门外;但打通了之后,你能往数字世界搬进去什么呢?

很显然,你真正理解、掌握的知识越多,那么你就越是有更多东西可以搬进数字世界。相反,你的夹生饭越多——学了杠杆轮轴你懂不了变速箱玩不转发动机、学了电路你不知道收音机电视机如何工作——那么你就越是摸不着头脑。

如前面我举那个三角函数的例子。这东西太基础了,以致于对很多很多人——那些真正理解了知识而不是死记硬背的人——来说,这都是本能。

但是,如果你只会做题,如果你从未围绕着你学过的概念有过任何思考,那么别人的每一句话,对你都是天书。

——如果我不解释,恐怕大部分人都会觉得“看远点就能解决开车走不了直线问题”和跳大神一样呢。

那么,有没有想过,其实你我都学过的每一个知识点,别人都可能掌握到了这种程度呢?

那么,有没有想过,当会议上,别人在每一个话题上都如此天马行空、让你目不暇接时,你会是什么体验?

你压根就跟不上他们的思路。

在他们看来,压根就没有难题,随随便便一个方案接一个方案就提出来了,随随便便就能想出特殊场景来对不同方案做出挑战、完成取舍。

但哪怕他们掰开了揉碎了给你讲,你都怎么也转不过弯来。

你压根想不到自己学过的知识还能这样用;他们则理解不了人人都学过的那么点简单知识,居然……只是死记硬背?!

综上,优秀的程序员已经不仅仅是比拼对计算机系统本身的了解了——那只是基础。

他们真正比拼的,是对这个世界认识的深刻程度;是因地制宜的把脑中杂七杂八的知识拿来、解决实际问题的能力。

这种东西是怎么训练出来的呢?

很简单,从小就要多动脑,要真正把任何知识理解了、活用了;千万不要通过死记硬背这类手段逃课。

人生是个马拉松。

你在小学手工课上耗费的时间并没有白费;你好奇的拆开玩具、摆弄钟表收音机所付出的努力成为了你的积淀;你“不务正业”的胡思乱想、对科普对科幻的痴迷使得你更早的接触了本质……

现在,它们终于体现出价值来了。

给大家推荐个很不错的免费自学课程,java全套1056集从入门到进阶必看B站:BV14h411U75p