Rob pike 在 go 发布 14 年之际做的回顾
可能由于日常英语只读不写, 我在阅读非对应领域或偏文的文章时需要纸笔来记录文章的核心关心用于前后检索. 类似文章都是我的主观理解, 任何你觉得不对劲的地方都以我错了为准就好.
Rob Pike 于 2023 年底, 在 GopherConAU 做了一次分享, 回顾了 Go 这 14 年中做的好和可以做的更好的地方. 文章被转到了 HN, 评论也蛮有意思的, 所以我直接贴 HN 的链接: id=38872362.
Go 的使命是让系统的构建更简单, 更高效
Go 的出现并不是为了解决某个语言的问题, 而是为了解决在 Google 内部构建服务端系统时遇到的问题, 包括但不限于:
- 依赖控制
- 大型团队且人员变动频繁下的协作
- 维护性
- 测试效率
- 有效的利用多核以及网络
Go 是一门程序语言, 更是一种更好的构建高质量系统的方法论.
Gopher: 萌萌的吉祥物是早期成功的一大助力
这么看起来高管们花大力气起名字也是有那么一点道理的, 狗头保命.
做的好的 7 个点
- 早期就定义了正式的官方语言规范
- 有多个编译器实现了官方规范
- 原生的支持多个平台, 包括但不限于 linux/windows/macos, x86/amd64/arm64
- 对兼容性的保证
- 官方提供了基础的库, 避免社区的分裂
- 语言设计时就考虑对工具的友好, 同时也提供了大量使用工具
- gofmt
有争议的点
Rok Pike 认为做的不那么好的点有 6 个:
- concurrency
- interface
- compiler
- project management
- package management
- documentation and example
Concurrency
- 并发(concurrency) 是重要的强力工具, 特别是在多核(multicore)和网络编程(network)中.
- 并发没有错, 错的是(当时的, 2007)解决方案, 包括线程这样的概念, 和 pthread 这样的底层库.
- 强调 Go 是为党国(并发)立过大功的, 包括:
- 在说服编程世界并发是强有力的工具的过程中扮演了一个重要角色, 并且提供了比 pthread 更好的解决方案
- 证明了 CSP 并发模型在过程式语言(procedural language)中适配的非常好, CSP -> Do not communicate by sharing memory; instead, share memory by communicating
- goroutine/channel/select 相对于 async/await, 虽然会导致底层的 runtime 更为复杂, 但是减少了上层使用者需要面对的复杂度
做的不太好的主要有两个点:
- 设计之初主要考虑的是服务端, 类似 net/http 这样的网络库, 缺乏其他领域的使用指南, 导致许多人在其他领域使用时遇到了困难.
- 应该在早期就明确指出并发(concurrency)和并行(parallelism)的区别. 并不是 goroutine 越多, 程序就越”快”.
Interfaces
首先必须要承认, 既不从事相关工作, 也不紧跟社区相关讨论的我, 要理解这部分内容的具体案例比较困难.
interface 是非常有 Go 特色的产物, 这是 Go 在一开始对面向对象设计的回答: 以行为为中心. 社区一直在推动以类型为中心的设计, 最终 Go 在 1.18 开始支持了泛型(generic).
Rob Pike 对此应该不是百分百赞成的.
Sometimes it takes many years to figure something out, or even to figure out that you can’t quite figure it out. But you press on.
Rob Pike 依然认为 interface 是 Go 最好的设计之一, 能够(简单的)解决大部分简单的任务. 同时, Rob Pike 也承认确实有一些案例无法被 interface 处理, 给使用者带来了不便.
但向 Go 中添加泛型的支持, 并不像一些人想象的那么简单. 因为 interface 已经被广泛使用, 泛型方案需要考虑 interface.
最终产物我们也看到了, 我直观的感觉是复杂.
The Compiler
主要讲述了为什么在一开始选择直接用 C 语言实现一个编译器而不是用 LLVM 或者用 Go.
不选 Go 的原因比较简单, 在初期不用 Go 来实现编译器是怕走偏, Go 并不是为了编译器而设计的.
不选 LLVM 这样成熟但庞大的现成生态的原因则是考虑到产品初期需要快速迭代, 所以选择了熟悉的且完全受控的方案.
毫不意外, 再次夸了夸跨平台编译.
Project Management
Go 在两年不是开源的, 这有利于快速迭代. 同时, 团队也知道 Go 这样的编程语言, 是不可能在不开源的情况下取得成功的. 所以在随后变成了一个开源项目.
在这个巨大的改变过程中, 有一些值得一提的地方:
- 社区的声音过于嘈杂, 消耗了大量的时间精力.
- 也带来许多, 比如完全由 Alex Brainman 领导的对 Windows 的支持.
Go 团队花了很长时间让社区接受相关的变更流程. 主要是通过强制的代码 review 和对细节的关注来保证代码的高质量.
Rob Pike 还特别提到 Google 对 Go 团队只发工资但不干涉. 确实只有拥有足够利润的大公司才养得起”闲”人.
Package Management
Rob Pike 首先承认了 Go 的包管理系统是缺失的, 核心是没有考虑从网络获取包的相关内容. 这在一定程度是由于团队早期的成员都来自 Google, 习惯了 monorepo 的工作模式, 并不用考虑版本问题.
更糟糕的一点是, 鼓励社区去解决这个问题, 但是最终的设计让许多人感到被忽视和伤害.
Documentation and Examples
团队在一开始就写了很多文档, 但是没注意到社区还需要案例.
来自 HN 评论区的一些观点
- Go 是 Java 的竞争对手, 而不是 Rust/C 之类
Go 在设计之处是为了在 Google 内部替代 C++ 实现的服务端代码, 实际上它也大获成功. 但除了少量公司, 大家都不会用 C++ 去写业务逻辑, 所以 Go 实际上吃了大量 PHP/Python/Java 在服务端的份额.
但在今天, Go/Java/Python 都有了很深的护城河, Go 在 k8s 为代表的云原生, Python 在 AI 相关, Java 在大数据.
真正的性能苛刻或者低延迟系统还是在 C/C++ 和新起的 Rust 中选择.