[译] Go语言的源起,发展和未来
本篇内容是根据2019年9月份Creating the Go programming language音频录制内容的整理与翻译,
两位主持人与Go 的创始人 Rob Pike 和 Robert Griesemer谈论了 Go 的起源、发展、影响和未来。这是一个史诗般的剧集,深入探讨了 Go 的历史和详细信息,以及他们在创建这种出色的编程语言的过程中所做的选择。
访谈中有不少可能不为人知的小八卦: 例如new和make的初衷,Rsc其实是个"工程师二代"等. 一向金句频出的Rob Pike,还谈了对Python和Rust的一些看法.
过程中为符合中文惯用表达有适当删改, 版权归原作者所有.
Carmen Andoh:欢迎大家收听 Go Time!今天的节目非常特别。今天是我们第100期节目,哇哦!我们邀请了非常特别的嘉宾。今天的主持人有我,Carmen Andoh,还有 Jon Calhoun。
Jon Calhoun:大家好!
Carmen Andoh:今天的两位嘉宾是 Go 编程语言的创造者 Rob Pike 和 Robert Griesemer。欢迎两位!我们非常荣幸能请到你们!
Rob Pike:太好了!谢谢邀请我们。
Robert Griesemer:大家好。
Rob Pike:Ken 本来也应该在这儿的,但他现在正在希腊度假,所以… 他赢了。
Carmen Andoh:[笑] 对,第三位---
我本来想凑个三人组的,但是… 对,他说他有一个非常好的理由不能来,他正在希腊度假。我们也希望自己能先去希腊,但现在上 Go Time 也算是个安慰奖吧… [笑] 或许吧,也可能不是。
Jon Calhoun:看来我们的预算不允许我们全体飞去希腊。
Carmen Andoh:是啊,那样就太酷了。
Rob Pike:你们有问吗?
Jon Calhoun:没有。我应该问的,不过我觉得预算可能不够。预算非常有限。
Carmen Andoh:你好,Robert。
Robert Griesemer:大家好,很高兴来这里。
Carmen Andoh:好吧,那我们开始吧。来聊聊 Go 吧。我想大家最想知道的其中一件事就是最初的日子是怎样的,在你们决定“嘿,我们来写一个编程语言吧”的时候。
Rob Pike:Robert,我想这有点是我的错,对吧?我不太记得具体是怎么开始的,但我们喜欢讲的故事是,我们刚看完一个关于 C++ 新版本的演讲,而 C++ 是 Google 大多数服务器软件使用的语言… 我已经思考了一段时间,觉得 C++ 不太适合,因为它不支持我们刚接收到的多核机器。我还想回到我多年前在并发编程中探索过的一些想法… 然后我们坐在一起---
我和 Robert 共用一个办公室,大概在 2007 年 9 月,我想我真的就是转过椅子对 Robert 说:“嘿,Robert,我们得做点什么。”
我们聊了几分钟,然后 Ken 在隔壁办公室,所以我就跑去找 Ken,问他:“你想帮忙吗?”他说想,那就这样开始了。Robert,这和你的记忆一致吗?
Robert Griesemer:是的,我觉得 C++ 的事情可能稍晚一点发生---
我不是 100% 确定---
但肯定是在九月;我昨天看了我的笔记,我想那应该是一个星期五的下午,或者是前一天,因为我们在一个下午, 预订了一个会议室,进行了三小时的头脑风暴。我的记忆有点不同,我记得你当时在写一个 C++ 程序,非常让人沮丧,你遇到了一个长达几分钟的编译时间暂停,然后…
Rob Pike:45 分钟。
Robert Griesemer:好吧,45 分钟,你当时不太高兴。然后我们其中一个人说:“我们应该停止做这个,或者停止抱怨,尝试做点什么改变。”我猜我们俩几乎立刻就决定:“是的,我们真的应该做点什么。”
Rob Pike:是的,那次漫长的编译也是因为我不被允许使用线程来解决程序中的并发问题,因为 C++ 库在这方面工作不正常,而且风格规则禁止在二进制文件中使用线程。所以我在做一些非常复杂的操作,试图解决一个在我看来非常简单的工作… 但是每次我动了任何东西,我都得等 45 分钟再编译一次,还是在一个巨大的分布式编译集群上。某个时刻,我的士气彻底崩溃了。我们必须做点什么… 但我清楚地记得当时转过椅子对 Robert 说:“帮帮忙!”
Jon Calhoun:那么你们当时开始的时候,是马上全职投入,还是像 20% 项目那样,作为副业来做的?因为对于大多数人来说,这样直接放下手头的工作去开发一门语言是非常困难的。这是一个很大的项目。那么当时是怎么样的?是像每周五花 20% 的时间来做,还是别的什么方式?
Robert Griesemer:我觉得我们是关上门开始聊的。我其实已经想了一段时间关于语言的事情了。我之前在其他语言上工作过,脑子里有很多想法,虽然我从来没有写下来,但已经在我脑子里呆了好几年;我时不时会想想这些… 不是真的想着做点什么,更像是个人的兴趣项目。
对我而言,完全不可能再做另一个项目了,因为我刚刚开始了另一个新项目,那就是 V8 解释器,这是 Google 为 Chrome 开发的新 JavaScript 实现。所以很长一段时间内,我都是在挤时间来做,直到我终于说服我的经理接受我可能想做点别的事情。
Rob Pike:我们当时肯定都有正式的工作,所以我们是挤时间来做的… 但我必须说,我们的老板---
至少是我和 Ken 的老板---
那时候是 Bill Coughran(译者注: 2011年离开谷歌,现在在红杉),他也是从贝尔实验室和我们一起过来的,他在早期非常支持我们,给了我们相当多的时间去做这个项目。他还多次替我们辩护,防止一些人认为我们应该去做别的事情。但大约六个月到一年后,我想我们都全职投入到这个项目中了。
Robert Griesemer:是的,我同意 Rob 的说法。我们非常感谢 Bill Coughran,如果他没有给我们这个自由,这个项目可能就不会发生了。
Carmen Andoh:而 Bill 之前和你们在贝尔实验室就已经共事了,他已经和你一起在贝尔实验室完成了很多其他的项目,Rob,所以他大概知道你如果放手去做,可以创造出什么。
Rob Pike:是的,Bill 是我遇到过最好的经理。他和我大概在 1980 年相隔一两周的时间加入了贝尔实验室,所以我们彼此非常熟悉。我们都在那里的计算机科学研究中心工作了二十多年。后来他升职成为该中心的主任。我已经不太记得那时候我的具体职责是什么了,但我们确实一起完成了一个大项目,像 Plan 9 就是在 Bill 的领导下完成的,还有其他一些内部的网络项目。
所以我们和他作为经理一起工作了很久,我非常努力地把他招来了 Google,因为 Google 需要像他这样的人,而我也希望他能成为我的经理。所以是的,他是这个项目中的重要人物。我觉得在这些故事里,人们经常忽略了那些虽然没有直接参与但却帮助推动事情发生的人的重要性,而 Bill 在这方面做得非常好,这也使得他成为了一位出色的经理。
Carmen Andoh:这是个很棒的故事。所以—
Rob Pike:请继续。
Carmen Andoh:不,我让你说。
Rob Pike:我只是想再补充一下时间线。到 2008 年 4 月的时候,Ken 已经在编写一个编译器了,最初是编译成 C 代码,然后再用 C 编译器编译,因为这样更容易起步… 虽然这种方式并没有持续很久。我记得 2008 年 4 月,我那时候在悉尼,我想 Robert 那时候也来了悉尼,我们有一个会议室,里面有全时段的视频电话,连到 Ken 在加州的办公室,我们三个人一起编写了语言规范和实现编译器。Ken 在编写编译器,我在编写规范,我们来回合作了大概一两周时间吧。
Robert Griesemer:两周,是的。
Rob Pike:那就是规范诞生的时候。是的,大概两周。所以我们大概花了六个月的时间在头脑风暴和大致构思上。我们做的第一件重要的事情之一---
可能是最重要的事情之一---
就是我们写了一份正式的语言规范,我认为这对项目的成功至关重要。
Robert Griesemer:没错。
Rob Pike:其中一个最重要的事情是 Ian Taylor 当时也在 Google,他看到了规范,决定想为这个语言写一个编译器。所以有一天他走进我们的办公室说:“哦,顺便说一句,我已经为你们的语言写了一个编译器。” 那对我们来说是一个非常惊人的时刻。他当然后来也成为了团队的一员,现在还在继续为 Go 工作。
Robert Griesemer:是的,这完全出乎意料。所以在悉尼的时候,我记得我们已经写了不少东西,但还不够正式。如果我记得没错,我们花了不少时间试图弄清楚如何正确地处理 map。我们想把 map 加入语言,但不太确定怎么做才好,我记得是你,Rob,最后说:“我们应该让它在 90% 的情况下工作得很好,对于其他特殊情况,我们不该让事情变得更复杂。” 回过头看,我觉得这是一个非常好的决定。
Rob Pike:我不记得了,但这听起来像我的风格。我们还努力让数组能够良好工作,最后变成了 slice。
Robert Griesemer:对,那个花了更长的时间,我觉得。
Rob Pike:是的。我记得 slice 是在我住院的时候发生的… 因为我几个月后出了个严重的事故,在医院住了一段时间。当我出院的时候,我记得 slice 就快完成了。我没有参与那部分,但我对结果非常满意。
Robert Griesemer:slice 的一些关键想法是 Ken 的贡献。
Rob Pike:是的,绝对是 Ken 的想法。
Jon Calhoun:所以,当你们说这些东西很难弄清楚时,是因为你们看到其他语言的做法并不合适,还是有其他原因?毕竟其他语言里已经有数组的处理方式,你们原本可以直接照搬,但你们选择了不这样做,为什么呢?
Rob Pike:是的,你得决定语义是什么。至少 Ken 和我都深受 C 语言的影响,所以我们花了一段时间才放下那些想法。但 C 没有的一件事,我非常想要的,我觉得 Ken 和 Robert 也同意,就是我们想确保有一种方法可以处理变长数组,或者说我们现在称之为 slice(切片)… 而在 C 的内存模型中做到这点有点棘手。
显然,很多其他语言已经实现了类似的功能,但我们必须决定如何选择这些功能的行为,确保它们与我们试图构建的语言模型相匹配。你不能通过从其他语言中随便抓取功能并粘贴在一起来设计出一个好的语言;相反,我们试图构建一个统一的语言模型,让所有部分都能协同工作。map 和 slice 很难,因为我们不得不采用与我们通常思考这些问题完全不同的方式,至少对我和 Ken 来说是这样。Robert 可以讲讲他的看法。
Robert Griesemer:是的,我来自完全不同的背景。我并不是从小就接触 C 语言;我成长于 Pascal 及其后继者的环境中… 其中一个后继语言是 Modula 2,然后是 Oberon,它们有一个类似的特性,叫做“开放数组”,是一种动态大小的数组… 但它们只能作为函数参数传递。所以你可以在函数内部拥有一个动态大小的数组,具体大小取决于传递的数组类型。这很不错,但没有我们想要的那么灵活,所以我们花了一些时间从 C 语言的各种想法以及这种开放数组的思想中提炼出我们现在拥有的东西。
Rob Pike:map 和 slice 的共同点是它们的内存表示在用户面前是部分隐藏的,这在 C 语言的基础层面上是不存在的。它们有更复杂的结构来存储数组的长度,或者 map 的哈希桶,等等。而 C 语言在基础层面上从来没有类似的东西… 这给我们带来了挑战。后来我们发现,为了让 slice 和 map 正常工作,它们必须以描述符块的地址形式传递,我们纠结于如何最好地隐藏这些指针。
有段时间这些指针是显式的,但这让人不太舒服,所以我们最终决定完全隐藏它们。但要做到这一点,我们不得不改变内存分配的方式,这也是为什么有两个分配器---
new 和 make。我从来没对这个很满意,我想没人对这个结果真的很满意… 但实际使用中还算可以。
Russ 加入后稍微改善了一些事情,他决定我们可以通过在字面值上使用地址创建操作符,大部分时候不再使用 new
。这清理了一些东西。所以现在大多数人只会看到 make
,他们几乎不会看到 new
。我想这对这个听众来说可能有点过于细节化了,但…
(译者注: 原来如此…make和new的区别也是面试常见八股文, 有了这段一手资料,更可以知道来龙去脉,知其所以然了)
Carmen Andoh:不,这很棒。
Jon Calhoun:没关系。
Rob Pike:…就是这么回事。
Carmen Andoh:我觉得这个播客的听众正是需要这些信息的。你提到了一些令人惊讶的时刻,也提到了 Go 历史上可能成为历史转折点的时刻。第一个是 Ian 突然来到你们办公室,说:“嘿,你们写的规范---
我已经有一个编译器了。”你还能记得其他类似的时刻吗?那些你认为是早期的转折点或关键时刻的?
Rob Pike:Russ 是在 Ian 之后不久加入的。他曾经是 Google 的实习生,和 Jeff Dean 一起工作。他负责了代码搜索的外部发布,这对于一个实习生来说是相当了不起的… 我之前在贝尔实验室和他共事过。他是贝尔实验室另一位经理的儿子,那位经理在声学部门工作,不是计算机方面的 。但 Russ 常和贝尔实验室的一些孩子们一起玩,我认识他有一段时间了。他的名字出现在我和 Brian Kernighan(译者注: 即著名的BWK) 写的一本书里… 我非常努力地说服他来帮忙。
我记得我当时在悉尼,Robert 也在那里,我们正在编写规范,我通过视频采访 Russ,告诉他我们在做什么,试图说服他加入我们… 他最后决定来了。
他大概是在 2008 年中期加入的团队,他的加入对整理我们留下的一些混乱有很大帮助,也帮助我们推动项目向前发展。所以他的到来是一个巨大的事件。
那时候我们是五个人,我们五个人大概一起工作了相当长的一段时间。到 2009 年正式发布之前,我们只增加了一些辅助人员。Robert,你觉得对吗?
Robert Griesemer:是的。我记得好像在 2009 年,我们至少有 Adam Langley,可能还有一两个人加入了…
Rob Pike:但他只是帮忙,不是正式的团队成员… 尽管他为我们做了大量工作。我们真的很幸运。
Robert Griesemer:确实如此。
Rob Pike:他为我们做了很多加密工作,还帮助我们建立了第一个网站… 类似的事情。
Robert Griesemer:对,对。我想我们差不多是五、六个人。还有一位女士---
可惜我忘了她的名字。
Rob Pike:对,Jeanie Kim(译者注: 未找到相关信息)。没错。
Carmen Andoh:这都是在开源之前的事情。你们想聊聊到 2009 年 11 月 10 日开源那天的经历吗?
Rob Pike:我们知道,如果我们真的要做这个项目,它一定会是开源的… 所以我们从一开始就计划做一个开源发布。但我们希望在向世界展示之前,尽可能地把它做对,或者尽量做到最好。在发布前大概有两年的工作时间,最后几个月我们匆忙清理了那些我们还羞于公开的东西,尽管不是所有问题都解决了…
在公司内部发布时遇到的那些常见问题---
像商标、专利和所有那些麻烦事,处理好这些问题才能确保许可正确。我必须说,Google 对开源软件的态度非常棒,发布开源项目从 Google 内部进行比我在 AT&T 内部的经历要容易得多。但要做到这一点,我们必须决定核心库里应该包含什么。Adam 帮我们做的加密工作非常棒,它使得我们能够支持 TLS 等功能。现在 Go 实际上已经成为很多加密工作的基石,很大程度上要感谢 Adam。
我们还得建立一个网站,让人们能看到它;我们得把规范整理好,处理内容管理系统的问题… 我们一开始用的是 SVN,然后转到了 Perforce,因为那是 Google 内部使用的系统。但后来 Git 出现了。我想 Go 的创建时间早于 GitHub,但不早于 Git 本身。我们当时运行的是 Mercurial,因为那是 Google 的开源产品使用的系统… 所以我们用了 Mercurial 大概两三年,然后才最终转向 Git,一旦我们意识到它才是未来。
所以 Go 实际上经历了四个内容管理系统---
SVN、Perforce、Mercurial 和 Git。这也是我们社区文化的一部分---
唯一不变的就是变化。
Carmen Andoh:这引出了另一个好问题,那就是当你们将 Go 开源后,社区的加入如何改变了项目的动态?现在有了社区的反馈和共同创作,这带来了哪些变化?
Robert Griesemer:嗯,我觉得一开始的反应有点两极分化,一些人觉得“哇,这很棒,很有趣”,也有一些人觉得“这太糟糕了”。然后从那里慢慢开始转变…
Rob Pike: 我觉得很多人在我们最初发布时并没有理解它的意义。这看起来不像一个“有趣”的语言… 用引号的“有趣”。“为什么它是这样的?为什么没有我期待的那些功能?”等等。对我们来说,语言的意义在于,我们试图让我们每天写的软件变得更容易,我们认为没必要使用那些复杂的功能来做到这一点。
但一旦人们开始使用它---
我想现在仍然有一些反对者,但看到这种情绪慢慢从“这没用”转变为“其实还不错”,再到“哇,这太棒了”是很让人欣慰的。这花了几年时间才真正取得进展。
第一次 GopherCon 是发布之后几年才有的,我还记得当时站在有五百多人的一间屋子里,所有人都因为 Go 而激动不已的那种感觉。想到 Robert、Ken 和我创建的东西把这些人聚集到了一起,这真是一个非常美好的时刻。但我们不可能一夜之间就做到这一点,社区的形成是一个非常渐进的过程。
Robert Griesemer:对,对。至少对我来说,当我想到第一次 GopherCon 时… 我们当时并不确定这是否是一个真正的事情,因为我们与那个活动几乎没有关系;我们没有组织它,但显然我们受邀参加了… 当我们到达那里时,我们并不太清楚会发生什么。“这会是个大活动吗?还是会有 24 个人坐在一个小房间里?”结果是几百人参与了,而且是一个组织得相当好的活动,这是一个非常积极的惊喜。
Rob Pike:而且真的很有趣。
Robert Griesemer:而且非常有趣,是的。我觉得在通往那个时刻的过程中,Docker 的流行也起到了帮助作用,因为它使用 Go 编写了大部分软件。我觉得 Docker 的成功和第一次 GopherCon 是我们获得的第一个大突破。你同意吗?我不太确定。
Rob Pike:是的,Docker 算是我们的杀手级应用,因为它是用 Go 编写的,工作效果很好,它成为了现在所谓的云计算的核心… 我们过去称之为系统编程或者服务器端编程。而一个关键技术是用 Go 编写的,这向很多人证明了这门语言的价值… 我觉得 Go 确实非常适合这种工作;这正是我们在设计语言时想到的那类应用,尽管我们自己并没有去做 Docker。
后来 Kubernetes 也是一个类似的例子,这次是 Google 的项目。但有重要的软件用你的语言编写,这是让一门语言成功的关键部分。不管语言有多好,如果没有人用它编写任何东西,它都不会成功。
Jon Calhoun:你们知道 Docker 团队在一开始就用 Go 编写它吗?你们有参与他们的开发吗,还是后来才知道的?
Rob Pike:没有,我们没有参与。我们后来才知道的。我见过 Solomon,他是 Docker 的负责人… 我想他是团队的负责人吧,不太确定。Solomon Hykes。他有一次来过 Google 在旧金山的办公室,我们聊了一下,但那是我第一次见到他,也是我第一次真正和人讨论 Docker。但那时它已经是一个很成熟的项目了。
我在某个会议之后看到了一段 YouTube 视频的演示,从中可以看出这就是未来。我知道那是个大事。Docker 是一个非常棒的技术。它利用了 Google 内部操作系统级别的工作,把它包装成一个非常好的用户界面和工具,使其真正可用于日常工作。我觉得这是一个非常好的项目。它变成了一个庞大的项目,启用了 Kubernetes 和我们今天用来运行大规模系统的所有云级技术。
Carmen Andoh:在这次重大突破之后,Go 开始被广泛采用,成为云计算的语言。你能回忆起一些成长的烦恼吗?现在回想起来,有什么是你希望当时能以不同方式处理的吗?
Rob Pike:嗯,没有什么是完美的……语言中有很多东西我想要改变,但这里可能不太适合深入讨论这些。我确实觉得团队当时还没准备好与开源社区互动,也不太清楚这意味着什么。Ian 是我们中唯一一个在开源世界有丰富经验的人,他承担了很多与社区相关的工作。
我们花了很长时间才理解成为开源社区的一部分意味着什么,尤其是当这个项目是由公司资助,但又有大量开源贡献者的情况下。实际上,很多杰出的开源开发在早期就发生了。比如,Windows 版本的移植完全是由外部贡献者完成的,这非常棒。社区的反馈对我们来说至关重要。
我觉得有时候人们认为 Google 对 Go 的控制太多了,这是他们的观点,但我不同意;我觉得他们低估了团队有多重视听取开源社区的意见。我们阅读所有的问题报告,处理得很好……虽然有时候处理得不太好,但最终都会修正。
当有成千上万的人在使用这个语言,现在据说全球已有数百万 Go 程序员时,如何倾听他们的意见,同时确保项目的核心不被偏离,这并不是一个简单的事情。我觉得很多人认为这是小事,认为你只要接受大家的意见就好了……但那样的话你就不会有 Go 了,而是会有另一个完全不同的东西。这是一个非常棘手的平衡行为。
Jon Calhoun:我猜部分原因是因为像我这样的人,工作中可以对网站进行重构,或者发布一个库的新版本。如果我第一次搞错了,也不难去改变……而你们面对的东西要难得多。
Rob Pike:是的,我们确实让它难以改变。我们在 Go 1 发布时明确写下承诺,不会改变任何东西。这对语言的成功至关重要,因为这让公司可以信任我们,他们依赖我们不会破坏他们的系统。这个承诺让我们在做出改变时变得更加困难。我觉得很多人并不理解我们对这个契约有多么坚定的信念。即使这个项目已经有十年历史了,我们依然没有破坏过用户的程序。这确实是个很大的负担,但这是我们能走到今天的关键。
Robert Griesemer:没错。一旦我们发布了 1.0,很多公司就开始采用它了。在那之前,他们只觉得“这很有趣,很酷……”但这也是我们停止做任何重大改动的时间点。
在发布 1.0 之前,我们做了很多改动。比如,最早版本中还存在分号(;
),如果我没记错的话。我们在 1.0 之前还能做一些改动,但之后就停止了。
Jon Calhoun:1.0 之后你们不能再做这些改动了。在那之前,这些带有主观性的改动是否也很难?比如,有些人不喜欢未使用的变量会触发编译错误。我猜如果你们想在后来加入这个功能,可能会很难,因为有人可能会说“为什么要做这个?你在破坏我的代码。”如果在 1.0 之前,你们有收到开源社区的反馈吗?还是说那时相对容易一些?
Robert Griesemer:我觉得那时候我们收到的反馈不多,主要是一些 bug 报告。我们那时还没有处理功能请求的流程,所以我们并没有看到太多类似的反馈。当然,1.0 之后我们不能再做这样的改动,因为这会破坏兼容性,而这是我们不想做的事情。我们至今也没有做过。
Rob Pike:Go 的一些特性对它的成功很重要,但人们并不喜欢。你提到的未使用变量会触发编译错误就是其中之一。这确实很烦人---
你忘记删除一个未使用的变量,程序就无法编译。但对我们来说,这是我们想讲述的故事的一部分,即尽可能确保编写出高质量的代码,尽管我们无法阻止你写出糟糕的代码,但我们可以确保不会有东西溜进来,导致编译变慢或者代码难以维护。
另一个让人抓狂的特性是:不能导入未使用的库。这对我们来说非常重要,因为我们在处理庞大的代码库时,花了大量时间应对冗余依赖,导致编译变慢、二进制文件变大。确保你的程序只包含必要的依赖对我们来说至关重要,但对很多人来说,每次你删除一个打印语句,编译器就会告诉你“你不再使用这个库了,我不再帮你编译了”,这非常烦人。
后来 Brad 写了一个叫 goimports
的工具,它是 go fmt
的一个变体,自动管理导入语句。这基本上解决了这个抱怨。正如常常发生的那样,自动化可以消除很多抱怨。
Robert Griesemer:导入语句的设计当然是编译器能轻松判断是否使用了某个库,但我们希望程序员能够清楚地看到自己依赖了什么,并且明确地意识到自己添加了一个新的依赖。
Carmen Andoh:这是个事后诸葛亮的问题,但你们有预见到 10 到 12 年后,软件复用的现状会是什么样的吗?
Rob Pike:没有预见到。
Carmen Andoh:那这只是某种幸运的猜测或直觉吗?
Rob Pike:其实这并不是为了软件复用,而是基于我们在 Google 的经验。在 Google,我们有一个庞大的环境,有成千上万个库可供使用。我们曾见过一些努力清理这些库的尝试,结果有时能减少 40% 或 50% 的二进制文件大小,因为真正未使用的依赖被剪掉了。所以我们知道依赖管理是保持编译干净的重要部分,语言可以在这方面帮到你。这是语言为软件质量提供帮助的少数几个地方之一,而且这也是一个很容易做到的地方,值得坚持。
但人们抱怨说编译器会因为一个看似无辜的错误而大吼你……但我们希望编译器只接受干净的程序。正如我所说,社区确实有很多邮件抱怨这件事,但 Brad 通过创建一个工具很好地解决了这个问题,这很棒。
Jon Calhoun:那这也是 go fmt
以及类似工具背后的动机吗?你们是想强制大家的代码符合某种标准吗?因为在很多其他语言中,每个人使用不同的格式设置,比如 Prettier(译者注: 一个支持多种语言的代码格式化工具) 在格式化 JSON 或其他内容时,每个人都有自己的一套规则,不管你去哪里,代码风格都不一样。
Robert Griesemer:go fmt
的想法部分来自我作为代码审查员的挫败感。大多数公司,尤其是 Google,都有一个流程,要求我们相互审查代码,确保所有提交的代码都经过同行评审……而这些评审中的很大一部分是遵循风格指南。如果你看过 C 或 C++ 的风格指南,其中很大一部分都是“这里要缩进多少,那边要有空格”等等。这些东西与工程本身无关,却耗费了大量时间。所以我觉得这是我们应该完全自动化的事情。数千名工程师浪费时间彼此指出“这里需要加个空格”或“这里不需要空格”,这实在是浪费时间。
当然,之前也有格式化工具,但我建议我们应该做这个,并且我想要去做……Rob 说“那你去试试看吧。”确实花了一段时间,这毫无疑问;花了好几年才达到今天的效果,当然它并不完美,但人们已经开始喜欢 go fmt
,即便有时他们不喜欢它对他们代码风格的处理。
Rob Pike: 我想 go fmt
是我们在头一两天就定下来的事。我们知道我们想要强制执行这一点。
Robert Griesemer:没错。
Rob Pike:go fmt
的实现全归功于 Robert,因为这是个真正的工程挑战。我相信 Go 是第一个通过外部工具强制代码格式的语言。虽然有些语言的语法不同,但 Go 是第一个说“你必须运行这个工具来格式化代码”的语言。而这种做法影响了其他社区。现在有一个 Java 的格式化工具被广泛使用,Rust 也有类似的工具,C++ 通过 Clang 也有格式化工具,我觉得越来越多的人理解了它的价值。
从我的角度来看,项目中发生的一件非常有趣的事情是,go fmt
的出现不仅非常棒,最终还被大家接受了,它还启用了我们之前没预料到的某些工具。因为事实证明,如果你有一个格式化代码的库,你可以编写工具来自动进行代码重构,并生成格式标准、可以直接提交的输出代码。我们有不少这样的工具。
在 Go 1.0 发布之前,库和语言细节发生了很多变化,Russ 写了一个叫 gofix
的程序,它有一些插件模块,用来实现语言更新或库的更新……但这个过程的惊人之处在于,我们每周发布一个小版本,通常附带一个 Gofix 模块,用户可以更新 Go 的安装版本,然后运行 Gofix 对所有代码进行自动更新。所以我们带着整个社区一起前进,而不是通过功能或“如果…那…”这样的方式来管理兼容性。我们开发了一个工具,让每个人都可以随着项目进展一起更新自己的软件。这是由 go fmt
促成的,但直到事情发生时我们才意识到这一点。
Robert Griesemer:是的,我觉得这是 Russ 开始的。
Rob Pike:是的。我们通过 gofix
进行了一些大规模的重构,尤其是在 Google 的代码库中。这真是一个惊人的发现,而且完全是意料之外的。
Carmen Andoh:你们提到 go fmt
及其意外的后果……你们觉得 Go 如何影响了开源世界?
Robert Griesemer:我觉得现在……也许不只是开源世界,更多是新兴语言……如果你现在推出一门新语言或系统,你可能会随之发布某种格式化工具。这几乎已成为标准要求。我觉得统一的代码格式影响了开源世界,因为这确实带来了一些积极的副作用,比如在合并代码时,你减少了因为格式差异而产生的无意义的变化……所以这里有一些协同效应。
Rob Pike:此外,所有代码看起来都一样,这听起来有点奇怪,但……没有两段 C 代码是一样的,而每段 Go 代码看起来都一样。我觉得这让你更容易与他人协作,更容易理解代码……这非常好。
我们还做了另一件事,虽然 Go 不是第一个这样做的,但它是最明确要求源代码必须是 UTF8 编码的语言之一。我们直接抛弃了那些荒谬的其他编码。我不会说 Go 改变了 UTF8 在世界上的重要性,但我认为几乎所有在 Go 之后发布的语言都遵循了相同的 UTF8 输入规则。
我们希望在另一个方面有更多的影响,那就是先写规范的理念。我觉得很多后续开发的语言如果能先写规范,会受益良多。我知道 Rust 直到最近才开始有一个正式的规范;他们正在编写一本书,至少据我所知……我觉得这很奇怪,你在没有准确知道自己要实现的语言是什么的情况下就开始编写编译器,这让我难以理解。
有了规范之后,你可以直接为替代实现铺路……现在已经有好几个 Go 编译器了。有 Go 到 JavaScript 的编译器,有 GCC/Clang 套件中的 Go 编译器,有 LLVM Go,还有我们自己为 Go 项目运行的原始 Go 编译器,所有这些都是基于规范的。如果你没有规范,只有编译器,你就无法很好地了解语言中的优缺点、其他技术等。所以我觉得规范的重要性并没有被广泛理解,但我希望它能被更多地重视。
Robert Griesemer:我觉得不同之处在于,Go 不是试图进行语言研究;我们试图基于已知的语言设计和技术来开发一个更简单的工具,把它打包成一个更现代、更好用的工具。
很多新兴语言——尤其是 Rust,在我看来确实是在做语言研究,所以……这里有很多未知的东西。
Rob Pike:是的,他们在尝试一些非常不同且聪明的东西,我希望它能成功……但他们试图解决的问题与我们不同。我们在影响方面还有其他什么呢?
我觉得我们对兼容性的立场对社区影响也很大。我们之前提到过,但我觉得其他人如果能像我们这样认真思考如何处理向前和向后兼容性问题,也会受益匪浅……因为这对我们和我们的社区产生了巨大的影响。确实有些事情因此变得更难了,如果你有一个好主意,你不能立即实现它。如果你发现了某个问题,你也不能立即修复它……但社区的稳定性和所有软件的稳定性对 Go 生态系统的增长非常重要。
Carmen Andoh:过去十年中,软件行业和编程语言的发展有什么让你感到惊讶的吗?
Rob Pike:我想大家都对开源成为主流感到惊讶。我记得 GitHub 大约是在 2007-2008 年左右推出的,差不多和 Go 诞生的时间相同。在 GitHub 之前,开源对很多人来说还是一个小众领域。但现在几乎所有企业软件系统都在使用某些开源组件。行业在如此短的时间内发生了如此大的变化,这确实令人惊讶。开源不再只是从网上抓代码的事情;整个依赖管理、更新、在分布式环境中构建、使用 Git 和代码审查工具……所有这些都是新的,我觉得开源社区为现代软件开发做出了巨大的贡献。
但这已经不仅仅是开源社区的问题了,整个软件世界都在使用这些工具……这完全出乎意料,也很令人惊讶,但同时也带来了一些非常棘手的问题,比如依赖管理以及如何确保你的依赖是安全和最新的。 现在一个典型的 Node 安装大约有一千个依赖,这是非常疯狂的……你怎么能自信地说自己信任那一千个你并不拥有的依赖?你如何知道那些代码是好的、安全的、健壮的、受保护的,什么时候该更新,什么时候不该更新,bug 是否修复了——这些问题都非常棘手。 而 Go 现在也面临这些问题。因为它也是从开源生态系统中获取依赖的。Go 的依赖树规模比其他语言要小一些,但仍然很大。比起典型的 C++ 程序,依赖树要大得多……你怎么知道你拥有的东西是值得信赖的?
Go 团队正在做很多工作,试图提高从网络获取代码的安全性和可靠性,但……这仍然是一个问题,它的到来让所有人都猝不及防。
Robert Griesemer:让我感到惊讶的一点是,在 Go 发布后不久,出现了这么多新的编程语言……因为在 2007 年左右,编程语言的世界似乎有些停滞不前。当时有 C++、Java、JavaScript,但没有太多其他的选择。
Rob Pike:还有 Python。
Robert Griesemer:当然,Python 是很广泛使用的……但在 Go 发布后不久,各种不同的编程语言就开始层出不穷,我觉得这很有趣。我想“少即是多”的理念开始引起越来越多人的共鸣。我认为这是一个积极的发展。
Rob Pike:但并不是所有人都认同。
Robert Griesemer:是的,并不是所有人。
Carmen Andoh:我觉得编程语言存在的时间越长,就越需要抵御复杂性或者功能膨胀,对吧?
Robert Griesemer:没错。
Carmen Andoh:那些存在时间较长的语言,它们必须尽力保持简单性。虽然简单性本身是削减的,但为了让事情变得更简单,它们不得不编写各种封装和更高级的封装工具,这其实是一种自相矛盾的做法……所以我觉得这也是我们处在编程语言发展史中这个阶段的一种反映。
Rob Pike:我觉得这是一个战略性的问题。你可以走向另一个方向。其他语言,比如 C++ 或者 Perl,可能会选择拥抱复杂性。我非常佩服 Bjarne Stroustrup(C++ 的作者),因为他给了用户他们想要的一切;用户提出更多需求,他就满足他们。因此,他最终打造了一门语言,这门语言至今仍是全球软件开发的关键部分。Google 的核心系统仍然大部分是用 C++ 构建的,我相信很多其他公司也是如此。
这是与我们完全相反的策略。我们选择的是锁定语言,不做修改……而要做到这一点,你必须相信你的愿景是合理的,是正确的。我并不声称哪种方法更好;它们只是完全不同的策略,而且都可以奏效。这是在开发过程中你必须做出的一个决定,选择你想走的方向。
Robert Griesemer:让我感到惊讶的是,C++ 在 2009 年变得更加复杂,可能现在仍然在变复杂。你说得对,如果你想保持向后兼容,即使你只增加一些小功能,随着时间的推移,语言还是会不断膨胀。我个人希望随着模块化的引入,我们能稍微控制一下这种膨胀。比如说,如果你使用的是 1.15 版本,那你可能不会得到我们认为过时的某些功能,或者那些设计不太好的功能,而是会得到一些其他的东西。所以至少这是我的希望,我们能够控制住这种增长并加以限制……但我们拭目以待吧。
Rob Pike:拥有工具也会有所帮助,比如 gofix
。你可以想象一个新的 gofix
帮助我们在前进的过程中清理代码库……这也是 Robert(与 go fmt
相关的)做的事情之一;在标准库中提供解析器和词法分析器让编写工具变得非常容易。
开源社区早期的请求之一是 IDE:“Go 的 IDE 在哪里?我想要一个 Go 专属的编辑器。”但它从未出现。我们没有创建它。现在有一些……比如 GoLand 是一个 Go 专属的编辑器,但它其实只是 IntelliJ 的一个版本。相反,我们提供了一个非常好的库,用于分析和编辑 Go 程序,任何有一定能力的程序员---
不需要是专家---
都可以基于这个库编写工具。所以我们没有为 Go 创建一个 IDE,而是创建了一个库,让编写 IDE 插件变得很容易。于是,最终所有的 IDE 都很好地支持了 Go,但我们自己从未编写过 Go IDE。这也是一个战略性的问题。我不认为这是有意为之。我想我们确实想要一个 Go 的 IDE,但从未觉得我们是合适的人选去做这件事。 但最终,由于 Go 与自身工具的完美集成,IDE 变得不再必要。
这是另一个问题---
Carmen,你提到了我们做过的事情;我不认为 Go 发起了这一切,但它确实是一个很好的例子,不仅仅是一门语言……它带来了自己的构建工具,自己的强大库。你可以用大约十行代码编写一个生产就绪的 Web 服务器,完全开箱即用。与依赖管理的集成虽然与人们今天想要的不同,但我认为从很早开始它就存在了。现在模块化的东西更直接地解决了这个问题。但为语言提供随附的工具,对于像 Go 这样的编译语言来说是个不寻常的步骤。我认为 Rust 的 Cargo 系统表明这是正确的方向。这是一个转变。
Carmen Andoh:我们还剩大约十分钟,我想讨论一下 Go 的持久特性。我们即将庆祝 Go 发布十周年……下一个十年呢?你们希望 Go 在第二个十年,或者在编程史上走向何方?
Rob Pike: 它已经比我预期的走得更远了,所以现在我也不确定它会走向哪里……我从未想过它会像现在这样流行,变得如此主流。它不是世界上最流行的语言,也永远不会成为第一,但老实说,它的成功让我们非常震惊。
Robert Griesemer:是的,我完全同意。我不认为我们能预见到这一点。我想时间会告诉我们它在十年后会是什么样子。
Carmen Andoh:你觉得它能经受住时间的考验吗?
Robert Griesemer:这取决于时间有多长。我认为我们已经走过了十年---
实际上是 12 年了,从最初开始——目前看来还不错。但事情可能会改变。我认为我们在与社区的互动方式上进步了很多。我们的社区在成长,社区感觉我们是一个具有包容性的群体。我认为这在很大程度上要归功于 Andrew Gerrand 的早期工作,他在社区方面做了大量工作,制定了社区行为准则等。我认为这是一个重要方面。当然,还有这门语言,它的库,等等。
Russ 在模块化方面做出的工作是一个巨大的进步。这是我们最初忽略的一些问题;我们没有很好地解决依赖和版本管理问题。我认为这是业界想要看到的,他们对此感到相当满意。
我认为这些是我们在过去几年中迈出的积极的、正确的步伐。而且还有一个大问题,那就是泛型功能……我认为我们正在接近某种解决方案,但我不认为我们已经完全决定是否要走这条路。
Rob Pike:无论 Go 作为一门语言和生态系统的遗产如何,我认为它所产生的影响将经受住时间的考验。我觉得因为 Robert 的 go fmt
,现在大多数人已经接受代码布局应该由工具来完成,而不是由人手动操作。我认为正确编写规范、确保你有合适的功能是件大事。强制将 UTF 编码纳入语言规范,以及我们之前提到的很多事情---
它们都有影响。我们将代码审查作为标准流程的一部分---
不仅仅是 Pull Request,而是进行全面审查,配合优秀的工具集……这些做法都是很重要的。
我们曾与其他项目讨论过如何接受社区贡献,有时他们对我们的做法感到惊讶,因为我们会首先审查,而不是先接受再进行清理。这是一种态度问题;我们希望确保进入系统的每一件事都是高质量的。虽然这种做法并非普遍被接受,但它非常有效,我认为其他很多项目也学会了思考项目的健康状况,而不仅仅是通过增加功能来吸引用户。
所以我们的生态系统中有些方面虽然不一定是开创性的,但对未来系统的构建有一些影响,无论 Go 的命运如何。
Go 社区还在不断成长,谁知道它会变得多大。正如我所说,我不认为它会成为全球最流行的语言,甚至离这个目标还差很远。它在教育领域还没有建立起多大的影响。我希望看到这一点。我认为除非它在大学中教授,否则它永远不会真正成为主流语言……但这几乎还没有发生。虽然现在有了一点点进展,但还远远不够。而 Python 现在几乎已经成为除了系统软件之外所有领域的事实标准语言,我认为 Python 是未来的语言,大家应该更多地谈论它。
Carmen Andoh:嗯……真是遗憾,因为我学过计算机科学,但我真的不喜欢它。我告诉所有人这个故事。我真希望当时有 Go,因为我确实觉得 Go 能让我们完全重新思考如何教授计算机科学。
Rob Pike:嗯,现在大多数科学软件开发都是用 Python 完成的……这很好,我对此完全没有意见。但正因为如此,而且现在很多普通软件教育也是用 Python 来进行的,所以很难让一门更加简洁、接近机器的语言进入标准课程中。我并不是在抱怨,这只是现实情况。
我很想看到 Go 用于教学。不一定作为入门语言,但作为大学课程的一部分。但到目前为止,它只在一些专业课程中得到了应用。
Robert Griesemer:我认为大学面临的一个问题是,它们几乎有一种使命要教授学生行业所需要的东西,但这并不是我上学时的做法。当我上学时---
我说的是计算机科学---
我们学习的是各种技术和不同类型的语言,以及不同的做事方式,这些并不一定与当时的工业需求密切相关。当时的工业需求可能是 COBOL 或 C。所以只要这一点不改变,大学就很难真正拓宽视野,使用其他语言。
Python 现在特别受关注,部分原因是因为机器学习。Python 让你可以轻松地与底层的 C 库进行连接,它只在顶层起作用。
Rob Pike:还有 Jupyter Notebook,这是一个非常出色的工具,我希望我上学时能有这个工具。
Carmen Andoh:完全认同!这真是改变生活的工具。如果当时有它,生活会完全不同。Jon,你还有什么问题想问 Rob 或 Robert 吗?
Jon Calhoun:我想问的是,你们之前提到的开源问题,当你们开源时,并没有完全准备好与社区互动,那是一个学习过程。我知道我发布的第一个开源项目时,犯的最大错误可能与你们相反。我当时基本上接受了所有人提出的任何东西,因为我非常兴奋,觉得有人愿意参与进来太棒了,所以我什么都接受……可能三个月后,我在维护这个项目时发现维护起来非常困难,因为我犯了一个错误,就是接纳了所有功能;任何我能接受的东西我都接纳了。而你们采取了相反的心态。对于那些想进入开源领域的人来说,还有哪些类似的经验教训是你们认为有帮助的,但可能不太明显的呢?
Rob Pike:嗯,我觉得行为准则虽然对一些人来说很有争议,但它是拥有一个健康社区的重要组成部分。我认为人们需要明白这是一个互相尊重的社区,喷子是不可接受的……尤其是在现今,这一点似乎更为重要,但我认为这是拥有一个健康社区的关键部分。
从技术角度来看——是的,你必须时刻关注自己的目标。如果你让不好的功能或太多的功能进来而没有控制,它最终会变成一个难以维护的软件。但当社区提出你并不认可的东西时,如何与他们互动并控制好这个过程,这需要花费大量的精力。而且你会失去一些人。有人会向你提交一个 Pull Request,你可能会说“你知道吗,我不想要这个”,然后你会解释原因,尽量解释得很好,但他们可能仍然会觉得你错了,感到受到了冒犯,然后拂袖而去。所以你必须尽量在拒绝的时候尽可能友好,而这会非常困难。
Robert Griesemer:是的,我觉得这正是问题所在。你基本上要坚定但礼貌。你要确保人们觉得你在聆听他们,并且认可他们的想法,但这并不意味着你必须采纳每一个建议并实现所有别人想要的东西。我认为这是重点。
Rob Pike:但话说回来,很多东西进来时是很棒的,只是需要在接受之前进行一些打磨和完善。如果你能友好、清楚地解释你想要做的修改,你就会赢得一个盟友,而他们的贡献会让系统变得更好,因为你有了一个想要帮助的新成员。
Robert Griesemer:反过来也一样,如果你能说服某人为什么某个功能请求可能不是一个好主意,并且他们被你说服了,那么你也赢得了一个盟友,因为他们会意识到“哦,好吧,这些人确实在认真思考这个问题。”
Carmen Andoh:在我们结束之前,你们有什么想对新一代 Gopher 们说的建议吗?有最后的话要对大家分享吗?
Rob Pike:享受它吧!我们在早期使用的一个词是---
我们希望让编程再次变得有趣……因为它已经变成了---
至少对我当时所做的一些工作来说,可能 Robert 也是---
一种苦差事。编译需要 45 分钟,而一个一行的修改可能引发系统中的大规模变化。我们希望有一种让人感觉轻松的东西,我想我们应该记住编程可以是件有趣的事情。
现在的云开发环境中有很多移动的部分。复杂性又回来了。确保你专注于正确的变更和正确的方式,让开发保持敏捷、适应性强并且有趣。更多并不总是最好的。有时精简的做法可能是前进的更好方式。
Robert Griesemer:是的,我认为保持开放的心态并跳出框架思考很重要。仅仅因为某件事已经这样做了五年,并不意味着这是正确的方式。我想回到我之前提到的关于语言和教育的观点……今天,大多数人通过正式的计算机科学课程可能只见过一两种语言。Java 可能是其中之一,Python 可能是另一个,但它们属于同一类语言。
很少有人见过过去那些真正不同的语言,比如 Lisp、Scheme 或 Smalltalk,它们与主流语言的做法完全不同(或者是函数式语言)。这些语言会给你提供不同的思路和想法,可能会改变你的视角。但最重要的是,我认为我们要确保复杂性尽量保持低水平。我们真的要在所有情况下尽可能保持简单,因为复杂性最终会伤害你。
Carmen Andoh:听起来像是一个新的 KISS 原则的延伸。太棒了。谢谢你们,Robert 和 Rob,今天能够来到这里,庆祝 GoTime 的第 100 期节目。我们真的感到荣幸,能够与你们在一起非常愉快。
Rob Pike:感谢你们邀请我。
Robert Griesemer:谢谢你们。
Carmen Andoh:我是 Carmen。下次再见,谢谢大家。