可视化编程为何是个糟糕的主意

mikehadlow于2018.10.1在他的博客上写了篇文章:Visual Programming - Why it’s a Bad Idea。他在reddit上发了个同名帖子:,一石激起千层浪。截至今日(2018.11.21),帖子获得414票的赞同,383个评论。考虑到它只是技术话题,算是非常热门了。

今早有人将这篇文章推到hacker news。我读完文章,顺带将同名帖子下的所有讨论一并读了。关于图形化编程,这是我近来读到最精彩的争论,做个梳理。

我最初给那篇帖子点了个踩,后来改为点赞。起初点踩的原因是,我不赞同文章的观点。但我认为那是一篇好文章,至少也算抛砖引玉,希望它被更多人读到,引起更广泛的讨论和思考。它值得一读,也值得一驳,这是我给它点赞的原因。一篇文章值得被反驳,是一种赞美。

这听起来有些古怪。如果有人跟我说,我写得东西,值得他花半个小时来反驳,我会觉得这是一种莫大的荣耀。要知道,太多的文章混乱不堪,根本不值驻足细读,更别说理解之后再反驳了,你恨不能捏起鼻子赶紧跑开。

在哲学圈,有这么一条不成文的规矩:对一位哲学家最大的尊重,就是去反驳他的论证。

罗素在《西方哲学史》卷三.近代哲学部分,写霍布斯时说:

把霍布斯和以前的政治理论家们作个对比,他的高明处显露得清楚极了。他完全摆脱了迷信;他不根据亚当和夏娃堕落人间时的遭遇发议论。他论事清晰而合逻辑;他的伦理学说对也好错也好,总是完全可以理解的东西,里面没使用任何暧昧含混的概念。除开远比他见识狭隘的马基雅弗利,他是讲政治理论的第一个真正近代的著述家。他若有错处,错也出于过分简单化,并不是因为他的思想基础不现实、偏空想。为这个缘故,他仍旧值得一驳。

你看,“他仍旧值得一驳。"的原因正是因为他有如此多的优点。

大卫·休谟(David Hume,1711—76)在1739年出版他的《人性论》(Treatise of HumanNa ture)后,期待着猛烈的攻击,打算用堂堂的反驳来迎击。殊不料谁也不注意这本书;如他自己说的,“它从印刷机死产下来。” 。你都准备好了在一次伟大的争论中,让观点屹立于世,却不料期待的对手始终没有出现。

我有个小人之心的想法,故事中持剑的少年,内心是期待着那条劫走公主的恶龙出现的。我甚至不知道持剑的少年究竟喜欢公主多些,还是喜欢恶龙多些。


近期正在尝试写文献综述风格的文章,本文是这个系列的第三篇。

可视化编程为何是个糟糕的主意

我先翻译mikehadlow对可视化编程的攻击,在文章后半部分,给出reddit社区用户对这篇文章的反驳以及我个人对此的反驳。

mikehadlowVisual Programming - Why it’s a Bad Idea中写道:

可视化编程语言允许编程者通过操控图形元素不是通过输入文本命令来创建程序。众所周知的例子是Scratch,一个来自MIT(麻省理工学院)的可视化编程语言,用于教孩子编程。Scratch的优点是让新手和普通用户能够轻松地开始编程。

在20世纪90年代,有一种非常流行的运动,即通过所谓的CASE工具将这类工具带入企业,企业系统可由UML定义和生成,无需雇佣专业开发者。这涉及“round tripping”的概念,在其中,系统可以在视觉上建模,程序代码从模型中生成,并且代码的任何更改都可以反映到模型上。这些工具未能兑现承诺,大多数这此类尝试现已基本放弃。

除了一些非常有限的领域外,可视化编程未能成功。这基本上归因于以下对编程的误解:

  1. 基于文本的编程语言使得本质上简单的过程变得混乱。
  2. 抽象和解耦在编程中处于边缘位置,作用不大。
  3. 为支持编程而开发的工具并不重要。

第一个误解认为软件开发存在很大的门槛,因为文本编程语言模糊了编程的本质。Scratch在教育学家中的流行属于这种误解。该观点认为编程实际上非常简单,如果我们以清晰的图形呈现它,将大大降低创建和阅读软件的难度,学习曲线将平缓。这种误解源自未能理解文本代码写就的典型程序,转而想将它转换为框和箭头等图形元素。如果你这样做,很快就会发现一行代码经常映射到几个图形块上,一个简单的程序包含数百行代码是很典型的。这将转化为成百上千个图形元素。在头脑中理解如此复杂的图形往往比阅读等效的文本要困难得多。

大多数可视化编程语言应对上述问题的策略是使用“块”来代表更复杂的操作,以便每个可视化元素等同于大块的文本代码。可视化工作流工具是罪魁祸首。问题是需要在某处定义此代码。它变成了“属性对话编程”。视觉元素仅代表最高级别的程序流程,大多数工作都是隐藏在框中的标准文本代码中完成的。这种做法,两边不讨好。一边是,文本编程没有现代工具的支持。另一边是视觉元素只能由有经验的程序员创建,只能通过阅读它们的文本代码来理解。因此视觉元素的大多数假定的优点都会丢失。在视觉“代码”和文本代码之间存在着阻抗不匹配,编程者必须在两者之间切换,时间都浪费在理解图形化工具上,而不是解决手头的问题。

这让我们产生了第二个误解,即抽象和解耦是外围问题。可视化编程假设大多数程序都是简单的程序序列,有点像流程图。实际上,这是大多数新手程序员想象软件的工作原理。然而,一旦程序变得比一个简单的例子更大,复杂性很快就会压倒新手程序员。他们发现很难推断大规模的程序代码,并且经常难以大规模生产稳定有效的软件。编程语言中的大多数创新都是尝试管理复杂性,最常见的是通过抽象,封装和解耦。面向对象和函数式编程实际上只是努力控制这种复杂性。大多数专业程序员将不断抽象和解耦代码。实际上,好的和坏的代码之间的区别本质上便是这样。可视化编程工具缺少有效的机制来实现这些,它们让开发者置身于1970年代的BASIC中。

最后的误解是可视化编程者可以在没有现代编程工具的支持下编程。考虑代码编辑器和IDE的长期演变。例如,Visual Studio支持高效的智能感知,可以单独查找基类库中可用的数千个API。缺乏良好的源代码控制是大多数可视化编程工具的另一个主要缺点。即使他们将布局保存为文本格式,比较代码差异(diff)几乎没有意义。对大量的XML或JSON进行“git blame”非常困难。有些事情对程序的功能执行没有任何影响,例如图形元素的位置和大小,仍然会导致元数据的变化,这使得观察差异(diff)变得更加困难。文本编程语言已经学会将代码单元分成单独的源文件,因此系统的一部分的更改很容易与另一部分的更改合并(merge)。可视化编程工具通常坚持每个图(diagram)单独存储,这意味着合并变得困难。当难以解析差异的语义时,这将更加困难。

总之,可视化编程工具提供的优势:使程序更容易创建和理解,几乎总是海市蜃楼。它们只能在最简单的情况下成功。

作者更新

我可能错误地使用了Scratch的截图,并将其用作我的第一段中的主要示例。我不是一名教育工作者,我对Scratch作为一种教学工具的有效性并没有真正的看法。许多人提到它在教学编程方面非常有用,特别是对儿童而言。任何将人们引向精彩纷呈的编程世界的东西都是值得欢迎的。我真的不打算将此帖作为对Scratch的批评,我主要批评人们听过的那些流行的可视化编程系统。

Reddit上的小伙伴们提到的另一个反例是静态结构工具,例如UI设计工具,数据库模式设计工具或类设计工具。我同意他们非常有用。任何有助于可视化数据结构或程序的大规模结构的东西都是好东西。但这些不足以支撑他们的论点的。PowerBuilder等90个试图构建在可视化之上,用以创建一个完全无代码的开发环境,都失败了,就证明了这点。

反驳

mikehadlow关于Scratch的观点,遭到reddit上很多用户的反驳,于是他在文章结尾处加了一段更新说:

我可能错误地使用了Scratch的截图,并将其用作我的第一段中的主要示例。我不是一名教育工作者,我对Scratch作为一种教学工具的有效性并没有真正的看法。许多人提到它在教学编程方面非常有用,特别是对儿童而言。任何将人们引向精彩纷呈的编程世界的东西都是值得欢迎的。我真的不打算将此帖作为对Scratch的批评,我主要批评人们听过的那些流行可视化编程系统。

mikehadlow在文章中盛气凌人,一副"我是资深程序员,你们这些渣渣新手"的姿态。关于Scratch的部分,在reddit上被一通反驳之后,态度突然变得这么低,让人反倒没什么反驳的热情了。

我们来看看reddit上的一些讨论。

@victotronics评论说:

我赞同这个家伙的几点论述。传统编程无法从图形环境中受益。
但是,对于初学者来说,积木块是不可能出现语法错误的语句。这很有价值!你希望初学者考虑算法的结构,而不是分号的位置。我现在正在教授一所大学开始编程课程一个月。我仍然看到学生们得到一个编译器消息说它预期出现一个分号,他们很难确定在哪里或为什么需要这个分号。为什么编译器指向“for“并且说它需要分号?嗯,这是因为前一行。非常违反直觉。”
请主意文章中关于Scratch的截图。编程者正在为精灵编写事件处理程序。事件循环是环境的一部分,而这不需要明确编程!你可以让一个10岁的孩子写一堆精灵,每个精灵都有一个行为,如果你点击某些东西,就会发生一些事情。你能想象用常规语言进行的工作吗?
但我完全承认他关于抽象的观点。图形环境可能对此的支持多是蹩脚的,而抽象是优秀软件的本质。

@AlSweigart评论说:

Scratch专为8至16岁儿童设计,这是完美的; 它是图形化的,具有简短的反馈循环,并使简单的事情变得简单。
我知道很多程序员都希望教他们的孩子编码,并忘记了它是多么令人生畏和沮丧。Scratch的辉煌之处在于它做到了平易近人的同时,仍然是实际的编程(而不只是配置一下游戏)。但是,期待“可视化编程”将使编码变得更容易却不现实。

@yummybear评论说:

今天向我11岁的女儿介绍了Scratch,她喜欢它。仅仅几分钟后,她就让人物移动和跳舞,并对进展感到开心。Scratch中的积木块也被翻译成我们的母语,她可以阅读它们的行为。
我不确定文本语言是否会给出同样直接的反馈激励。

当我们谈论图形化编程的时候,我们在谈论什么

当我们谈论图形化编程的时候,我们在谈论什么呢?

mikehadlow以为他在谈所有的"图形化编程",他假设所有的这些编程工具都吹嘘一样的优点,有一样的缺陷,所以mikehadlow准备写一篇文章,一次驳倒它们,把“可视化编程”通通归为糟糕的主意,他不具体谈哪个软件,不举例说明,唯一在开头举了Scratch的例子,结果又成为众矢之的,只好改称:

我不是一名教育工作者,我对Scratch作为一种教学工具的有效性并没有真正的看法。

而reddit上的用户则代入各自的经历,以为mikehadlow在谈他们各自熟悉的图形化编程工具,有人在吐槽Labview,有人在拥护虚幻引擎中的图形工具,有人在赞扬Scratch...于是我们一时不知道大家在争执什么。这场面简直像哲学家们对意义、真理、道德的争论,大家自说自话,全然忘了问题是什么。

那么问题是什么?我们究竟能否用"图形化编程"来描述所有与图形有关的编程,它们是否可以混为一谈?是否都拥有一样的缺陷?是否需要再做细分,分门别类来谈论?是否更多的例证,而不是泛泛而论?

@teerre对此说得比较尖刻:

阅读他的文字我不禁认为他实际上从未使用过任何可视化编程,而只是在谈论他在自己的脑海中所构成的猜想。缺乏实际的例子。

Scratch的缺陷

总的来说我是喜欢mikehadlow这篇文章的,正是因为喜欢,我才决定好好反驳它。尽管他的讨论,显得有点粗糙,mikehadlow本人对Scratch也缺乏必要的了解,但他提到的“图形化编程共有的问题“,其中一至少有一点,Scratch确实存在:

缺乏良好的源代码控制... 对大量的XML或JSON进行“git blame”非常困难。对程序的功能执行没有任何影响的事情,例如图形元素的位置和大小,仍然会导致元数据的变化,这使得观察差异(diff)变得更加困难。

@balefrost在帖子下的评论,比mikehadlow的原文更为精彩,也更为深刻。balefrost评论道:

我认为使用Scratch教学基本编程没有任何问题。在我看来,图形化编程大的缺点在以下方面:
使用空间经常不足。我见过的大多数图形化编程环境都有节点与线的连接。因此需要将节点间隔得足够远,以使连线有足够空间,并限制你将获得的线路交叉数量; 即便如此,无论给它们多少空间,总会有一些交叉线。你可能必须手动布线,以获得好看的图表。最终会投入大量时间和精力来制定“漂亮”(即“可读”)的图式。只要更改图式,所有仔细的布局工作都可能毫无价值.尽管Scratch不需要连线,但使用空间经常不足却也经常不足。而且积木组合如何分布好看也确实影响阅读。
文本编程语言还省略了图形化编程环境中存在的视觉装饰,因为我们不需要它们。VP(visual programming)中的框必须足够大,以便用户可以合理地使用鼠标来操纵它们,这是我们可以在文本语言中不必考虑的因素。
围绕纯文本文件构建了很多工具。我可以在任何我想要的编辑器中编辑纯文本文件。简化和合并纯文本编程文件通常是众所周知的活动,并且像Git这样的源代码控制工具针对纯文本文件进行了优化。即使VP环境将其代码保存在纯文本文件中,因为可视化编程文件需要编码算法信息以及空间信息,VP语言文件的差异通常比文本编程文件更嘈杂。
为文本编程编写代码生成器很容易,因为不需要太担心空间安排(只关心缩进)。用于可视化编程的代码生成器将需要担心放置节点的位置,这是一个非常重要的细节。
还有许多其他工具针对处理纯文本文件进行了优化。有一个丰富的文本编辑器生态系统,其中许多都对文本编程有很好的支持。可视化编程的编辑可能是一次性的。

@balefrost的这些论点都非常精彩,Scratch确实有这些问题。但我认为这些并不影响Scratch达成它的使命。而且像编辑器生态总是会随着时间和社区的壮大,持续改进。比如blockly就发展出了编译为6种文本语言的能力,并且可以还加入类型判断,用以决定可组合性,两块积木是否可吸合,这即便在文本编程工具里,也是很酷的功能,相当于静态分析了。而makecode则发展出了代码与图形积木的双向转换。这些都是非常先进的。而且在持续改进中。我们有理由保持乐观。

@balefrost继续说道:

我认为可视化编程将在非传统环境中取得最大成功。对于有大量条件逻辑的常规算法工作,我不知道可视化编程是否合适。我认为它在高级别工作中效果更好 - 将算法复杂性隐藏在预先封装的块中。我认为可视化编程适用于我们之前使用过脚本语言的一些任务。在我看来,Automator是一种向不熟悉Bash的用户提供UNIX管道功能的方法。
根据我的经验,一旦达到一定程度的复杂性,VP似乎真的会崩溃。我不能确定这是因为工具不足,个人经验不足,还是因为它是范式的根本限制。我的直觉告诉我,问题是根本的。

我的反驳

下边单说我的反驳。

由于我的兴趣主要关注图形化编程在教育这块的应用,所以我的焦点集中在以下系统:

我将结合这几种图形化编程工具,来反驳mikehadlow的观点。

降低入门门槛

mikehadlow

该观点认为编程实际上非常简单,如果我们以清晰的图形呈现它,将大大降低创建和阅读软件的难度,学习曲线将平缓。

我认为mikehadlow对Scratch存在很大误解,我甚至怀疑mikehadlow并没使用过Scratch。在Scratch社区,我们认为Scratch帮助降低编程入门门槛,我们并不认为编程实际上非常简单,我们认为入门编程应该尽可能简单,不应该让入门者太沮丧。使用Scratch构建大型程序确实会变得非常复杂,其中一些原因@balefrost在前头说得非常好,为了克服这种复杂度,Scratch的分支项目Snap!做了很多探索。

图形积木与文本代码的视野切换

mikehadlow在文章里说:

视觉元素仅代表最高级别的程序流程,大多数工作都是隐藏在框中的标准文本代码中完成的。

视觉元素只能由有经验的程序员创建,只能通过阅读它们的文本代码来理解。在视觉“代码”和文本代码之间存在着阻抗不匹配,编程者必须在两者之间切换,时间都浪费在理解图形化工具上,而不是解决手头的问题。

我不认为在Scratch3.0中, 这种切换是必要的,如果我们把编程积木视为一种好的抽象(我们应该这样做),那么我们是可以设计出原子积木的,它们彼此正交。编程者并不需要理解抽象背后的细节,这正是抽象的目标之一。正像他们在面向对象系统中,可以轻易使用别人定义的类。

我认为这是设计Scratch3.0这类积木化编程系统的核心工作。它并不容易,让一个积木可以运行是简单的,要设计出抽象得合理又正交的积木,极为困难,你可能需要一些研究PL的人以及交互设计的人,而且他们最好是一个人。

但你知道,大多数项目并没有精心设计,只是勉强能用,于是造成了使用者的灾难。

我们在codelab.club中做了很多有趣的探索,我们希望设计出尽可能正交的积木。此外我们允许大家在熟悉系统后,可以轻松去扩展这个系统,我们准备了通用的积木(EIM)。这里的核心概念是Everything is message,在这一点上,基于这个概念,能很轻松解耦。同时免费获得可组合性。我们是艾伦凯的忠实追随者。在这个领域,他一骑绝尘。

视觉元素仅代表最高级别的程序流程,大多数工作都是隐藏在框中的标准文本代码中完成的。

我不认为这是个缺陷,而认为这是个很好的特性,我在两种硬件编程风格的比较有做论述。

复杂度

然而,一旦程序变得比一个简单的例子更大,复杂性很快就会压倒新手程序员...编程语言中的大多数创新都是尝试管理复杂性,最常见的是通过抽象,封装和解耦。面向对象和函数式编程的所有类型系统实际上只是努力控制这种复杂性。大多数专业程序员将不断抽象和解耦代码。实际上,好的和坏的代码之间的区别本质上便是这样的。可视化编程工具缺少有效的机制来实现这些,它们让开发者置身于1970年代的BASIC中。

这是全文中我最为赞同的一段,如《SICP》在序言里说的,编程的本质是克服复杂度。但我认为Scratch/blockly这类积木化语言是有支持抽象的机制的。

先说Blockly。

@SanityInAnarchy在帖子下说:

我无法真正看到关于抽象的观点。函数只是一个容纳代码的块,包括一个“参数”块。一旦定义了,你就会得到一个调用你的函数的“调用”块,并且可以将值作为参数放到该函数中。这是抽象的大部分内容,而code.org上的东西似乎很好地涵盖了它。

code.org使用blockly,blockly确实已经很好地实现了函数的机制。这个机制并不比大多数语言的函数功能更弱。而函数是实现抽象的绝佳工具。

至于Scratch则在解耦这块做得很好。消息机制是Scratch的核心机制。消息是绝佳的解耦工具,如果你逛一逛Scratch社区,就可以看到人们构建了许多令人惊叹的项目。它们中的许多并不简单,消息是帮助他们克服复杂度的核心工具之一。这个特性继承自smalltalk的设计原则:

计算应该被视为可通过发送消息来统一调用的对象的内在功能。

codelab.club中,我们把这个概念进一步发挥,使用消息将积木块接入现实生活,我们做了许多有趣的[探索]。(https://scratch3-adapter-docs.just4fun.site)

如果你对图形化编程充满热情,来codelab.club中与我们一起探索吧。

未来

我赞同@balefrost在前头提到的:

我认为可视化编程将在非传统环境中取得最大成功。对于有大量条件逻辑的常规算法工作,我不知道可视化编程是否合适。我认为它在高级别工作中效果更好 - 将算法复杂性隐藏在预先封装的块中。

我们相信可视化编程将在非传统环境中取得成功。我们在codelab.club做了许多探索,我们希望将可视化编程(我们更喜欢称它们为积木化编程)带入物联网与人工智能,我们已经做出了很多有趣的东西

我们将继续探索这个领域,并且利用这种技术,让编程变得更加温和有趣,为每个人所用,去解决他们生活中的问题。

科技,以人为本。

除了codelab.club,这个领域还有很多有趣的探索者。艾伦·凯正在领导一个革命性的项目dynamicland,如果进展顺利,dynamicland将重塑人们对计算的理解。艾伦·凯在施乐实验室的工作,塑造了今天计算机的形态,我们认为他在dynamicland的工作将塑造未来。codelab.club计划明年三月份去dynamicland实验室参观。我们喜欢dynamicland的理想:将数字力量赋予给所有人,而不是收聚在技术精英手中。

dynamicland远不是一般的图形化编程,它把现实世界的真实物体视为编程元素,"现实便是计算引擎",这是极为激进而令人热血沸腾的想法。如果你对此感兴趣,可以参考我此前的文章:"下一件大事"是一个房间

收尾

最后我想用reddit两个用户的评论来结束本文.

@zushiba评论道:

虽然我同意文章的很多观点,但我想指出,当低级编程语言统治世界时,高级编程语言也遭遇类似的说法。
他们说:"这样做会混淆代码实际上在做什么,或者产生一代不知道编译器如何工作的程序员。"
我并不是说可视化编程会接管世界,但这些都是可以解决的问题。

@not_perfect_yet评论道:

我不喜欢看到人们诋毁一个没有真正探索过的想法。如果我们现在扔掉火并回到树上,我们将永远不会使用内燃机。

参考




Fork me on GitHub