下载本文的PDF版本 PDF

我们计算所用的隐喻

代码是一个解释如何解决特定问题的故事


阿尔瓦罗·维德拉

在其现已成为经典的著作《我们赖以生存的隐喻6中,乔治·莱考夫和马克·约翰逊旨在向语言学和哲学界表明,隐喻不仅仅是诗歌和修辞上的藻饰。他们展示了隐喻如何渗透到我们生活的方方面面,特别是隐喻如何支配我们理解世界的方式、我们在世界中的行为方式以及我们在世界中的生活方式。他们表明,我们的概念系统也基于隐喻,但由于我们通常没有意识到自己的概念系统,他们不得不通过一个代理来研究它:语言。

太初有道

通过研究语言,莱考夫和约翰逊试图理解隐喻如何通过在我们生活中强加意义来发挥作用。他们提出的基本例子是概念隐喻“争论即战争”。我们理解与他人争论的行为方式与我们理解战争的方式相同。这导致了我们日常语言中的以下表达方式

• 你的论点是站不住脚的

• 他攻击了我论点中的每一个弱点

• 我驳倒了他的论点。

• 我从未赢过与他的争论。

这些句子可能看起来无伤大雅,但问题是我们如何根据它们来行动和感受。我们最终将与我们争论的人视为我们的对手,一个攻击我们立场的人,因此我们将争论构建得好像我们与对方处于战争状态。这意味着隐喻不仅仅是语言的藻饰;我们活在其中。莱考夫和约翰逊提出了一个练习,想象一种文化,在这种文化中,争论不是从战争的角度来看待的——不是赢家和输家——而是在这种文化中,语言是一种舞蹈,你必须与伙伴合作才能实现期望的目标,作为一个团队达成结论。

这本书继续分析了语言和隐喻的不同方面,以及它们如何影响我们的概念和世界观。作者给出了许多例子来捍卫以下论点:我们对世界的理解是基于隐喻的,而这些隐喻是行为的基础。

这本书最大的收获之一是,正如争论即战争的例子所说明的那样,隐喻促成了某些思维方式,同时限制了其他思维方式。本文将这个想法应用于计算机科学。隐喻如何塑造我们理解计算及其相关问题的方式?正在使用的隐喻促成了哪些类型的问题?而且,不,单子不像墨西哥卷饼!8

首先,本文着眼于隐喻如何帮助我们理解相对年轻的计算机世界,以及它们如何影响我们构建代码或设计算法和数据结构的方式。我们甚至根据我们的武器库或工具箱中包含哪些隐喻来解决问题。正如作者尼古拉斯·卡尔在他的著作《浅薄3中所述,“有时我们的工具会按照我们告诉它们的方式去做。其他时候,我们会让自己适应工具的要求。” 隐喻是理解的工具。

隐喻的理解

人们通过将新概念与他们已经知道的概念联系起来来理解新概念。早在 40 年代末和 50 年代初,当今天的计算机诞生时,还没有这样的发明的词语,但人们将它们理解为自动大脑。实际上,计算机这个词在当时就存在,但它被用来指代为工程师进行计算的人。想想工程师需要知道弹丸的轨迹或风如何影响飞机机翼形状;他们会向他们的人工计算机抛出几个公式和数字以获得答案。现在出现了这些自动完成工作的新机器;他们称它们为电子计算机,最终去掉了名称中的电子部分。因此,我们自己的学科是以隐喻命名的。

但是,如果你不理解隐喻的局限性,隐喻也会掩盖可能性。新隐喻的一个常见问题是,词语的原始含义被表面化地使用。用来解释新概念的词语实际上可能会限制对该概念的理解。在他的著作《信息5中,詹姆斯·格雷克生动地描述了电报的发明。电报这个词的意思是远程书写。瞧,早期的电报是奇怪的机器,试图远程书写,将字母表的字母一对一地映射到电线中,这听起来非常不切实际。大约在那个时候,由于路易斯·布莱叶,人们开始理解语言可以用不同于其发音(或书写)的形式进行编码。莫尔斯电码是改进电报和理解人们不必“远程书写”即可进行实际远程通信的下一步。

感谢数学家克劳德·香农和像他一样的其他人,我们设法摆脱了电报隐喻的问题,并在 1940 年代后期开始构建了整个信息论学科。香农的开创性著作《通信的数学理论》提出了通信的基本要素:信息必须首先被编码,然后发送到信道中,以便在另一端被解码,从而使目的地接收到它。7

隐喻与代码

一句著名的无署名引言(经常被错误地归于查尔斯·贝克)是:“编程就是向另一位程序员书写我们对问题的解决方案。”2 程序是对问题可能如何解决的解释;它是一个隐喻,代表了一个人对问题的理解。然而,为了使隐喻有效,它们需要使用我们已知的概念来传达意义。特定程序的解释力可以用作衡量其自身优雅程度的标准。

考虑以下示例。假设你可以编程一台计算机来命令其他计算机执行任务,尊重它们的到达顺序。这种描述已经很难理解了。另一方面,你可以通过描述一个队列服务器来描述解决方案,该服务器根据先进先出的队列规则将作业分配给工作者

队列是日常生活中常见的概念,在超市、银行、机场和火车站都能看到。人们知道它们是如何工作的,因此对于阅读你代码的人来说,谈论队列、工作者和作业可能比不使用队列隐喻来解释这种设置更容易。

通过选择正确的隐喻,你的程序达到了一个抽象级别,这需要对问题不熟悉的人付出最少的努力来理解解决方案。此外,使用队列解决问题还免费提供了一整套数学理论。数学本身就是一个领域,只有当有适当表达能力的语言来处理问题时,问题才能得到解决。有了队列隐喻,你不再是盲目地摸黑。现在你可以使用排队论提供的所有工具来分析和理解问题。

作为隐喻的数据结构

分析数据结构有助于我们了解哪种数据结构更适合特定问题的性能特征,但我们常常忘记数据结构也包含解释力。

数据结构的选择有助于传达意义。你可以将一堆元素存储在数组中,但是如果你需要确保元素是唯一的呢?那不是集合的用途吗?你的集合的底层表示仍然可以由普通数组支持,但现在你的程序以更清晰的方式表达了其意图。每当其他程序员阅读它时,他们都会明白你的集合中的元素必须是唯一的。重要的是要意识到程序只是计算机需要处理的另一个比特序列。是程序员赋予了这些比特意义,因此你必须在它们之上使用正确的隐喻,使你的程序更清晰。正如有人所说,“没有人见过机器无法理解但人类可以理解的程序。”2

你必须努力使你的程序尽可能容易被其他程序员理解。易于理解应该是衡量程序的标准。请记住,你可以用许多不同的方式安排代码来解决计算问题,但并非所有这些安排都有利于人际沟通和理解。你必须问问自己,通过阅读我的代码,其他人会理解我是如何解决这个特定问题的吗?

正如隐喻促成某些理解方式并限制其他理解方式一样,数据结构也是如此。早些时候,我们看到了使用直接隐喻(例如原始电报)的问题。当涉及到数据结构时,你可以看到集合将揭示其元素是唯一的,并且它将允许你测试元素是否是集合的成员。但是,使用链表,你可以了解逐个遍历其元素的概念,而不能跳过它们。使用数组,你可以了解可以通过索引寻址其元素的概念。队列和堆栈也是如此,它们是任何算法课程中教授的最基本的数据结构之二。每个都可以使用数组来实现——不同之处在于,一个按 FIFO(先进先出)顺序返回元素,而另一个按 LIFO(后进先出)顺序返回元素。

即使这对于大多数程序员来说看起来像是每天都在发生的事情,但当你选择使用堆栈而不是队列的那一刻,你就是在决定如何解释你的程序。堆栈是程序处理的项目集合的一个非常好的隐喻,因为它告诉程序的未来读者以什么顺序期望处理项目。你甚至不需要阅读堆栈是如何实现的,因为你可以假设你将按 LIFO 顺序获取项目。这就是类型在计算机科学中如此重要的原因——不是程序静态类型检查中的类型,而是用于描述程序的概念中的类型:人、用户、堆栈、树、节点,等等。类型是讲述你的程序故事的角色;没有类型,你只有对字节流的操作。

认知飞跃

目标是找到描述和解释问题的正确隐喻。正如前面用排队论的例子解释的那样,需要一个认知飞跃才能从必须按一定顺序处理的任务转变为理解这是一个排队问题。一旦你设法实现认知飞跃,排队论的所有数学工具都可供你使用。图论中充满了平凡任务的例子,这些任务一旦转换为图问题,就会有众所周知的解决方案。每当你要求 Google 地图带你到达目的地时,Google 都会将你的问题转换为图表示,并建议图中的一条或多条路径。图是数学家和计算机都能理解的正确隐喻。是否还有其他看起来很困难但可以通过找到正确的隐喻来解决的问题的例子?分布式系统文献中有一个非常有趣的例子。

在 80 年代后期,施乐公司的艾伦·德梅尔斯和他的同事试图在不可靠的网络中找到数据库复制的解决方案。他们将他们的算法归类为“随机化”,并通过使用谣言传播的隐喻来解释它们:一台计算机会告诉另外两台计算机有关更新的信息,然后每台计算机又会告诉另外两台计算机有关更新的信息,依此类推,直到信息在整个系统中复制。这个隐喻催生了一个新的研究领域,称为流言算法。流言隐喻使这个想法易于解释,但施乐团队仍然缺乏有助于分析算法有效性的数学工具。

在他们的研究过程中,他们发现了与他们的问题相关的另一个隐喻:流行病。他们理解他们的算法以与流行病在人群中传播相同的方式复制数据。通过使用这个新的隐喻,他们立即获得了流行病的数学理论1中的所有知识,这非常适合他们的工作。他们不仅将他们的论文命名为“用于复制数据库维护的流行病算法4,而且还采用了该学科的命名法来解释他们的算法。这是一个找到正确的隐喻以获得新的解释能力世界的问题。

无处不在的隐喻

我们在编程中真的使用了那么多隐喻吗?让我们看一下分布式系统文献中的一个例子(隐喻用斜体表示)

每当节点需要就一个共同值达成一致时,就会使用共识算法来决定一个值。通常有一个领导者进程负责根据从其对等方收到的投票做出最终决定。节点通过在通道上发送消息进行通信,由于流量过多,通道可能会变得拥塞。这可能会造成信息瓶颈通道两端的队列积压。这些瓶颈可能会使一个或多个节点无响应,从而导致网络分区。是否是响应时间过长的进程死机了?为什么它没有确认心跳信号触发超时?这种情况可能会继续下去,但你明白我的意思了。

代码中的故事

程序员必须能够用他们的代码讲述一个故事,解释他们是如何解决特定问题的。像作家一样,程序员必须了解他们的隐喻。许多隐喻都能够解释一个概念,但你必须有足够的技巧来选择正确的隐喻,以便将你的想法传达给未来将阅读代码的程序员。

因此,你不能使用你所知道的每一个隐喻。你必须掌握隐喻选择、意义放大的艺术。你必须知道何时添加,何时删除。你将学会像作家一样修改和重写代码。一旦没有什么可添加或删除的,你就完成了你的工作。你开始的问题现在就是解决方案。那是你最初打算传达的意义吗?

参考文献

1. Bailey, N. T. J. 1957. 流行病的数学理论。阿诺德。

2. Charles Baker (Ed.). 1967. 程序员做什么。《Datamation》(4 月); http://archive.computerhistory.org/...What-Programmer-Does.pdf

3. Carr, N. 2011. 浅薄。W.W.诺顿。

4. Demers, A., Greene, D., Hauser, C., Irish, W., Larson, J. 1987. 用于复制数据库维护的流行病算法。《第六届 分布式计算原理年度研讨会论文集》:1-12。

5. Gleick, J. 2011. 信息:历史、理论、洪水。万神殿。

6. Lakoff, G., Mark J. 1980. 我们赖以生存的隐喻。芝加哥大学出版社。

7. Shannon, C. E., Weaver, W. 1949. 通信的数学理论。伊利诺伊大学出版社。

8. Yorgey, B. 2009. 抽象、直觉和“单子教程谬误 https://byorgey.wordpress.com/...abstraction-intuition-and-the-monad-tutorial-fallacy/

致谢

我要感谢乔丹·韦斯特和卡洛斯·巴克罗,感谢我们所有关于隐喻如何渗透计算的讨论,以及他们在文章写完后给我的反馈。

相关文章

首先,不要伤害:软件开发人员的希波克拉底誓言
- 菲利普·A·拉普兰特,宾夕法尼亚州立大学
更认真地对待我们的职业有什么问题吗?
https://queue.org.cn/detail.cfm?id=1016991

为代码而编码
- 弗里德里希·施泰曼和托马斯·库恩
模型可以为软件开发提供 DNA 吗?
https://queue.org.cn/detail.cfm?id=1113336

一段优美的代码
- 乔治·V·内维尔-尼尔
生动的隐喻和正确地重用函数
https://queue.org.cn/detail.cfm?id=2246038

阿尔瓦罗·维德拉 (alvaro-videla.com; @old_sound) 在瑞士的家中为一家硅谷公司担任分布式系统工程师。他曾是 RabbitMQ 的核心开发人员,并且是领导团队构建德国最大的约会网站之一的首席开发人员。他是曼宁出版社出版的 RabbitMQ 实战 (2012) 一书的合著者。

版权所有 © 2017,所有者/作者所有。出版权已授权给 。

acmqueue

最初发表于 Queue 第 15 卷,第 3 期
数字图书馆 中评论本文








© 保留所有权利。

© . All rights reserved.