原文

Debug Mode is the Only Mode

译文

(由 ChatGPT 翻译, 种瓜校对和微调)

最近 Bret Victor 的一些演讲博客文章引起了相当多的讨论。如果你还没有看过这些内容,我强烈推荐你去看一看,但要保持一定的怀疑态度。

这些作品提出了与编程和编程环境相关的重要观点,并且做得非常出色。

它们还涉及到教育和其他我在这里不会讨论的事项。

因其精美的呈现,这些作品引起了比其他人更多的关注,这是一件好事。然而,在优雅的外表下,令人不安的问题出现了。

Victor 展示的演示因令人失望的认识而被破坏,我们并没有看到一个可以完成这些奇迹的通用编程环境。相反,它们是手工制作的示例,展示了这样一个工具可能的行为。这是关于这种环境的愿景, 而不是环境本身。仅有一些暗示涉及如何为一般情况创建这样的工具。

我们应该将这些想法作为灵感,并看看在实践中可能做些什么。我期待这是 Victor 打算通过这些演示实现的目标之一。

Victor 意识到他的许多例子依赖于图形反馈,并不一定适用于其他类型的编程。然而,他对轨迹和时间线的使用是我们可以普遍使用的。在一个片段中,循环期间的状态会被编程环境自动展开 - 将时间转化为空间,这样我们就可以可视化计算的进展(或者缺乏进展)。

在现有的调试器中,可以使用尾递归形式的循环来处理这个特定的例子, 没有尾递归消除!然后可以使用调试器中的堆栈普通视图, 虽然基于轨迹的视图在屏幕空间方面可能具有优势,因为我们不需要重复代码。这些优势将适用于任何递归例程,因此添加递归调用的展开视图是人们可能想要研究的一个小的具体步骤。

显示所有相关数据的跟踪本质上与时间旅行调试相关,因为我们想要的不仅仅是选择性打印输出 - 我们希望能够在追踪的任何时间点探索数据,跟随对象图,无论它将我们带向何处。

我坚信时间旅行调试器比一大堆语言特性更有价值(特别是因为大多数这样的一大堆特性实际上都没有价值)。

当我第一次看到 Bil Lewis 的全知调试器(Omniscient Debugger)时,我试图说服我的管理层在这个领域投资。不用说,我一无所获。

总体观点是,程序是某个真实或想象的世界的动态和发展模型。我们应该能够对该模型进行实验,并观察和与其任何部分进行交互。一个人应该能够查询模型的整个历史,搜索过去发生的事件和情况,然后回到它们发生的时间,或者在事件发生之前的时间,这样我们就可以预先阻止事件并随意改变历史。

由回溯调试器(back-in-time debugger)实现的查询技术也可以帮助实现图形演示。您可以询问我的代码中间接调用了哪个写入给定像素的调用。这是一个复杂的查询,但基本上类似于询问变量何时获得了给定的值。

这个领域有一些工作,有些是学术性的,有些是商业性的(请原谅我没有在这里引用所有的工作),但它并没有真正起飞。这是一个挑战,因为程序会生成大量的临时数据,记录所有这些数据是昂贵的。这给“大数据”一词赋予了新的解释。数据在我们所做的许多事情中都是核心,关于程序的数据也不应该例外。

一个相关的主题是将数据与代码相关联,通过将实际值与程序变量关联起来。一个简单例子解释将值与变量关联的优势,我们可以在没有静态类型信息的情况下进行名称补全。我们可以在 workspaces、REPL、对象检查器和(再一次!)调试器等工具中获得变量与其值之间的连接,而在普通编辑器甚至类浏览器中查看程序文本时无法做到。

在 Newspeak 和 Smalltalk 中,开发人员有时会使用调试器从初始草图构建程序,因为在调试过程中他们可以看到实时数据,并根据这些具体信息设计他们的代码。你将 Victor 在的演讲中找到这种情况的一个例子,大约在 19:10 左右,其中一个错误是基于运行时值在编写代码时被检测到的。

Self 环境展示了一种将实时数据与代码集成的方法。基于原型的语言在这方面有一些优势,因为代码与实际对象相关联, 但一旦涉及到带有参数的方法,我们就会回到处理抽象的情况,就像以类或函数为基础的语言一样。

你甚至可能会说,JavaScript 作为一种基于原型的语言,是 Self 的现代化体现。请不要酒后驾车;最好的情况是这是一个关于“小心你所期望的”的警世故事

我们需要一个流程,使得从最初的草图到稳定的生产代码更加容易。我们希望从 workspaces 开始,并能够顺利地迁移到类和单元测试。这与本文中所表达的哲学是一致的。

我觉得各种工具,比如编辑器、类浏览器、对象检查器、workspaces、REPL 和调试器,都创造了不同的操作模式。如果能够更紧密地集成这些工具,那就太好了。在编辑代码时,与你的作用域关联的实例将始终存在,并且具有逐步评估代码的能力(就像在 REPL 中一样),以及像时间旅行调试器一样向前向后步进。这样的工具的确切形式仍然是一个未解决的 UI 设计挑战。

无论您是进行面向对象编程、函数式编程(顺便说一句,这是一个错误的二分法),还是逻辑编程,上述所有内容都适用。

题外话:我知道在惰性函数式语言中调试的概念是有问题的。但是对于实时数据和交互式反馈的需求仍然存在。一旦发生交互式计算,时间就已经完全确定了。因此,向前迈进可能毫无意义,但回到过去却不是。

我们不应该把程序仅仅看作是代码。PL 社区对代码的静态视图,脱离其动态范围,已经被过分强调。这种情况需要改变,而且它将会改变。