成为 Go 程序员的 7 个阶段

无论你是 Go 新手还是经验丰富的 Gopher,你都可能会在通往 Go 启蒙的道路上认出这些步骤。
636 位读者喜欢这篇文章。
3 text editor alternatives to Emacs and Vim

opensource.com

有一天在工作中,我们在工作聊天室里讨论 Go 编程语言。有一次,我对一位同事的幻灯片发表了评论,大概是说

“我认为这就像成为 Go 程序员的七个阶段中的第三阶段。”

很自然地,我的同事们想知道其余的阶段,所以我简要地概述了它们。这里,扩展了更多背景,是成为 Go 程序员的七个阶段;看看你是否能在这条道路上看到自己。

第一阶段:你相信你可以让 Go 进行面向对象编程

在您初步运行 A Tour of Go 后,您开始思考“现在,我如何才能让这种语言更像面向对象的语言……?” 毕竟,您已经习惯了那些东西。您想要编写健壮的代码。您想要多态性。

“肯定有办法!” 你说,然后你找到了 结构体嵌入。它允许您巧妙地将方法从封闭对象委托给嵌入对象,而无需复制代码。太棒了!

当然,这不是真的。结构体嵌入仅允许您委托方法调用。即使它看起来像您正在进行多态方法分派,但关系不是 IS-A。它是 HAS-A,因此方法调用的接收者不是封闭对象:接收者始终是将方法调用委托给的嵌入对象。

在 Go 中进行面向对象编程。句号。

第二阶段:你相信 goroutine 会解决你所有的问题

您被 Go 吸引是因为它承诺让您轻松运行并发代码,这确实通过 goroutine 做到了!您只需要使用 go 关键字,就可以让几乎任何函数或方法调用并发运行。因此,很自然地,您希望通过尽可能多地并行运行代码来最大化代码的效率。并且因为您通过使函数调用自动创建 goroutine 来隐藏了这个事实,所以调用者甚至不需要意识到这一点。

是的,所以它可能会使你的代码更复杂一些,但看,现在一切都并发运行了!

Go 允许你创建数百万个 goroutine 而不会牺牲太多效率,但你不应该仅仅因为你可以就使用 goroutine。并发代码比在单线程中流动的代码更难维护和调试。我的意思是,你有没有认真考虑过当从多个 goroutine 同时访问时,你的共享对象是否真的正确同步了?你确定执行顺序绝对正确吗?你真的检查过这些 goroutine 在不再需要时是否真的退出了吗?

Goroutine 最好的用途是在它们必要时才使用,除非你的要求指示你必须在内存中完成所有事情或诸如此类的事情,否则你永远不应该放弃使用良好的多进程模型。

最后,尽量不要在用户背后生成 goroutine,特别是如果你正在编写库。显式调用 go 调用通常会给用户更多的灵活性和权力。

Goroutine 只能带你走这么远。仅在真正有意义时才使用它们。

第三阶段:你相信接口会解决你所有的问题,而不是面向对象编程

在对你无法使对象以多态方式行为感到失望之后,你突然意识到 接口提供的功能。接口允许你描述 API;肯定有办法使用它来编写更健壮的代码。

所以现在当你编写库时,你为所有东西定义接口。你只导出接口并拥有私有结构体,这样封装就非常完美了。它还应该给你在切换底层实现时提供更大的灵活性,因为现在你已经成功地将 API 与其实现解耦了。

接口确实给你带来了很多权力,但它不是万能的解决方案。它仍然没有提供面向对象编程意义上的真正的多态性。你也受到接口只能定义 API,并且你不能将任何数据与之关联的事实限制。

此外,虽然在某些情况下,仅导出接口而不是具体结构体是有道理的,但这真的不应该是你的默认操作模式。接口最好是小型的(而不是描述为对象定义的整个方法列表)。此外,如果你不小心,你将不得不编写大量的额外代码来满足接口,或者编写需要大量类型断言的代码。

为了最大程度地利用接口,你只应在想要使某些类型可互换时才使用它们。

第四阶段:你相信通道会解决你所有的问题

在你花费大量时间思考如何使 Go 按照你的方式工作之后,你现在正在寻找使一切按照你的方式工作的缺失部分。“等等,还有 通道!”

通道隐式地正确处理并发访问。你相信你应该能够通过巧妙地使用通道来处理同步、返回值(类似于 future/promise)以及使用带有各种通道的 select 语句进行流程控制,从而解决迄今为止的许多障碍。

同样,通道非常有用,但它们的用途仅与其最初的目的相同,即提供一个在 goroutine 之间传递值的原语。

我相信你会发现许多使用通道的 Go 惯用语:用于超时、阻塞 I/O、同步技巧等。但同样,因为通道是并发构造,滥用它们会导致更复杂、难以调试的代码。

第五阶段:你现在相信 Go 没有人们声称的那么强大

“为什么?!为什么编写 Go 代码如此痛苦?它不允许我按照我一直以来的方式编写代码。”

你感到沮丧。没有多态性。并发很难。通道不能解决你的问题。你甚至不明白 Go 存在的意义。你觉得你已经被剥夺了其他语言提供的所有好用的工具和构造。

你认为更强大的工具来表达抽象思想是绝对必要的。Go 就是不行。

Go 非常固执己见。我来自 Perl 背景,有一段时间我简直不敢相信 Go 有多么受限制。所以,是的,我理解你感到沮丧。

但这是因为语言真的有限制,还是因为你试图让语言按照你认为应该的方式工作,而没有考虑语言作者希望你做什么?

第六阶段:你意识到第一到第五阶段都只是你的想象

在某个时候,你勉强决定 按照大多数标准库的编写方式 编写 Go 代码。你也放弃了尝试变得聪明,并开始编写直截了当的代码。

然后你就明白了:你只是不想接受 Go 的方式。

一切都开始变得有意义。

认真地说,学习 Go 确实需要一些反学习。我不得不稍微反学习面向对象编程,并接受这样一个事实,即无论语言给你多少有用的工具,编写并发代码对于凡人来说都太难了。我也不得不反学习使用异常。

我没有与 Go 的作者核实,所以这只是我个人的看法,但我认为该语言的重点是让开发者更难编写复杂的代码。它给你足够的工具来编写执行复杂任务的代码,但通过取消某些关键工具,你最终编写的代码更简单,更难搞砸。

一旦我决定接受这些功能和构造的现状,编写 Go 代码就变得容易得多,而且肯定更有趣了。

第七阶段:你现在心平气和

你已经接受了 Go 的方式。你现在用 Go 编写所有东西,包括你通常会用 Perl/Ruby/Python 编写的东西。你意识到 if err != nil 不再困扰你。你只在必须时才使用 goroutine 和通道。

你与 Gopher 合二为一 你感受到它光荣的 chi,当你意识到它的仁慈允许你用如此庄严的语言编写代码时,你会哭泣。

恭喜你。现在你是一名 Go 程序员了。


即使这听起来有点半开玩笑,但这些确实是我在适应 Go 时感受或经历过的实际问题。也许你同意,也许你不同意,但第六阶段对我来说实际上就是那样。我最终放弃了试图让 Go 按照想要的方式工作,并决定按照 Go 告诉我的方式 编写。这听起来很傻,但从那以后,事情真的开始变得有意义了。

希望新的 Gopher 少花时间思考如何弯曲语言并感到沮丧。祝你编程愉快!

User profile image.
Daisuke Maki,又名 lestrrat,是 <a href="https://github.com/peco/peco">peco</a> 的主要作者,一位 Go/Perl/C 程序员、演讲者、作者和连续技术会议组织者(前 <a href="http://yapcasia.org">YAPC::Asia Tokyo</a>,以及现任 <a href="https://builderscon.io">builderscon</a>)。

8 条评论

Daisuke,好文章!我必须说,我还没有达到 Go 的禅宗顿悟第六阶段,更不用说第七阶段的涅槃了,可能是因为我发现很难将自己融入真正的 Go 惯用语。但你的文章给了我一些继续探索的动力!

这些步骤的时间线是什么?

好文章!

我相信这句话值得成为自己的 meme

“你在 Go 中进行面向对象编程。句号。”

:)

经过多年的过程化、过度复杂的代码之后,面向对象编程出现了,并且有史以来第一次,*如果做得正确*,程序的功能集大小与其复杂性之间存在线性关系。
我说“如果做得正确”,是因为我在无知、愚蠢或懒于学习如何正确做事的人手中看到过太多次做得不正确的例子。
如果没有能力轻松、快速且以非混淆的方式通过 IS-A 关系(继承 - 在适当的地方使用!)继承行为(这实际上是属性和使用它们的方法的组合),那些懒于学习如何正确进行 OO 的人,如果被迫使用一种对 OO 有宗教反对的语言,也会懒于避免复制/粘贴,从而走向一堆无法维护的意大利面条式代码。
在不支持 OO 的语言中避免复制/粘贴罪恶的“正确”方法是“手动连接”一堆不神圣的 HAS-A 关系。
人们为了支持他们的宗教信仰而做奇怪的事情 :)
我可以看到有些人可能会为故意从语言中删除像 OO 这样的工具辩解,因为有些人不理解它,或者不知道如何正确使用它,他们会说“我们是在拯救你免于自己”,但想象一下,如果因为一些愚蠢的人不小心砸到自己的拇指而从建筑工人手中夺走了锤子。
我从 80 年代初就开始编码,经历了所有来来去去的“范式转变”、时尚、炒作和流行语。在所有的噪音中,只有一件事真正实现了它的承诺,并且经过长时间的证明,成为一个巨大的、永久的游戏规则改变者,它带来了指数级的生产力和可维护性改进:面向对象编程。

:( 现在我感觉很奇怪。我绝不是一名全职程序员,也不是一个会选择一枚戒指(或语言)来统治我所有项目的人。我从来没有遇到过任何这种情况。

很酷的是 go-lang 内置了测试,所以安装 go-lang 就拥有了无需外部库即可制作测试套件的工具(我确信有人会制作一个替代测试套件,但为什么要费心呢?)。很酷的是它有不同类型的测试。很酷的是它有一个很好的界面,可以跳入和跳出管理并发和串行代码片段,但这只是一个新的工具。

哈哈,没有泛型

非常实用

这个很有趣。 :-)

Creative Commons License本作品根据 Creative Commons 许可协议 授权。署名-相同方式共享 4.0 国际许可协议。
© . All rights reserved.