【导读】:作为程序员,你会如何跟非程序员解释写程序不容易这件事?为啥看不见摸不着的程序需要花时间去写去维护?很多人其实都没想明白。来看看 Erlang 之父 Joe Armstrong 的感触。
编程为什么这么难?
多年前我曾一度认为编程很简单,然而随着岁月的流逝,我终于意识到编程并不是件容易的事。这是因为,我所认为的「究竟什么是编程」和「程序员到底是做什么的」,在感知上已经渐渐地发生了转变。
定义1:所谓程序就是一种把输入转化为输出的东西,程序员就是写程序的人,编程就是写程序的这个行为;
现在让我们给我对程序的这个定义加一些约束吧。
定义2: 所谓程序就是在遵从下列约束的条件下,把一些输入转化为输出的东西。
- 程序输出是优美的;
- 程序输入是优美的;
- 程序本身也是优美的;
- 程序输入有着完好并正确的文档;
- 程序本身也是有着完好并正确的文档;
- 程序是经过良好测试过并验证是正确的;
- 正在解决的问题是十分明确的;
- 整个问题本身也是十分明确的;
加上这些约束后,编程就变得非常困难了。现在对于一个特定的问题,上述一部分约束是可以放松的。几个典型的设想是:
不必持续维护的程序
我们经常仅仅为了得到输出结果而写程序。 这种情况下,程序的输入和程序本身以后是不需要维护的,因此这些不必诠释地特别优美和充分。
我的 Erlang 这本书就是这样的一个例子。一旦书出版了,为了写书而使用的程序以及输入部分就不必在维护了。程序结果看起来很优美,但是输入部分只是一堆混乱的 xml 文件,为了写书而用到的一些测试代码也永远不必保留了。
书的勘误表和为了后续重版的一些必要订正只是涉及到了输入部分的轻微修改,即使程序的输入部分并没有很完善的整理记录过,这也是很容易操作的。
必须要维护的程序
对于那些从头到尾都要进行维护的程序来说就是这种。程序的输入和程序本身都必须诠释地特别优美,文档和注释完整而优雅。
我不久之前和一位开发 Web 应用程序的计算机咨询师聊天。他说一旦程序的输出看起来没问题了(即网站看起来不错,程序似乎也可以运行了),客户就会认为项目已经完成了,项目经理就会把他分配到下一个项目上去。
在下一个项目启动之前,不仅网站要看起来不错,而且编写的代码也应该是整理有序并且有案可循的。但是人们没有空闲时间这么做,也无法理解这个观点。而这类项目就是在将来需要一直被维护的。
还有什么因素让编程困难?
还有其他三个因素让编程变得困难:
- 修复本不应该出问题的程序
- 没时间学习
- 编程的恶劣环境
这三个问题全是「时间的小偷」,让我们具体来看看:
修复本不该出问题的程序
为了解决某个特定的问题,我经常会使用既不是我写的,我也不是很理解的软件。最好的情况是,这个我不得不用的程序有一份描述精确的使用说明。 但是往往这个程序要么没有描述文件要么就是描述文件是错误的。
那么, 当文件写着:『做XYZ后,就会发生PQR』,而你做了『XYZ』后,『PQR』却没发生的时候,你该怎么办呢?如果你很幸运,写这个程序的人就在你旁边,那么你就能直接过去问搞定这些问题。不是这样的话,你要么用Google碰碰运气,要么就直接挖出源代码找答案吧。
用Google这个「大赌场」找怎么修复bug,真的是让人极度沮丧的事儿。我简单 Google 搜索一下,然后会发现一些记录,某个可怜不幸的家伙也遇到了和我正好一样的问题。我喜出望外,颤抖着用手指输入可以除掉诅咒的魔法指令…..然后…..啥也没有改变。问题依然存在。
为啥这修复工作对其他人有效对我没用呢。难道有个邪恶的神监视着我,还是我处于宇宙中暂时不符合物理规律的局部区域?我们两个机器的初始状态不同,因此在一种状态内修复一个机器bug的方法未必能修复另一种状态下机器的bug。
正像有时候我想用 smalltalk 编程,我们都用一模一样的程序映像开始着手-Smalltalk 的程序员必须活在这种情况不会发生的理想的天堂里,但是一旦有一天,甚至他们自己的程序可能不得不和其他程序对话的时候,好玩儿的事就开始了。修复被破坏的东西带来的沮丧是双重的,即便你已经赶走了bug,你也真的并不知道这是不是你要修复的最后一个问题,也不知道你所做的改变带来的实际影响。
顺便说一句,这类问题耗费了我大部分的时间, 粗率估算一下大概占用60-70%。我曾经用了超过一星期的时间试图让一个坏了的LDAP服务器工作,我的老板禁止我执行我自己的LDAP服务器,然而和这个用 C 编码归档混乱的坏了的 LDAP 服务器斗争了一周后,我记忆模糊了一些,也忘记了老板说的话,意外地在午餐休息的时候用 Erlang 在 scratch 里成功地运行了服务器。
老实说,这并不是一个完整的LDAP服务器,但是我也不需要一个完整的LDAP服务器。我只想运行一些命令而已,这其实是很容易修复的。 现在我对执行陈旧又变态的协议没有什么乐趣,而通常情况下最快的进行方式是在scratch里重新实现他们。
解决问题而不是学习
我懒,我就是个懒虫。当我想在LaTeX里放入一个图表的时候,我不想先读一遍391页的操作手册。现在我猜你肯定会指责我的懒惰和不健全的品德。我也知道我想应该先读一下这份优秀的手册,但是我想十分钟内在文档中放入一个图表,那么读完391页的手册是不可能的。解决这类问题时,我会选择更快的解决方法—但是长期来看这样损失惨重。
制作文档这事儿,我一直犹豫是使用TeX/LaTeX,XSLT-FO还是我自己的 Erlguten。
大约每三年我都有一次强烈的欲望把自己所有的文档直接在postscript中写一遍,然而之后我只是做个深呼吸后等这个想法慢慢消失。
我猜 Giambattista Bondoni 在 1818 年发明他的手工印刷的时候,并没有特别关心排版一页纸是否要花费几个星期。但是现在我们让机器做这些无聊又危险的事儿,我们就有了更多的时间却没有时间把事儿做对了。
我问我老板他是否需要一个炫酷的幻灯片做下次的讲座,他说需要并要求我在明天之前交给他。这使我没时间正确地学Tex(我估计几年可以完成这个事儿),也没时间实现我自己的排版语言(大概要用5年时间),也没时间在postscript里直接写(大概要一周左右)—这样我估计我还是用PowerPoint吧。
编程的恶劣环境
如果你读到了这里,你就会理解我说编程真的很难的话了。原因是工作场所就是设计来让编程更难的。我们开放的工作场所,提供了破坏我们聚精会神的吵闹环境,打扰我们的手机和让我们分心的因特网。
幸运的是,我们可以去不会打扰我们的地方。那就是睡觉。很多编程问题都是在睡觉的时候解决的。
有两个办法,第一你把问题上传到你的大脑里然后睡觉,第二天起床后一些问题就解决了。很简单。
第二,你把问题在睡前放到网上或者推特上。第二天就会有人发给你解决办法了。成为一个好的程序员是需要很长时间的,你需要学习很多的知识也需要知道当你卡壳的时候去问谁。
令人惊讶的事实
当我完成这篇文章的时候,我想检查下内容的拼写。 emacs的ispell模式罢工了。这个我一直用于拼写检查的程序,现在无法搜索到一个拼写。
我的emacs拼写检查器在这台机器上忠实的工作了好几年了。就在我抱怨花费半生时间修复本不应该出问题的程序的时候,我的emacs拼写检查器坏掉了。
我不信邪神,也不信我现在打字的起居室沙发的左边角落不遵循物理定侓。尽管有些间接的证据似乎在反驳我。
我不知道我的拼写检查器坏掉的原因—一切看起来都没问题,我没有改变任何东西。哦从我上次检查文本拼写后,我只安装了新版的Erlang安装了Julia,并写了一些讲座笔记而已。
幸运的是,在Google赌场里工作了11分钟后,第二个如何修复我的问题的建议起效了。 然而我还是不懂为什么 emacs 不能搜索一个拼写。人生苦短,来不及找寻所有答案。
我猜大概只是有些事情我们永远不会明白罢了。