理解Dijkstra的Mozart编程风格

20
我看到了这篇文章,是关于编程风格的,由Edsger Dijsktra提出。简单概括一下,主要区别在于莫扎特和贝多芬,当用于编程时,莫扎特在写任何东西之前完全理解(有争议的)问题,而贝多芬则在纸上写音符时做出决定,并在此过程中进行多次修订。采用莫扎特编程方法,1.0版本将是软件的唯一版本,应该旨在实现无错误和最大效率。另外,Dijkstra说,没有达到这种精细度和稳定性水平的软件不应发布给公众。
基于他的观点,有两个问题。莫扎特编程真的可能吗?如果我们采用莫扎特风格,今天编写的软件真的会受益吗?
我的想法是,为了解决日益复杂的软件问题,我们已经从这种方法转向敏捷开发、公共测试和不断修订的方法,这些方法定义了网络开发,其中速度最重要。但是,当我想到所有Web软件可能经历的修订,特别是在维护期间,通常会将补丁应用于补丁,然后通过繁琐的重构过程进行改进-莫扎特的方式似乎非常有吸引力。这至少会减少那些令人讨厌的软件更新,例如Digsby,Windows,iTunes等,这些更新往往是由于未预见到的漏洞而需要新的和即时的发布。
编辑:有关Dijsktra观点的更准确解释,请参阅下面的回复

1
这个比喻不太恰当。Dijkstra 从来没有主张仅凭头脑构思就能掌握所有细节。他主张使用形式化方法(因为逻辑已经被充分理解并且永远不会改变,所以是可靠的)来构建程序,而不是通常在行业中看到的“先编程,后测试”的方法。只有在程序已经被正式证明满足需求之后,才应该进行编程。这样一来,错误和“迭代”都受限于纸面之中,实际上不会被实现。 - isekaijin
10个回答

52

莫扎特编程风格是一个完全的神话(每个人都需要编辑和修改他们最初的努力),尽管“莫扎特”在这个例子中实际上是一个隐喻,但值得注意的是,莫扎特本身也是一个神话。

据说莫扎特是一个神奇的神童,4岁时就谱写了他的第一首奏鸣曲(实际上他是6岁,而且很烂 - 你永远不会在任何地方听到它被演奏)。当然,很少有人提到,他的父亲被认为是欧洲最伟大的音乐教师,并且他强迫所有的孩子在能够拿起乐器或笔之后每天练习演奏和作曲数小时。

莫扎特本人小心翼翼地使他的音乐看起来像是从他的头脑中整体产生,通过销毁了大部分草稿,虽然足够多的草稿保存下来表明他和其他人一样都是需要编辑的。贝多芬只是更诚实地阐述了这个过程(可能是因为他是聋子,无法听到是否有人偷偷接近他)。

我甚至不会提到莫扎特的旋律来源于听鸟歌的理论。还有这个事实,他创造了一个使用骰子随机生成音乐的系统(实际上相当酷),但也可能解释了为什么莫扎特的音乐似乎是从无处而来的。

故事的寓意是:不要相信炒作。编程是一项工作,需要更多的工作来修复你第一次犯的错误,然后需要更多的工作来修复你第二次犯的错误,依此类推,直到你死去。


15
一个关于真正的编程天才的Usenet经典故事。

真正的程序员用Fortran语言编写代码。

也许在这个充斥着"轻啤酒"、"手持计算器"和"易用性强"软件的颓废时代,现在的程序员们都不这样做了。但在那些美好的过去,“软件”一词听起来有些滑稽可笑,真正的计算机是由鼓和真空管组成的,而真正的程序员则直接用机器码进行编程,而非Fortran、RATFOR或汇编语言。机器码——裸露、神秘、难以理解的十六进制数字。为了让下一代程序员不至于无知于这段辉煌的历史,我觉得有责任穿越两代人之间的鸿沟,尽我所能描述一个真正的程序员如何编写代码。我将称他为梅尔,因为他就是这个名字。
我第一次见到梅尔是在皇家麦比计算机公司工作时。该公司是一家已经倒闭的打字机公司的子公司。该公司生产LGP-30,一种小型的、廉价(按当时标准)的鼓式存储器计算机,并且刚刚开始生产RPC-4000,一种改进得更多、更大、更快的——鼓式存储器计算机。电子线圈太贵了,而且不会长存。(这就是你没有听说过这个公司或计算机的原因。)
我被聘请为这种新奇玩意儿编写Fortran编译器,而梅尔则是我对这个奇迹的引路人。但梅尔不认可编译器。
他问:“如果一个程序不能重写它自己的代码,那有什么用呢?”
梅尔用十六进制写了一款公司拥有的最受欢迎的计算机程序。它在LGP-30上运行,并与潜在客户玩二十一点游戏。效果总是引人注目的。每次展览会都会挤满LGP-30展位,而IBM的销售人员则围着彼此交谈。这是否实际上卖出了电脑是一个我们从未讨论过的问题。
梅尔的工作是为RPC-4000重新编写二十一点程序。(移植?那是什么意思?)新的计算机具有一种一加一寻址方案,在其中每个机器指令除了操作码和所需操作数的地址之外,还有第二个地址表示下一条指令在不断旋转的鼓上的位置。用现代术语来说,每一个单独的指令后面都跟一个GO TO!把那个放进Pascal语言里然后就可以淡定地吸口气。
梅尔喜欢RPC-4000,因为他可以优化自己的代码:也就是说,将指令定位在鼓上,使得当一个指令完成其任务时,下一个指令就可以立即执行。有一个程序来完成这项工作,叫做“优化汇编器”,但梅尔拒绝使用它。
他解释说:“你永远不知道它会把东西放到哪里,所以你必须使用单独的常量。”
我很久之后才理解了这句话。由于梅尔知道每个操作码的数值,并分配了自己的鼓地址,他编写的每个指令也可以

2
你忘了故事的标题:“梅尔的故事”。请参考http://en.wikipedia.org/wiki/Mel_Kaye获取更多细节。 - CesarB

15

它无法扩展。

我可以在脑海中想出一行代码、一种例程,甚至是一个小程序。但是一个中等规模的程序呢?可能有些人可以做到,但是他们有多少人,需要花费多少钱?而且他们真的应该编写下一个工资单程序吗?这就像把莫扎特浪费在流行音乐上。

现在,请试着想象一个由莫扎特组成的团队。只需几秒钟。


它仍然是一个强大的工具。如果你能在脑海中想出一整行代码,那就这样做。如果你能想出一个包括所有有趣情况的小程序,那就这样做。

表面上看,这避免了因为没有考虑到需要完全不同的接口而回到起点的情况。

更深层次的含义(头脑飞翔?)可以通过学习另一种人类语言来解释。很长一段时间里,你会思考哪些词汇代表你的想法,以及如何将它们组成有效的句子——这个过程耗费了很多前台循环。
有一天,你会注意到一种让人感到自由的感觉,那就是你可以直接说话了。这可能感觉像“用外语思考”,或者“话语自然而然地流出”。有时候你会跌跌撞撞,寻找特定的单词或习语,但大多数时候翻译都在“潜意识CPU的广阔资源”中运行。


"高目标"是开发一个解决方案的心理模型,该模型(大多数情况下)独立于实现语言,以将问题的"解决"与"转录"分离。转录易于操作、重复性强且易于培训,而抽象的解决方案可以被重复使用。
我不知道如何教授这种方法,但是在开始编写代码之前尽可能多地了解问题听起来像是朝着这个目标的良好编程实践。

迪科斯彻也谈到了这个问题,如果你有兴趣读一下他写的东西的话。他说我们要把事情分成小块来理解每一个部分,然后再理解整体。但是大多数程序员和计算机科学家连小块都难以处理! - user9903

14
在这个名为“思维的纪律”的YouTube视频中,Edsger Dijkstra讨论了他对莫扎特与贝多芬编程的看法。

alt text

这个帖子中的人们已经讨论了Dijkstra的观点是不切实际的。我要试着为他辩护一下。

  • Dijkstra反对公司在客户身上“测试”他们的软件。发布1.0版本,然后立即发布1.1补丁。他认为程序应该被打磨到一个程度,以至于“热修复”补丁是有些不道德的。
  • 他并不认为软件应该一次性编写完成或永远不需要更改。他经常讨论他的设计理念之一是模块化和易于更改。他经常认为单独的算法应该以这种方式编写,但前提是你已经完全理解了问题。这是他的纪律之一。
  • 通过与程序员的广泛经验,他发现程序员不会满足于只是使用他们已经掌握的知识。他说程序员不想编写他们完全理解并且100%理解的东西,因为这没有挑战性。程序员总是想要处于他们知识的边缘。虽然他理解程序员为什么会这样,但他指出这并不代表低错误容忍度编程的特点。

我相信,有些编程领域或应用程序同样需要迪科斯彻的“纪律”。例如NASA漫游车,医疗行业嵌入式设备(如发药器等),一些财务软件转移我们的资金。在发布后没有增量变化的奢侈条件下,这些领域需要更多的“莫扎特方法”。


1
很棒的回答。你的第三点是一个非常有价值的事情,需要时刻注意并防范。 - mechanical_meat
1
这是否可以简化为,“尽管通过实验和‘玩弄’是可行的,但只要你使用它来确定你将要交付的东西,而不是交付实验本身?并不是所有类型的实验都能够欺骗客户一段时间...” - cjs
计算机科学和软件交付是两回事,它们并不相同。在客户端测试软件似乎已经成为当前市场中必要(且不良)的一部分。美丽、高效、优化的算法可能是必要的,但并不足以构建成功的软件产品。 - Cheeso
你说得很有道理。Mozart编程确实有其用处,但这并不意味着在非关键应用程序中发布可能存在漏洞的东西是100%的坏事,原因有两个:1、你必须在某个时候将其推出市场;2、用户可能是目前最有效的漏洞发现工具 :) - RCIX

6
我认为莫扎特的故事混淆了产品发布和开发过程。贝多芬没有在公众面前对他的交响乐进行测试。(看看他在第一次公开演出后有多少改变得分数会很有趣。)
我也不认为迪科斯彻(Dijkstra)坚持只在脑海中完成。毕竟,他写了关于纸上编程的书籍,并且正如他希望看到数学质量的纪律一样,你有没有注意到数学家在解决问题时可能会消耗大量的纸张和黑板?
我赞成Simucal's response,但我认为应该放弃莫扎特-贝多芬的比喻。这将把Dijkstra对纪律和理解的坚持塞进一个它实际上并不属于的角落。 附加说明: 电视的普及并不那么火热,这让一些人对音乐作曲和程序员所做的事情产生了困惑。正如Dijkstra在他1972年图灵奖演讲中所说:“我们不要忘记,我们的任务不是制作程序;我们的任务是设计出一类计算,使其呈现出所需的行为。”作曲家可能正在寻找所需的行为。
此外,在Dijkstra认为1.0版本应该是最终版本的观念中,我们太容易混淆所需的行为和功能随时间演变的方式。我认为他过于简单化地认为所有未来版本都是因为第一个版本没有经过严谨可靠的思考和完成。
即使没有时间紧迫的要求,我认为我们现在更加了解重要的软件类型是随着用户体验和实用目的的演变而发展的。明显的反例是游戏(还要考虑剧院电影的开发方式)。你认为贝多芬能够在没有所有前期经验和探索的情况下写出第九交响曲吗?观众能听出它的价值吗?他应该等到有完美的奏鸣曲吗?我确信Dijkstra并不提倡这种做法,但我认为他过分强调莫扎特-贝多芬来证明自己的观点。
此外,考虑下象棋软件。新版本并不是因为之前的版本没有正确运行。这是关于利用象棋启发式和可用计算机性能的进步。对于这种和许多其他情况,认为1.0版本是最终版本的想法是错误的。我理解他正当地反对发布已知不可靠甚至有缺陷的软件,并需要在维护和未来的版本中弥补缺陷。但对我来说,莫扎特主义的反驳不成立。

那么,Dijkstra是否继续驾驶他购买的第一辆汽车或完全相同的克隆汽车呢?也许有计划性陈旧,但很多原因与改进和可靠性有关,这在以前的汽车技术中可能根本不可用或不能考虑。

我是Dijkstra的粉丝,但我认为莫扎特-贝多芬之争过于简单化,也不合适。我也是贝多芬的粉丝。


我同意。我不认为Dijkstra反对增量变化。他反对发布未完成/质量差的软件。我认为他的莫扎特/贝多芬比喻被断章取义了。他不希望我在问题上进行瞎搞,而是要有条不紊地理解和设计稳定的软件。 - mmcdole
1
伟大的名言:“贝多芬没有在公众身上进行交付测试他的交响乐。” - MusiGenesis

5

我认为可以通过 似乎 运用莫扎特编程。我知道有一家公司叫作暴雪,他们不会在准备好之前发布软件产品。这并不意味着Diablo 3将在一次炫目的编码过程中完整地出现在某人的头脑中。它 确实 意味着对我们其他人来说就是这样的。暴雪公司将在内部进行大量测试,直到处理掉所有问题之后再向全世界展示。大多数公司不采用这种方法,而是更愿意在软件足以解决问题时发布,然后随着问题的出现修复错误和添加功能。这种方法(以不同的程度)适用于大多数公司。


1
+1;这让我想起了《合理的设计过程:如何以及为什么要假装它》(http://web.cs.wpi.edu/~gpollice/cs3733-b05/Readings/FAKE-IT.pdf)。 - mlvljr

4

我们不能像莫扎特那样出色,也许贝多芬编程更容易些。


1

我认为这个想法是提前规划。你至少需要有一些关于你要做什么以及如何实现的大纲。如果你只是坐在键盘前,希望“灵感”会引导你到达程序需要去的地方,结果可能会相当不平衡,并且需要更长时间才能到达目标。

这对任何类型的写作都是正确的。很少有作者只是坐在打字机前没有任何想法,然后开始敲打,直到出现畅销小说。我的岳父(一位高中英语老师)甚至为他的信写大纲。


1
如果苹果采用了“莫扎特”编程,今天就不会有Mac OS X或iTunes。 如果谷歌采用了“莫扎特”编程,今天就没有Gmail或Google Reader。 如果SO开发者们采用了“莫扎特”编程,今天就没有SO。 如果微软采用了“莫扎特”编程,今天就没有Windows(嗯,我觉得那会是好事)。
所以答案很简单,不行。没有什么是完美的,也没有什么永远都要完美,包括软件在内。

0

计算机技术的进步值得在某些地方牺牲荣耀或天才。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接