《编程的修炼》:程序员的思维必修课

《编程的修炼》:程序员的思维必修课

原创程序猿阿诺2021-01-13 16:55:05

引言

中国的互联网行业在过去二十年中,迎来了跨越式的发展,以至于能在世界上有一席之地。这一堪称奇迹的背后,不能不提那一众默默辛勤工作的程序员们,他们用飞舞的双手在键盘上创造了这一切。

但程序员这一工作,却越来越被贴上“青春饭”的标签。诚然,互联网公司招聘时公开的年龄限制,就是一个直观的证明。不过我对此有不同的思考。

对于一名程序员来说,如果他从新人到成长为熟练工程师,其所掌握的仅是对工具的运用,那么度过了年龄的红利期,必然会面对职业发展的瓶颈。

因为这样的程序员相对于其他人来说,只具备年龄上的优势,当失去这一条件时,就面临失去一切的境地。那么,程序员应该让自己拥有怎样的优势,能够突破职业瓶颈呢?

毫无疑问,改变思维,让自己看到别人所还没看到的,自然就走在了前面。这又需要回到程序员本身来说,仅是把代码写好,把程序调试完上线就下班回家睡觉,这样就足够了吗?

显然还不够,程序员应当从更深的层次来思考自己的工作。意外的是,一本写于三十多年前的书——《编程的修炼》,给了我不少的启发。

在说这本书之前,我们要先说一下此书的作者Dijkstra,他对程序设计的诸多开创性工作,实在是太重要了。

Edsger W. Dijkstra

Edsger W. Dijkstra是一位荷兰计算机科学家,他在计算机的诸多领域都有杰出的贡献,其中最为人所知的就是提出了结构化编程的思想。即编写程序只需要顺序、选择、循环三种结构就可以了。

这一点在我们现在看来,好像就是天经地义的,难道不是本该如此吗?

这要回到Dijkstra所处的时代来看这个问题。他给ACM通讯写的那封著名的“Goto letter”信件,是在1968年。那会儿计算机还是一门高深的学问,懂编程的都没几个。

要知道第一台PC机Altair还要在六年以后的1974年才会被发明出来,编程这项工作就没有规范可言,大家都是奔着功能能实现就行。

可想而知,这样写出来的代码充斥着混乱不堪的“goto”跳转,也被称之为“面条式代码”。并因此在上世纪六十年代爆发了一场软件危机。即照这样去写代码,那么全人类都是程序员,也生产不出需要的软件来。

当结构化编程成为一种规范时,软件工程才得以继续发展,并有了今天我们所看到的数字化世界。Dijkstra也因其贡献而获得1972年的图灵奖,可以说是实至名归。

因此,我们看到Dijkstra他更多的是一位思想者。也许大多数人都是在埋头赶路,而Dijkstra则是少数几个能抬头看路的人之一,而他甚至还站在了高处看向更远的地方。

那么,Dijkstra对于编程的思考,则精萃于《编程的修炼》这本书中。接下来让我们细细体会。

Dijkstra

一本讲编程却没有实例可运行的书

对于当代的程序员们来说,最流行的一句口头禅,恐怕是“talk is cheap, show me your code”。如果拿出一本关于讲如何编程的书,但书里没有一行可以实际运行的代码,结果会怎样?

在你打算放下这本书并转身离开时,我建议你先忘掉上机操作这件事,然后再来细心看这本书。

为什么要忘掉上机操作?

因为面对机器操作,虽然可以很快知道结果,但不一定会去仔细体会产生结果的过程。而《编程的修炼》正是在最大程度上摒弃了可实际操作带来的任何影响,让我们专注于算法的逻辑推理中。

我也知道,这对于现在的许多程序员们来说,并不容易。因为进行一项学习,最好是马上就能在工作中用得上的,那才会有动力。

例如,一个能解决当前问题的开源库;一段现成的代码;一个固定的模式。总之,不需要去思考,拿来能用就可以。

但成为这样毫无创造力的程序员,不说在事业上能有多大发展空间,就算是作为这个职业本身,我觉得甚至都不能称之为程序员。或者叫那个程序员们自嘲的“码农”会更合适一些,不管过程怎样,结果是对的就行。

需要说明的是,这本写于三十多年前的书,里面的内容偏学术化,没有多少与现实的结合。不像现在讲编程和算法的书,总可以从一个现实的应用出发,那就会更好理解。

原因也很简单,因为那个时候计算机还多是用来做纯科研计算,谁也无法预知它会如何改变我们的世界和生活。但是Dijkstra的厉害之处就在于, 不仅规范了软件开发的方式,也提出了许多经典的程序算法。

例如加权有向图中的最短路径算法,就以Dijkstra命名,要是没有这个算法,那么就没有现在的导航应用,可能你自驾出行的方式还是膝盖上摊开一张地图,你在艰难地寻找着标志物。

既然已经做好了准备,那接下来就先了解一些基本知识,以便深入学习吧。

阅读准备

在《编程的修炼》中,Dijkstra没有遵循任何一门编程语言的语法,而是自创了一套文法规则和约定,让大家可以将注意力集中到他思考的过程上。

书中诸多的示例都是采用一种循序渐进,逐步推进的方式来讲解。往往会在初始时设定一些简单的条件,然后提出问题,接着给出一个解决问题的框架。

在对这个框架进行正确性论证之后, 又对其中的步骤进行精细化讨论。最后,一个经过严谨推理的答案,也就形成并确定下来了。

将一个大的问题分解,并逐步求精,这是我们现在实践软件工程的一个基本原则。而在三十年前,一切还都在混沌之中的时候,Dijkstra就给我们展示了这样超越时代的智慧之光。

下面对一些概念和规则进行简单说明。

后条件:系统完成活动之后所处的状态。

最弱前条件:从这一初始状态激活之后,能保证系统一定完满的终止,并将达到一个满足给定后条件的最终状态。

谓词转换器:给定一个后条件,然后能够推导出与之对应的最弱前条件的规则。

卫式命令:分支或者循环处理语句,说明如下。

格式:<guarding head> ::= <boolean > -> <statement>

示例:if B1 -> SL1 [] B2 -> SL2 fi

如果使用现代编程语言风格,则示例表示如下:

if B1 then    SL1 elseif B2 then    SL2 end

程序员的两种能力

在技术论坛里,新手们一个常问的问题是:想学编程一定要学好数学吗?

对于这个问题,以前我都会留言说不一定。因为我本人就并不是数学特别好的那种,在学校里的成绩也就是及格的水平。工作多年,还真没有说有用到哪个数学公式来解决问题的。

但如果对数学的理解只停留在这样的水平,其实还是有问题的。在《编程的修炼》中,Dijkstra就提出,程序员的编程能力应当包括数学能力与工程能力。

而我显然是片面强调了工程能力,忽视了数学能力。工程能力,就是对问题进行分析后,能从过往的经验中找到一个合适的答案,并将其付诸实施。

不难看出,工程能力,就是将事情做对的能力。可是如果需要程序员自己提出问题呢?或者说对于要处理的问题,它本身是否有答案呢?这考验的就是程序员的数学能力。

具备优秀数学能力的程序员,能够以严谨地推导对问题进行思考,从而发现问题是否有解,以及可能的最优解会有怎样的时空复杂度。

举例来说,在没有运用数学思维的情况下,我最可能做的就是不断地尝试各种方案,一个不行再换另一个。也许在付出可观的工作量之后,凑巧找到了答案。但也有可能根本就是无解的问题,我所有的付出就白费了。

所以,对于本节开头提出的那个新手问题,我现在要修正我的回答,应该是:学会编程,找到一份工作,可能数学能力要求不会那么高。但如果想要将这份工作持续做下去,那么就一定要修炼数学能力。

结语

实话说,《编程的修炼》并不是一本很好读的书,它需要我们能够静下心来,跟随着Dijkstra的思路,去细细地品味他通过推导去解决问题的思维方式。

我也知道,你一定很忙,客户在投诉,老板在拍桌子。但我想你也一定不愿意一直在这样的状态下工作,那不如抽出时间来,给自己一个提升思维能力的机会。

也许,掌握了这本书的精髓,解决问题再也不费劲了,代码质量还上了一个台阶。客户天天写表扬信,老板笑脸相迎,工资年年涨,资金月月发。

程序员们,补上这门必修课吧!

收藏
举报
1 条评论
  • LLLol6小时前

    看看 hacker's delight 很多小算法

    回复1 
(0)

相关推荐