仓库源文站点原文

https://www.zhihu.com/question/405766658/answer/1327906058

和英文视频网站的弹幕功能没有兴起同理。

早在近三十年前,苹果公司就开发出了 AppleScript,例程如下:

可见不仅实现了接近自然语言的英文、法文的标识符带空格语法,而且实现了日语的不带空格语法。

而在 2006 年 AppleScript 主创者之一的论文中(详见AppleScript类自然语言与非英语语法设计),提到了一个关键问题:

It is easy to read AppleScript, but quite hard to write it.

在那个 IDE 的检查、高亮、补全功能还未完善的时代,这个理由足够让这种语言设计失去竞争力。但为何在近二十年 IDE 迅速发展,很大程度上接手了编译器的部分功能的时代,照理说语法检查和提示、标识符补全等等功能完全可以弥补这一劣势,但仍然没有类似语言进入主流商业市场呢?

看这个 AppleScript 示例(源自它的 wiki 页):

tell application "Finder"
    set passAns to "app123"
    set userAns to "John"
    if the text returned of (display dialog "Username" default answer "") is userAns then
        display dialog "Correct" buttons {"Continue"} default button 1
        if the text returned of (display dialog "Username : John" & return & "Password" default answer "" buttons {"Continue"} default button 1 with hidden answer) is passAns then
            display dialog "Access granted" buttons {"OK"} default button 1
        else
            display dialog "Incorrect password" buttons {"OK"} default button 1
        end if
    else
        display dialog "Incorrect username" buttons {"OK"} default button 1
    end if
end tell

尤其这句:

if the text returned of (display dialog "Username : John" & return & "Password" default answer "" buttons {"Continue"} default button 1 with hidden answer) is passAns then

达到了 182 个字符之多。当然,可以将括号内部分分行写,但那样又和接近自然语言阅读习惯相悖。

从最前面的英日法例子也可见,所有表述都长于“职业“表达。这恐怕是更无法被 IDE 辅助功能弥补的。因为过于冗长的句子会导致可读性迅速下降,而代码的业务逻辑往往比起日常的自然语言表述复杂的多,这种冗长的句子也更容易出现。

简而言之:英文自然语言表述太长,难以满足职业程序员阅读代码效率的要求。

【继续更】

关键是可读性

退回几步慢慢说。首先,为何我认为相比易写,代码可读性对于编程语言设计是更重要的因素。先引这位的话:

Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. ...[Therefore,] making it easy to read makes it easier to write.

― Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship

读代码的时间至少是写代码的十倍之多,难怪国外大厂早早重视代码可读性审核(亲历几年,并非走流程而已)。

接下来,是标识符(变量、方法、类等等)命名对于可读性的重要性,这篇 2015 年的论文(见此文末)指出:

Approximately 70% of the source code of a software system consists of identifiers. Hence, the names chosen as identifiers are of paramount importance for the readability of computer programs and therewith their comprehensibility.

占代码篇幅 70% 的标识符自然对代码可读性有及其巨大的影响。那么再回到本题,接近自然语言语法的带空格标识符自然更易读。既然技术也可行,为何并未被广泛采用呢?

拓宽一些,蛇形命名(下划线代替空格)是一种近似形式,Python 更在 PEP8 中指出它有时可以提高可读性:

Function names should be lowercase, with words separated by underscores as necessary to improve readability.

我认为除了它在格式上更接近英文自然语言之外,还有一个原因:

如果一个命名是用更接近自然语言风格的格式起的,命名时往往会倾向于接近自然语言风格的用词和用语

这意味着,它相比驼峰命名来说,往往会用更多“可用可不用”的词来使其更接近自然语言习惯。

既然可读性更好,虽然没有数据支持,但就我看到现在的即使是大型合作项目,蛇形命名法远并未形成压倒性的占比,这是为何呢?

单打和合作

有其他回答提到,标识符可以看成一个“词”。严格来说,标识符当然是词组,但越是单人实施的项目,这种感觉会越强。如果熟识自己的代码,命名在一眼之下可以直接理解,就会感觉“跳过”了逐词理解的步骤。

这应该是更加简短但“不自然”的驼峰命名法仍然大行其道的很重要原因。记得看过 github 的一个数据,单人项目占了相当大部分。商业项目中,相信也是类似比例。

在开发者对自己代码熟识于心的情况下,蛇形命名法的“易读”优势就不明显,反而代码冗长的视感会影响阅读。

但为何合作开发的大型项目中,蛇形命名法也未形成明显压倒占比呢?

我认为一个重要原因是:阅读速度上限受限

在大型企业的大型项目中,成本控制占据高优先级。代码的阅读速度直接影响开发效率和成本。驼峰命名虽然更不接近自然语言,但只要在项目内一致了命名“风俗”,就能使得它的易理解性和阅读速度达到无论是新手还是老手都可接受的程度。而很大程度决定老手阅读速度的,就是代码的长度,这与单人开发同理。

“风俗”的代价

英文命名用语的风格,很多时候倚靠约定俗成的、但并不完全符合自然语言规则的用语格式,包括各种英文自然语言中语法必备词汇的省略,缩短了代码长度,并在项目参与者都接受的前提下,获得了更大的“信息密度”,进而提升了阅读速度。但这种“风俗”,可以看成是英文自然语言的一种“DSL”,是针对编程领域甚至特定项目的一种“专用自然语言”。

这里有两个问题:

  1. 相对于英文自然语言,英文命名的信息密度更高
  2. 学习和遵守这一风格需要额外精力

1 决定了,并不是每个人都能适应这种信息密度,而且适应需要过程。 2 决定了使用它需要比使用自然语言耗费更大精力。

另外 30%

虽然此题主要关注占比 70% 的标识符,但也想顺便说说语法。

首先,如果是像 AppleScript 那样类似自然语言的关键字和语法,同样有冗长的问题,而一旦开发者对语法熟悉和适应之后,这种“易读性”的优势就相对下降,而冗长度越来越成为负担。

有些编程语言甚至用符号代替自然语言的关键字,一个原因应该也是试图提升这剩下 30% 的部分的“信息密度”,从而提升阅读速度上限。但这同样存在与英文命名风格类似的问题(见上一部分)。更不用说这 30% 的篇幅决定了,在可读性上的挖掘潜力相对有限。

说这些有什么用?

对我来说,是重新审视标识符命名对中文母语开发者的意义(不仅在用母语中文命名标识符时),以及中文编程语言设计参考自然语言时的相对优势。先上个刚看到的图:

据说来自Lost (or gained) in translation

【07/08 夜深,搁笔,改日再更】

2020/07/10 继续。以下部分的主角是母语为中文、英语为第二语言的开发者(以下简称为“国内开发者”,对应英语为母语的“国外开发者”)。

命名

上面的图的数据很惊人,从字符数上看,1000 字的英文文本在翻译成中文后,几乎只有 300 字左右。不妨比较之前的 AppleScript 例程与假想的对应中文代码:

the first character of every word whose style is bold
每个单词的首个风格为粗体的字符

54 个英文字符,16 个 中文字符。54 * 0.3 = 16.2,果然差不多。

但是,如果把这个函数用驼峰命名呢?(笑,刚发现这句英文有歧义,我上面的中文和最上面表格的代码{ words | style == bold }.character[1]语义不同)

firstCharacterOfWordsInBoldStyle (貌似还是有点歧义,就这样吧)
每个风格为粗体的单词的第一个字

33 个英文字符,仍是 16 个中文字符。虽然字符个数仍只有一半,但是“视觉效果”已经很接近了。我的 IDE 中的屏幕长度比大约是 26/33 = 79%

正好昨天看到如下讨论:

A: 英文为了适应编程 , 还不是弄出来驼峰 这样奇怪的用法( 我问过国外同事, 在他们眼里 下划线还可以接受 ,驼峰真的怪 )

B: 我反正觉得驼峰很正常

乍一看会觉得匪夷所思,为啥国外开发者有些看不惯而国内反倒觉得正常呢?

从与自然语言的比较来看也许就易于理解了:就上面这个例子,在格式和信息密度上来说,驼峰命名都更接近中文自然语言。

这里的信息密度 = 包含信息 / 视野

在格式上,驼峰不用空格分隔,中文也是。在信息密度上,中文与驼峰基本相当也许略高(与我之前的体验也吻合)。国内开发者自然对中文的信息密度早已习惯,适应驼峰的信息密度相对更容易,而国外开发者也许反而需要花额外精力适应这种高于日常用语的信息密度。

这意味几点:

  1. 如果其他开发实力相同,那么单从阅读英文代码的效率来说,国内开发者也许更有优势。
  2. 如果具备编程所需基本素养,国内的新手相对更易培训成为程序员。

第一点意味着,很多程序员即使在与国外开发者共事时,也难得会由于阅读代码效率(很大影响 debug 效率)而落下风。第二点,则意味着,对于“搬砖”性质的活,相比国外来说,国内更易找到替代者(转行到程序员更容易)。

当然,两点的大前提都是“如果英文水平足够”。准确的说,是水平足够适应英文命名的风格,也就是前文说的英文自然语言的这种“DSL”,或者“方言”。比如上面的 AppleScript 例子,可以看到驼峰命名中为了用短语代替从句而去掉了the,whose,every,is等词。

往往,这并不需要英文绝对水平多高,因为编程需要的词汇用语是相对局限的(详细阐述见此)。从这个角度说,也更容易理解,中低端岗位为何明显有越来越多竞争者。

到这里为止,听起来中文命名似乎没有什么推广的需要。我是不是把自己绕进去了?

关键关键就在于:国内开发者在项目中始终遵循这个相当于英文“方言”的命名规范,有多难?

“遵守命名规范”自然是老生常谈,这里不过将其纳入整个理论体系中。

如果是新手,往往根本不顾什么命名规范只图方便完成功能即可。即便是有意遵守规范,如果接手了一批代码,往往也很难通过阅读所有代码而早早习得各种风格。而完全遵守命名规范编写代码即使对老手而言也是挑战,毕竟是第二语言又和自然语言有距离。

更何况,第二语言水平随年龄下降的幅度还大于母语(个人感觉),这使得即使项目老鸟也很难保证一直坚持沿用这种英文“方言”。代码互审固然能治点标,但不治本。

这一问题在多人合作、或者单人但工期较长的项目会尤其突出。这也意味着,相比较国外同样的中大型项目,国内项目花费在英文命名规则维持的开销会更大(如果不维持,必然导致更严重后果),整体投入产出比更低,从而不得不更倚靠增加工时来弥补,甚至更易于夭折。

据了解,一些国内项目会建立一个中英对照术语表,这从一定程度上可以辅助维持命名规范,但是难免无法覆盖所有命名风格。更何况,维持这个术语表以及开发时频繁参看这一术语表都是额外开销。

说到这,中文命名的优势就不言自明了:命名几乎与中文自然语言完全相同前文第一条)

与驼峰命名等相比,在消除了第二语言的因素、可以直接使用文档中的母语术语之外,还意味着国内开发者不用为编程演化出一套“方言”来就可以直接命名,因为中文自然语言的信息密度已经够高

这里值得提的是,之前看到几次关于如何将“get..By..”这样即为常见简约的英文命名结构变为合适中文的讨论。现在更能理解,这是习惯了英文“方言”之后的自然问题。诚然,现在还没有同样达成共识的中文对应结构。但是,这完全不妨碍将此英文结构保留而将其他部分用中文命名来提高部分可读性。比如:getCostOutcomeRatioByClientGroup->get投入产出比By客户组。这里的前提是,这个英文结构非常易于阅读且几乎成为了不成文的规则,从而并不会是可读性和易写性的瓶颈。

嗯好像听到了那谁说“频繁切换输入法”是吧?类似这样的 IDE 插件可以不需切换输入法补全:

事在人为,不因噎废食。这样可以在中文命名结构完善成熟之前,沿用英文命名风格的某些常见易用的部分。

【中文编程语言部分待续】