本篇内容是根据2017年4月份#42 Race detection, firmware, production-grade Go音频录制内容的整理与翻译

Kavya Joshi 参加了节目,谈论了生产级 Go、用 Go 编写固件、使复杂的技术概念易于理解以及其他有趣的 Go 项目和新闻。

过程中为符合中文惯用表达有适当删改, 版权归原作者所有.




Erik St. Martin: 好的,大家好,欢迎回来收听新一期的 GoTime 播客。这是第 42 期,今天的赞助商是 Backtrace 和 DataDog。

今天的主持人有我,Erik St. Martin,还有 Carlisia Pinto---和大家打个招呼吧,Carlisia。

Carlisia Thompson: 大家好。

Erik St. Martin: 还有 Johnny Boursiquot 也在这里,和大家打个招呼吧,Johnny。

Johnny Boursiquot: 大家好,很高兴回来。

Erik St. Martin: 今天我们的特别嘉宾是 Kavya Joshi。我们应该从一个自我介绍开始……我知道你做过几次演讲,而且你还会在 GopherCon 上发言,但我们想听你亲自讲讲---你是谁,现在在做什么工作?

Kavya Joshi: 好的。我目前在旧金山的一家名叫 Samsara 的初创公司工作。我们是一家物联网公司,涉及硬件、软件和固件。我主要是一名后端或系统开发人员,同时也做一些基础设施相关的工作。

最近我觉得自己对固件有点兴趣,所以我也在尝试多做一些这方面的工作。除了日常工作之外,我还会在技术会议上发言。我做过一些关于 Go 或至少与 Go 相关的演讲,也做过一个关于 Python 的演讲,主要是讲解一个 Python 库。

今年我会在 GopherCon 上发言,我对此非常兴奋……此外,我还会写一些东西。实际上我今天刚发表了我第一篇技术博客文章,真的难以置信……所以,我目前主要做这些事情。

Erik St. Martin: 你做过的一个演讲---我们从这个开始聊吧---是在 StrangeLoop 上,对吗?

Kavya Joshi: 是的。

Erik St. Martin: 你在那个演讲中讲解了竞态检测器的实现。这真的非常酷。这个主题是你自己想到的吗?还是你在研究内部实现时,觉得“嘿,我对这些内部机制很了解,我应该做个演讲来分享”?[笑]

Kavya Joshi: 并不是……那样的话就太方便了。其实,这个演讲的起源是我听说了竞态检测器并用了一下,然后我觉得“哇,这个工具真棒。我很好奇它是怎么工作的。”我有计算机科学硕士学位,在读研期间,我所在的研究组主要研究分布式系统和操作系统,因此我有一些学术背景来深入研究支持 Go 竞态检测器的线程消毒器(Thread Sanitizer)论文。读完论文后,我觉得“这听起来很酷,但我还是不知道它在实践中是如何工作的。”于是,我开始深入研究源码并试用这个工具,最后觉得“这可以做成一个很棒的演讲”,这就是这个演讲的由来。

Erik St. Martin: 的确很有趣……自从竞态检测器推出以来,它一直是个很棒的工具。我之前从来不知道它是如何在底层实现的,比如使用向量时钟(vector clocks)之类的东西。

Kavya Joshi: 是啊,我觉得很酷的一点是,一些我以前只在分布式系统上下文中读到的概念被用在这个工具中。它们之间的关联是显而易见的,因为它们都涉及并发……但这些概念的转化真的很有趣,我觉得这很棒。

Erik St. Martin: 关于竞态检测器的一个有趣的故事---那是在第二届 GopherCon 上……有一位演讲者 Blake Caldwell 在演讲者晚宴上大谈特谈竞态检测器有多棒,坐在他旁边的人正好是 Dmitry,他转过头对他说“谢谢!”[笑] Blake 完全没意识到,在他对竞态检测器大加赞赏的时候,身边坐着的就是这个工具的作者。

Kavya Joshi: 哦,是啊……Dmitry 做了很多很酷的东西。他开发的其他工具,比如 Go Fuzz,看起来也很棒,还有他在调度器上的工作……都非常有趣。

Erik St. Martin: 是啊,很难跟上 Go 团队的一些成员在做的所有事情……他们贡献了太多优秀的东西。

Kavya Joshi: 是的。

Erik St. Martin: 那个演讲现在依然很有价值……你是在去年中期还是前年在 StrangeLoop 上做的那个演讲?

Kavya Joshi: 是去年的 StrangeLoop,也就是 2016 年 9 月。

Erik St. Martin: 所以对任何对底层工作原理感兴趣的人来说,它仍然非常具有参考价值。

Kavya Joshi: 是的,我觉得这是我最喜欢做的演讲类型或者呈现的内容类型……深入表面之下的东西---我觉得这很有趣,而且能为人们对系统的理解提供很多价值,这很酷。

Erik St. Martin: 是啊,我也很喜欢至少学习一两层你所使用的东西的底层原理。从工程学的角度来看,这很重要,因为很多抽象是有泄漏的……当一切都运行良好时,抽象很棒,但当事情开始出问题时,你就想知道你所使用的东西到底在做什么,以便更好地解决问题。

Kavya Joshi: 是的。

Erik St. Martin: 而且,知道这些东西是如何工作的本身就很极客……比如,“你为什么会知道调度器是怎么工作的?”你可能会说,“嗯,有一天我突然有个疑问,然后我就去研究了它的工作原理。”

Kavya Joshi: [笑] “然后我花了 20 个小时研究它,现在我可以给你讲讲它的所有细节了。”

Erik St. Martin: 至少这些东西以后是有用的。

Kavya Joshi: 是的。

Johnny Boursiquot: Kavya,我在那个演讲中发现一个很有趣的点是你提到了向量时钟以及它们的使用……那是我第一次看到向量时钟在这种场景中的实际应用。你用的插图在解释这些内容时非常到位,不仅对有一定技术背景的人来说很清晰,而且我觉得它也非常易于理解。如果有人是初学者,对并发或多线程程序还不是很了解,那也是一个很好的入门介绍。你一开始是有意让它适合不同技术水平的听众,还是因为这样解释本身对你来说更顺理成章?

Kavya Joshi: 这是个好问题。我觉得就逻辑流程而言,这样解释对我来说更顺理成章。但在制作内容时,我确实有意让它对有计算机科学背景但不一定对我讲的主题非常熟悉的人来说更易于理解。

在把一些非常技术性的内容做得平易近人和易于理解方面---首先,这很有趣,因为这是一个挑战。比如,“我有这些背景知识,但我要试着把它解释给可能没有这些背景知识的人听。他们在其他领域和主题上有知识储备,但不一定具备与我想讲的内容相关的知识。我该如何让它对他们来说变得更容易理解?”这是一种有趣的沟通挑战。

第二点是,我认为以一种易于理解的方式呈现技术理念最终会带来更好的结果。它能促进更好的系统设计,产生更有趣的对话,并以一种更普适的方式分享知识。

给你一个具体例子。Julia Evans 就非常擅长解释如何使用像 stracenetcat 这样的系统工具。她很擅长消除人们使用这些工具时的障碍。同样,我有一个朋友特别喜欢性能工程,他经常和我以及其他朋友讨论性能分析和跟踪的内容。我觉得当他以一种我们都能理解的方式分享这些知识时,这会让我们设计出更好的系统,产生更多有趣的讨论……总体来说,这是一件非常好的事情。

Erik St. Martin: 我真的很喜欢 Julia Evans 的插图。

Kavya Joshi: 是啊,那些 zines 真的是太棒了。我还打印了很多份,送给了我的实习生们。这真是太棒了。

Carlisia Thompson: 我非常喜欢 Kavya 提出的关于以一种更容易接近的方式呈现技术内容的观点。我在想,随着 Go 语言的迅速发展,越来越多的人开始接触这门语言,那么对于那些编写技术内容或者进行演讲的人来说,他们应该如何以更好的方式做到这一点?你有什么建议可以分享给我们和观众吗?

Kavya Joshi: 天哪,我希望自己能有一些通用的知识可以分享……我认为,当我准备一场演讲或写一篇文章时,我会花很多时间去思考如何呈现内容。比如“应该以什么顺序呈现内容?用什么图表或者动画可以让第一次听这场演讲的人觉得最直观?什么可以让内容对他们来说更容易理解?”

Erik St. Martin: 我觉得这很大程度上取决于我们对别人的假设---我们假设每个人都知道我们知道的东西。在计算机科学领域,越来越多的人并没有接受过正规教育,所以如果你假设他们都有计算机科学背景,这可能会让事情变得困难。我知道有很多概念其实并不难解释给没有基础的人,但你一打开书或者白皮书,就会觉得“天啊,救命!”[笑] 看着那些正式的证明,你会想,“好吧,也许我不够聪明,无法理解这个……”

这感觉就像是你到了一家公司做新员工,但对领域一无所知。每个人都在用缩写和你不了解的术语交流,这让你觉得整个业务完全令人困惑且遥不可及。但一旦你开始学习这些术语,就会发现它并不像你最初想象的那么复杂;只是你不知道这些小概念以及它们如何结合在一起。

Kavya Joshi: 是的,我觉得这是一个很好的类比。你的目标受众不一定是初学者,也不一定是没有计算机科学背景的人……而是他们没有你拥有的背景知识,因为你为演讲准备了很多时间,或者因为你对这个主题有着浓厚的兴趣。他们没有那些背景知识,所以我觉得关键是要意识到你的目标受众这一点---他们可能没有像你一样花那么多时间专注于某个主题。

Carlisia Thompson: 我觉得问你这个问题是值得的,关于如何准备内容的建议。因为我曾经很早之前在 StrangeLoop 上看到过你的演讲,做得非常出色。

Kavya Joshi: 谢谢。

Carlisia Thompson: 就像 Johnny 说的,你传达得非常好,比如竞态检测器(race detector)以及与之相关的一些概念。至于我自己,我做的一件事情是---我并不认为自己在这方面多么擅长,但当我完成一篇文章后,我会问自己,“如果我写完后睡一觉再看,质量会不会显著提高?”答案是会的。如果我隔一天再看,文章会更好;再隔两天,它甚至会更好。然后改进的空间会开始逐渐减小。

所以无论人们能做什么来让内容更好,即使需要多等一段时间,我觉得都是非常值得的。因为这样会让更多人从中受益,而不是匆忙发布一些内容,这些内容可能很简洁,但并不是所有人都能真正理解……无论是博客文章还是 CFP(Call for Proposals)提交,如果不够清晰,最终只会变成大量的噪音。

Kavya Joshi: 是的。

Carlisia Thompson: 所以我觉得你刚才正说到你会怎么做……如果你还有其他想分享的内容,那就太好了。

Kavya Joshi: 是的,我觉得让你信任的人来审阅你的内容是很有帮助的。我曾和许多优秀的人一起工作过,比如让他们阅读我的文章,告诉我是否清晰,是否作为一个局外人能理解……我们在代码审查方面做得很好,对吧?代码审查系统……所以我觉得如果你也能让人审阅你的内容,这会很有帮助。

Carlisia Thompson: 这很有道理。

Johnny Boursiquot: 对于 Go 初学者的一个建议是避免直接使用 goroutines 和并发原语(比如 channels 等等)……不要一开始就跳到深水区,因为那是一个完全不同的领域,你在写很多程序时并不一定需要这些东西。将程序写成顺序执行的方式是完全可以的,尤其是你从像 Ruby 或 Python 这样的语言转过来的时候,Go 已经能带来很大的性能提升了。

那么对于那些通常不在多线程环境中编程的人来说,如果他们觉得“好吧,我被告知不要急着跳进去,但现在我觉得我准备好了,我需要一些背景知识来帮助我正确地处理 Go 中的并发”,你会建议他们从哪里入手?或者有没有一些你可以推荐的资源,我们可以在播客页面上发布?你觉得对初学者有用的资源有哪些?他们需要什么样的背景知识才能真正利用好 Go 的并发特性?

Kavya Joshi: 我觉得官方的 Go 文档做得非常好……比如里面的教程会很好地解释一些基础概念。但我认为最好的学习方式是多读代码、多写代码。有许多开源的 Go 项目……你可以去阅读这些代码,或者用你喜欢的调试工具,或者自己写一些简单的例子,去尝试“如果我创建一个 goroutine 会发生什么?如果我创建两个呢?如果我用这种方式使用 channel 会怎样?用那种方式又会怎样?”通过动手实践写代码和阅读代码来学习。

Erik St. Martin: 我在想,那款 Go 并发可视化工具是谁写的?

Kavya Joshi: 哦,那工具真的很酷!

Erik St. Martin: 用它来理解这些事情如何并行发生,真的超级棒。

Kavya Joshi: 是的,我知道你说的工具,但我也忘了作者的名字。

Johnny Boursiquot: 有一个 GopherCon 的演讲视频,对吧?Erik,你是说这个吗?

Erik St. Martin: 是的……但我想不起来他的名字了。这些年大会上的演讲者太多了,总人数已经超过一百了,要记住所有人真的很难……

Johnny Boursiquot: 这可是个好问题,对吧?

Kavya Joshi: 你是组织者之一,对吗?

Erik St. Martin: 是的,是的。

Kavya Joshi: 太棒了。组织 GopherCon 现在是不是已经非常疯狂了?

Erik St. Martin: 是有点疯狂……每年的开头通常会很忙,然后大会前一个月会特别忙,但等到最后看到一切都顺利举办时,一切都值得了。不过我们超级兴奋能邀请到你,你对并发和 channels 的深入探讨肯定会非常精彩。即使是我,也从来没有深入研究过 channels 是如何实现的,我觉得这肯定会很有趣。

Kavya Joshi: 太好了,我也很期待今年的 GopherCon。

Erik St. Martin: 这是不是又是你非常感兴趣的东西?你会想“我想知道这个如何工作”,然后深入研究?

Kavya Joshi: 是的,是的……尤其是 Go 中的 channels,它们被设计成了一种语言原语。所以研究它们是如何工作的确很有趣。而且它与运行时的许多部分交互,这正是你会预期到的。我很期待这次演讲。

Erik St. Martin: 我有点难过,因为得等一个月才能看到……[笑声] 因为大会期间通常太忙了,我们通常等视频出来后才看。

Kavya Joshi: 是的,这很合理。

Carlisia Thompson: 我想问问你最近为 O'Reilly 写的文章……我读过,真的很棒。你工作的公司 Samsara---是 Samsara 吗?

Kavya Joshi: 是的,没错。

Carlisia Thompson: 你们遵循这些指南吗……?

Kavya Joshi: [笑] 这是个陷阱问题吧……[笑声]

Erik St. Martin: 你是不是在实践自己倡导的东西?

Kavya Joshi: 我们遵循文章中提到的大部分内容。比如,我们使用文章中提到的 panicwrap 库来报告 panic。我们将创建的所有 goroutine 包裹在一个顶层函数中,这个函数会捕获 panic 并报告。特别是在生产环境中,我们发现 panic 报告非常有价值。

我们还使用了 errors 包,这是一个非常流行的包,也是有原因的,它确实很有用。我们也会收集应用程序指标,所以这是五项中的三项……第四项是什么来着……?结构化日志---我们也用结构化日志。我们目前将日志发送到 AWS 的 Elasticsearch 服务,但它的体验很差,所以我们可能会很快切换到 Honeycomb 或类似的服务。

测试方面---我希望我们能在测试上做得更好,或者说可以……总的来说,拥有良好的测试实践非常重要。但对于我们这种规模的系统来说,如果一开始没有一个好的测试体系,后来要建立起来会很难。我们正在慢慢改进,但我觉得在测试这方面我们还有进步的空间。

Carlisia Thompson: 我想提一下这篇文章是在 oreilly.com 上,标题是 《How To Ship Production-grade Go》。绝对值得一读。抱歉,我不是故意让你的公司尴尬,但当我读到这篇文章时,我就在想,“这真的很棒……如果你所在的公司没有遵循这些指南,或者其他关于 Go 开发的指南,你会如何将它们引入到公司中呢?”

Kavya Joshi: 是的,这确实是个好问题。那你们呢?有没有其他让 Go 应用程序更符合生产要求的好建议?

Erik St. Martin: 我觉得很多内容其实适用于任何生产环境的程序---假设一切都会出问题,假设没有任何东西是完美的。你会遇到时钟漂移、网络问题……这些通常是最难追踪的奇怪问题。

Kavya Joshi: 是的。

Erik St. Martin: 我觉得这对所有人来说是个很好的起点。

Johnny Boursiquot: 我认为,对于我们中的许多人来说,使用十二因素模型(Twelve-Factor App Model)来配置环境或运行应用程序已经成为一种沿用已久的最佳实践。我认为这一点对于 Go 程序仍然非常适用,我们在自己的组织中也大量使用。

另外,在设计应用程序时,我们发现一个对程序设计和简化测试都非常有效的方法是大量使用接口(interfaces)。我们倾向于更多地依赖接口而不是具体的类型(concrete types),然后再处理实现细节。因为在设计过程中,尤其是在尝试新东西的阶段,引入具体类型来满足接口的要求比在之后去替换掉具体类型要容易得多。

基本上,这种方法意味着“我可能一开始并没有所有的答案”,但通过使用接口,可以帮助我们更好地理解程序的结构。我认为这种方法对我们按照自己的想法构建应用架构非常有帮助。

Erik St. Martin: 我也很喜欢当下用于配置管理和密钥管理的各种工具。这些工具在应用程序跨环境迁移时变得越来越重要,并且可以防止人们做出一些错误的操作,比如将凭据提交到 GitHub 仓库中。这样的事情经常发生……有些工具,比如 Bolt 和 Kubernetes 的脚本……

Kavya Joshi: Bolt 很棒!

Carlisia Thompson: Bolt 简直太棒了。Docker 也推出了一个密钥管理系统。

Erik St. Martin: 哦,挺有意思的。

Kavya Joshi: 哦,是吗?

Carlisia Thompson: 是的……我记错了吗?你们没人知道这件事吗?[笑]

Erik St. Martin: 我觉得这不会让我感到意外,因为……

Carlisia Thompson: 我很确定。

Erik St. Martin: ……这符合很多容器编排的逻辑;Kubernetes 在管理密钥,所以它们在编排的同时管理传递给容器的密钥也是合情合理的。但我好像没见过这个。

Kavya Joshi: 我对 Kubernetes 并不是很熟悉,我自己也没实际用过。我们使用 AWS,所以我们在 ECS 上运行我们的容器。但 Kubernetes 是如何进行密钥管理的?

Erik St. Martin: 它有一个资源类型叫做密钥(Secrets),你可以管理这些密钥。基本上,它有点像一个清单文件(manifest file),你可以用它来部署容器或容器组(pods),然后可以将密钥映射为文件---容器内运行的任何东西会将其视为一个文件---或者映射为环境变量。

因此,你的程序可以假设硬盘上有一个文件,或者假设有一个环境变量存在,而不需要知道或者关心这些内容是如何被放置在那里的。这真的很棒,因为 QA 环境可以有自己的密钥,生产环境也可以有自己的密钥,而应用程序本身无需做任何更改。即使是本地测试,你也只需要设置环境变量就可以了,一切搞定。

Kavya Joshi: 听起来确实很有用。

Erik St. Martin: 我刚刚意识到我们已经超时了,现在该进入今天的第一个广告时间了。让我们先暂停一下,感谢今天的第一个赞助商 Backtrace。

广告时间:

Erik St. Martin: 我们回来了,刚刚和 Kavya 聊到了 Kubernetes……因为时间关系,我们不得不中断了刚才的话题。你还有其他关于 Kubernetes 的问题吗?你们团队是否正在考虑使用它?

Kavya Joshi: 有在考虑,但目前它还在我们的愿望清单上,因为我们所有的基础设施都运行在 AWS 上,而 AWS 有自己的容器管理和编排调度服务 ECS。我们现在已经深度绑定 AWS 了,但我越了解 Kubernetes,就越希望切换过去能更容易一些……

Erik St. Martin: 我没研究过 Amazon 的容器编排实现……但我们通常会尽量设计软件时让它不需要感知自己是否运行在容器中……这和密钥管理的工作方式有点类似。事实上,无论是 Mesosphere 还是其他平台,只要密钥通过环境变量传递过去,代码就不需要做任何修改。

Kavya Joshi: 是的,所以对于我们的密钥,在 ECS 中……好吧,你基本上运行的是一个 Docker 容器。因此,你可以将环境变量传递给 Docker 容器;除此之外,我认为你可以使用 Amazon IAM 角色来管理对其他资源的访问控制。但是,我认为他们并没有专门针对密钥管理的解决方案,不过你可以让现有的系统正常工作。

Johnny Boursiquot: 我们的组织也依赖 AWS ECS 来进行镜像部署。Amazon 提供了 KeyMS(密钥管理服务),它可以提供主密钥,并支持定期轮换。这些都有一些最佳实践支持。这使我们能够获取这些密钥,加密密钥数据,然后我们基本上会将这些加密的密钥和镜像一起打包,通过一个内部工具从 S3 检索数据对象。而这个对象本身是使用 KeyMS 的密钥加密的。当镜像在环境中启动时,我们可以解密这些数据并将它们注入到环境中。

这让我们基本上不需要以明文形式传递密钥,而是保持密钥加密状态,直到它在必要的环境中被检索和解密。这种方法对我们来说效果很好。

回到我们提到的 Kubernetes……我读到关于 Kubernetes 的一些内容时会想,“哇,他们在做一些非常酷的事情”,但同时又想“好吧,我们现在完全绑定在 AWS 上了……”,想把 Kubernetes 引入并重建我们已经完成的所有东西---虽然很酷,但成本太高了。

Erik St. Martin: 我需要研究一下具体怎么做,因为我很好奇 Amazon 是否有 Kubernetes 的一些新概念,比如部署(deployments)或者集群联邦(cluster federation)。部署的概念是---你有这些基本单元,比如副本集(replica set)……你有一个 pod,pod 是一组一起移动的容器,然后你有一个副本集,用于指定“我需要在集群中运行 N 个这样的 pod”,然后你有一个服务(service),它基本上作为这些 pod 的负载均衡器暴露出来。部署(Deployment)允许你在这些资源上设置部署需求,它会通过创建一个新的副本集,包含新的容器版本,然后逐步增加新副本的数量,同时减少老版本副本的数量,从而完成滚动更新。我不知道 Amazon 的容器编排平台是否支持这些功能。

Johnny Boursiquot: 是的,在我们这里,Amazon 提供了一种叫任务定义(task definition)的概念,它基本上是说:“好吧,对于这个特定的容器,我们需要配置这些参数:需要多少内存、CPU、资源分配……如果是一个高可用环境,我希望将这些东西分布到不同的容器实例、不同的可用区(Availability Zones)中。”然后,Amazon 还提供了一个服务(Service)的概念,用于支持长期运行的任务,这些任务由任务定义来定义。我可以指定需要的副本数量,以及最大和最小健康百分比。

举个简单例子,如果我至少需要运行两个容器,我会说“我想要一个服务,期望数量为 2,最小健康百分比为 50%”。然后,当你想要推出一个新容器镜像时,由于有 50% 的健康要求,它会关闭一个旧容器,启动一个新容器镜像,然后当新容器启动后,再关闭另一个旧容器并替换为新版本。所以它确实有一些编排功能,并且能够将服务分布在不同的实例和 可用区 中。总的来说,这种方式对我们来说运行得相当不错。

Erik St. Martin: 这听起来很棒。

Kavya Joshi: 我们也会这样做,但ECS服务缺少的额外部分是负载均衡。例如,你需要在服务前面放置一个负载均衡器(例如ALB---应用负载均衡器),如果你为它设置了一些参数,它会继续将流量路由到你的服务。而Johnny提到的管理方式,就是这种工作流程的一部分。ECS服务会根据新的定义启动和终止任务,但你必须确保在ECS服务前面有一个负载均衡器。

Johnny Boursiquot: 是的,一开始我们不得不自己实现一个内部负载均衡器。我们有一个服务,任务是将流量路由到它知道的不同服务。我们在后台有自己的服务发现机制,并且内部有一个内部负载均衡器,所有的请求都会通过它。然后服务发现组件会将流量路由到它知道的不同服务和主机上。

AWS提供的ALB(应用负载均衡器)与经典的弹性负载均衡器不同。ALB可以将流量路由到集群中它知道的不同服务。我还没有太多尝试过这个,但听起来它确实能在这方面有所帮助……尽管服务发现有很多不同的实现方式,我个人非常喜欢HashiCorp的方案---他们有一个组件在这方面做得很好……现在我记不起名字了,但他们确实有一个。Linkerd也是一个非常不错的选择。

所以有很多选项可以选择,但显然你会找到一个适合你环境的。

Kavya Joshi: 很棒。既然提到HashiCorp的工具,因为你之前提到了Vault,还有刚刚提到的那个……这里有人试过用Terraform吗?

Erik St. Martin: 我没有试过。

Kavya Joshi: 好吧。那是另一个非常神奇的HashiCorp工具……

Erik St. Martin: HashiCorp的很多工具都非常神奇……

Johnny Boursiquot: 我知道,我是他们团队的忠实粉丝。他们开发了一些非常好的工具。Kavya,你要不要为不太了解这个工具的人稍微介绍一下?

Kavya Joshi: 当然可以。Terraform基本上是一个帮助你管理基础设施的工具---管理并创建基础设施。它的妙处在于,你可以将你想要的基础设施通过配置的方式来定义,所以它是声明式的。Terraform会检查你现有基础设施的状态,并与你指定的配置对比……以某种方式计算出差异,并决定需要执行哪些操作来使你的基础设施达到你指定的状态,然后应用这些更改。它会创建一个依赖图,确定哪些操作可以并行进行,哪些有依赖关系,因此它是一个非常快速且简单的方式来指定基础设施的变更。我们刚刚开始使用Terraform,所以我现在对它有点着迷。

Johnny Boursiquot: 在AWS栈上---不确定你是否尝试过,但与之对应的是CloudFormation。我最开始接触时有点抗拒通过JSON和YAML来指定架构,但一旦你深入了解并开始使用CloudFormation,你会发现很难回到手动或者像使用Chef或Puppet那样的工具去编排。CloudFormation一旦你真正理解它的工作原理,它就是一个非常棒的工具,专注于这个目的。现在,它几乎是我用来搭建任何堆栈的首选工具。

它的神奇之处在于,你可以很轻松地说,“嘿,我想在另一个可用区或者完全不同的区域中搭建相同的堆栈”,然后一切就自动完成了。使用起来真的很棒。

Kavya Joshi: 是的。所以Terraform可以与Chef和Puppet这样的工具结合使用,用于配置管理。Terraform真正擅长的是定义基础设施,比如实例、负载均衡器等等,以提供这些规范。

我们的使用方式是将实例的配置和软件安装等工作分开,但用Terraform来创建新的基础设施。

Johnny Boursiquot: 是的,这与典型的开发工作流非常不同。你不会在通常的CI/CD管道中使用它。这更像是为第一次搭建基础设施,或者以后需要重新生成它,甚至是需要修改它的场景。很多时候你会从“嘿,我知道我需要12个这样的EC2实例,这些实例需要这样的内存和CPU资源配置”开始,然后你会发现“哦,我之前以为需要的资源没那么多”或者“我需要更多资源”。

你可以轻松更改配置……这就是基础设施即代码的魅力,你只需提交更改,让AWS知道,然后状态机会启动,调整你的基础设施到所需状态。如果需要,Terraform会关闭资源,删除不再需要的东西,基本上把你带到那个所需状态。所以它是一个非常好的工具,用于首次设置和后续修改,但显然它纯粹是用于基础设施,而不是传统的开发发布管道。

Kavya Joshi: 是的。

Johnny Boursiquot: 我觉得我们有点沉迷于基础设施了---

Carlisia Thompson: ---换个话题吧……[笑声] 你们准备好聊点别的了吗?我想问问Kavya关于固件的兴趣---[笑声] 你提到过你对此很感兴趣……听起来你好像还没真的开始做什么?我很好奇,如果你有机会接触一些硬件并随意发挥的话,你会做些什么?

Kavya Joshi: 是啊,天哪……我工作的那家初创公司做固件,因为我们有一个硬件工程团队---我们自己制造硬件……还有一个固件团队,而固件团队实际上确实在使用Go。我们有传感器,这些传感器不运行Go---它们全部是嵌入式C---但运行Yocto Linux的网关上运行了一些C++和Go,后端则完全是Go。

我最开始在这家公司做的是后端工作,涉及一些基础设施之类的角色……但我对固件方面的了解越多,我对编写固件代码就越着迷。能在固件上运行Go真的很酷,所以如果说我用它会做些什么---天哪……

Carlisia Thompson: 没关系,为什么不分享一下……我很好奇是什么让你觉得固件代码有趣?我完全相反的感受是,每次涉及到硬件编程,我都觉得很痛苦,因为我曾在一家公司做了三年的硬件相关工作,主要是用C语言编程。硬件经常坏掉,或者不像预期那样工作,所以你不仅需要处理软件,还要面对这个“怪物”……[笑声] 我不是电气工程师,完全不知道怎么搞定这些,所以我对此的感受就是这样。我很想知道是什么让你觉得编写固件代码这么酷。

Kavya Joshi: 好吧,首先声明一下,我没写过太多固件代码,只是稍微玩了一下。我觉得权衡取舍非常有趣。固件团队不得不考虑功耗,这不是作为一个后端或者传统软件程序员需要考虑的事情,对吧?比如,你需要多一个实例,需要更多内存或者CPU---直接启动就行了。

当然,你会优化代码,但这很容易;你不用面对硬约束。而当你谈到固件编程,或者设备上的编程时,这些都是非常真实且非常硬性的约束条件。另外一个你从未思考过的新约束是功耗,而作为固件程序员,你会想:“哦,在睡眠模式下,我的代码消耗了多少功率。不在睡眠时又消耗了多少功率。”

你需要处理的约束条件完全不同,我觉得这就是它的有趣之处。

Erik St. Martin: 那你是对用Go编写固件感兴趣,还是总体上感兴趣?

Kavya Joshi: 总体上感兴趣,但用Go感觉是一个非常方便的起点,尤其是现在有Gobot和其他新的工具。

Erik St. Martin: 我想我的感受跟你很像……硬件方面我不是电气工程师,但我有一堆零件,因为我正在慢慢学习。我觉得学习固件编程有趣的地方在于:1)我们写了那么多代码,它们运行在别的地方,而写能够与实际交互的代码,比如点亮东西或控制一些东西---真的很有成就感。而且想到你能发明物理产品,而不仅仅是运行的程序,这真的很酷。另外,想深入理解事情如何运作也很吸引人。理解---就像你说的,固件编程有一些奇怪的约束,比如实际的中断、中断运行的时间、汇编指令的数量……你不能做Load, Modify, Store操作,因为如果一个中断发生并修改了底层寄存器,你可能会搞乱它……这听起来很麻烦,但我觉得当你构建的东西越多时,你就会想要更难的问题。

Kavya Joshi: 是的……

Johnny Boursiquot: 并发很难……[笑声]

Erik St. Martin: 是的,尤其是内存约束很有意思,特别是如果你使用的是普通的ARM芯片,或者类似的东西,取决于系列……你可能只有几KB的RAM,即使你通过总线使用外部RAM,你仍然不会处理几GB的RAM,而是会像“嗯,谁在乎呢?”

Kavya Joshi: 是的。

Erik St. Martin: “他们只有8GB内存,而不是32GB,那是他们的问题!”[笑声]

Kavya Joshi: 是的……我们最近换了一个新的芯片组和不同的网关主板,固件工程师们说:“天哪,我们现在可能有150MB的RAM可用?”我就想:“呃,好吧……你要拿它干嘛?”[笑声]

Erik St. Martin: 像是,“你能用它点亮一个LED吗?”[笑声] 在分布式系统和云的世界里,当你想到几MB的RAM时,你真的会觉得“你要用它干嘛!?”

Johnny Boursiquot: 启动一个VM吧,如果能启动的话!就这样了。 [笑声] 我很好奇……在硬件的世界里,如果你在“开发”时让它在硬件上运行,是否有某种保证它每次都会以完全相同的方式运行?相比于软件世界?

Erik St. Martin: 是的,我大概可以回答这个问题……不过我们可能需要先进行下一段赞助中场休息,然后我再回答,因为这可能会讲得比较多。所以今天的第二个赞助商是DataDog。

Break:

Erik St. Martin: 我们回来了。在休息前,Johnny你提到了---你是问更像是测试场景吗?

Kavya Joshi: 当你开发并最终发布了一个硬件产品……你能否几乎确保在测试和开发时运行正常的代码,到了消费者手中仍然能够以同样的方式正常运行?你们有这样的保证吗?

Erik St. Martin: 确保一切正常运行,需要对物理设备进行大量测试……通常会有一些测试接口。一旦电路板设计完成,有些人会用一种叫做“钉床”(bed of nails)的工具,它类似于一个装置,可以与物理设备的接触点连接,然后向电路的不同部分施加电压等操作,并测量其他部分的响应。

我不记得这个是什么时候推出的了,但有一个叫做联合测试行动组(Joint Test Action Group,简称 JTAG)的标准接口,很多微控制器都会实现它。它基本上允许你像移位寄存器一样与所有芯片通信,你可以通过它对微控制器的引脚施加电压或者读取引脚数据……所以你可以在实际的硬件上模拟很多单元测试。

至于固件开发,很多工具,比如 QEMU 等,也会用来编写单元测试……类似于我们编写“只崩溃软件”(crash-only software)的方式,固件开发人员也必须尝试去处理类似的问题,因为硬件可能会发生硬故障。如果你有堆栈溢出之类的问题,微控制器会直接进入硬故障状态,并停留在那里。所以人们会通过捕获这些中断来处理这些问题。当这种情况发生时,你会收到一个中断信号,然后可以在这个中断上设置回调,重启微控制器使其进入一个干净的状态,等等。

这是一个有趣的领域……我自己不开发固件,但我认识一些电子工程师(EE),我对这些东西非常感兴趣,也一直想学更多相关的知识。

Johnny Boursiquot: 听起来你对这方面很感兴趣啊……[笑声]

Kavya Joshi: 是啊!

Erik St. Martin: 我总是感到纠结,一方面我想拿一个单板计算机,比如 Intel Edison,然后在上面装 Linux 和 Go;另一方面,我又特别喜欢汇编和 C,喜欢深入了解它的底层。我买了一些开发板,它们基本上就是一个 ARM 处理器和一些 RAM。我今天刚收到一个,我本来以为 UPS 会在我们录播客时送到……它上面有一个 4.3 英寸的触摸屏,配备了相当大容量的 RAM,还有一个速度很快的 Cortex 微控制器。我迫不及待地想为它写点代码了。[笑声] 不过这些代码基本上都会是用 C 或 C++ 写的。

Johnny Boursiquot: 你觉得在资源非常少的系统上开发---比如和我们在云端部署的那些强大的服务器相比---是否会让你写出性能更高、更节省资源的代码?

Erik St. Martin: 我想你会更加注意这一点……我会尽量在写代码时保持意识到这一点,但确实在这种情况下你考虑得更多。通常你的编译工具会告诉你程序在闪存上占用了多少空间,而这也是一个问题,对吧?因为芯片上只有这么多闪存空间可以用来存储程序。我们甚至不用考虑磁盘存储。

如果你写了一个程序,把服务器的硬盘空间全填满了,你会立马被炒鱿鱼。[笑声] 所以会有类似的事情……或者你需要编写代码,从外部闪存中拉取更多代码。但这确实让你更加关注处理器的工作方式、汇编指令、寄存器以及这些东西的运行方式。

Johnny Boursiquot: 那么在需要传输数据的情况下,似乎你可以通过产品自带的存储,或者通过网络传输那些数据。在如今的物联网(IoT)世界里,几乎所有东西都能通过网络通信……你会如何传输需要收集的数据呢?

Erik St. Martin: 大多数物联网设备的数据传输会通过某种射频(RF)技术,比如蓝牙、Wi-Fi 等。如果不是的话,USB 接口或者 SD 卡也可以用。但在调试的时候,很多调试接口实际上可以通过串行连接给电脑发送日志信息。调试可能是硬件开发中最大的痛点之一。

我想说的是,如果你不是试图设计电路本身,而只是想用 Arduino 或类似工具做一个小装置,那么硬件开发比我原先想象的要容易得多……尤其是,现在很多芯片使用的都是非常通用的串行接口,比如 SPI、I2C 和 UART。通常所有的芯片---包括 Wi-Fi 芯片和主微控制器---都会通过这些串行连接进行通信。你的闪存或 RAM 也会通过这些接口通信。这让你可以轻松反向工程你家里用的一些硬件,比如,“哦,这是微控制器,那是闪存……它在存储什么样的数据呢?”[笑声]

你可以买到很多芯片并将它们连接起来。很多时候,Adafruit 和 SparkFun 是我最喜欢的地方,因为你可以直接买到小的分线板,只需要连接电源和串行线就可以用了。你不需要担心电容器和那些支持电路的细节。

Carlisia,你有没有接触过硬件开发,还是主要写固件代码?

Carlisia Thompson: 我没有写固件,也没有写嵌入式代码……我写的是驱动机器的代码,比如打印机和覆膜机---这些巨大的定制机器。即便如此,有时候也很麻烦。[笑声] 有时候机器关了,我都不知道怎么把它开起来……一些很傻的情况。[笑声]

Johnny Boursiquot: 没有电源按钮吗?

Carlisia Thompson: 硬件编程中可能遇到的各种中断……然后硬件坏了,你就不得不停止工作,然后心想“好吧,我都不知道从哪儿开始修起。”

Erik St. Martin: 是啊……当电路出现故障,电压水平下降时……主电压应该始终保持在 5 伏以上,但却掉下来了,这会让微控制器进入一个奇怪的状态……还有一些人会故意这样做。

在硬件逆向工程的圈子里,有一种叫做“故障注入(glitching)”的手段---你基本上可以设置……我有点记不清这些设置的名字了,但芯片上有一些属性,你可以把它设置为只读模式。这通常是在生产时完成的,这样别人就不能读取固件以进行逆向工程。但人们已经找到了一些方法,通过以特定频率“故障注入”电源,来触发这些保险丝,从而仍然可以提取固件。能理解这些物理现象并实现的人得有多极客啊?[笑声]

Johnny Boursiquot: 听起来像是硬件世界的 SQL 注入……[笑声]

Erik St. Martin: 我记得第一次听到一个关于这种技术的演讲时,我简直不敢相信:“你做了什么……?!你只是故意让电源出问题,然后就进去了?”他们用热风枪、红外热成像仪(FLIR 摄像机)和类似的工具,甚至会用 X 光扫描芯片,查看单个晶体管之间的通信……这种水平---我喜欢学习低层的东西,但这可能是我不会触及的一个领域。[笑声]

Johnny Boursiquot: 我还是待在云端吧,谢谢……[笑声]

Erik St. Martin: Johnny 和 Kavya,你们有在家里捣鼓硬件吗?

Kavya Joshi: 只能算是“捣鼓”吧……我订购了一个 Adafruit 的开发板,等它到了,我应该会开始玩一玩。不过,目前还没有什么特别酷的项目计划。

Erik St. Martin: 对,这通常是从一些简单的东西开始的,有时候就是找到一个传感器……我最早做的一个项目之一是---这还是 Arduino 尚未流行的时候……当时有一家叫 NerdKits 的公司,几个同事买了他们的产品。基本上,它就是 Arduino 板上的核心组件---一个 AVR 微控制器、晶振、电阻和一个 LED……他们会把这些东西装在一个面包板上,附带一份长长的 PDF 教你如何组装和运行。

这是我开始入门的地方,当时有人给我寄来一个气体传感器,据说还能检测酒精……我心想,“我要做一个酒精测试仪。”[笑声] 我不知道为什么会这么想,但当时觉得很酷。

我会逛 Adafruit 或 SparkFun 的网站,随便看看,然后说:“哦,这个很酷……我要买一个 LED 矩阵。”我也鼓励还没玩过硬件的人,从一个简单的 Arduino 板开始,找个扩展板(shield)搭配使用。你会发现,这并没有你想象中那么难以接近……大部分芯片的串行协议其实就那几种常见的。

Brian 今天不在节目里,但他和我一直在研究一个用于烧烤烟熏炉的热量控制器……他用树莓派搭建了一个示例,通过 GPIO 引脚与继电器通信,用的是 I2C 协议。这些东西其实很容易上手。

Johnny Boursiquot: 他当时想在 GopherCon 上用他的 PID 控制器现场烧烤,但提案没被接受,这让我特别失望。我不知道是不是消防员插手了这件事……[笑声] 他们可能会说:“在大会上现场烧烤?为什么不呢!?”

Erik St. Martin: 我不确定他们是否曾正式回应过我们关于带烤炉的请求……不过还有闪电演讲可以做啊。

Johnny Boursiquot: 这倒是……[笑声]

Erik St. Martin: 演讲提案筛选过程中最难的部分,就是我们收到的提案数量实在太多了。

Johnny Boursiquot: 而且还是在截止日期的最后阶段提交的……[笑声]

Kavya Joshi: 那我还是不告诉你们我是啥时候提交的了……[笑声]

Johnny Boursiquot: 哦,我们知道的……[笑声]

Erik St. Martin: 我们刚才讨论云计算和硬件话题聊得有点偏了。

Kavya Joshi: 好的东西总是容易聊偏。

Erik St. Martin: 我觉得你的演讲会非常有趣……大家对那些讲解“幕后运行原理”的演讲通常都很感兴趣。

Kavya Joshi: 是的。我觉得 Go 核心团队的贡献者们在谈论、解释或发布关于底层工作原理的文章时做得非常好。比如说,关于调度器、垃圾回收器的设计文档,甚至只是提交信息都非常有见解。虽然关于通道(channels)的内容网上还不多,但这些文档真的很酷。

Erik St. Martin: 我觉得这可能是因为……这是我从 Go 团队那里听到的一个普遍观点……这些是实现细节。他们可能不太愿意发布太多关于这些实现的内容,因为它可能在某个版本中就会改变。而且可能不希望鼓励人们基于特定实现进行开发。但我觉得大家确实对这些原理很感兴趣。

而且,像你说的,了解这些内容能让更多人参与讨论,比如“它是如何工作的?它应该如何工作?”等等,而不是像个秘密组织似的:“哦,那是编译器……没人能跨越那道界限。”

Kavya Joshi: 是的,我还想说,这也是 Go 社区的一部分文化……每次设计文档发布后,比如调度器的设计文档,总会有一大群人在 Hacker News 上阅读和评论。显然,程序员(特别是 Go 程序员)对系统内部的运行原理充满兴趣,这是一件很棒的事情。

Erik St. Martin: 好吧,按照惯例,我们每期节目都会在快结束时谈谈最近遇到的一些有趣项目、新闻或者其他内容(有时候是之前没来得及提到的)。今天有没有什么大家觉得一定要提到的?

Kavya Joshi: GopherJS 很酷……

Erik St. Martin: Brian 非常喜欢 GopherJS。我想他现在还在断断续续地玩,但他以前是这个工具的超级拥护者。

Kavya Joshi: 是的……写原生 JavaScript 对我来说太费时间了,有了 GopherJS,我甚至都不需要写 JavaScript 了。太棒了!

Erik St. Martin: 我写了这么多年的 JavaScript,现在对我来说直接写 JavaScript 可能更容易……不过说实话,我还没试过 GopherJS。

Kavya Joshi: 我们团队甚至在考虑用 Go 写我们大部分的 JavaScript 代码,然后通过 GopherJS 编译成 JavaScript 运行。

Erik St. Martin: 这是一个关于 GopherJS 采用的问题---在你们公司通常是怎样运作的?因为按照大多数公司的结构来说,通常有一个后端团队和一个前端团队,而前端团队通常掌控着大量的 JavaScript。所以对于前端团队来说,学习 Go 和 GopherJS 是否存在门槛?还是说更多是一些全栈(虽然我很讨厌使用这些流行词汇)工程师控制整个应用程序?

Kavya Joshi: Samsara 的工程团队规模很小,大概有 10-12 人,当然我们有各自的关注领域。我在支持或后端团队(我们团队有三个人),但团队之间并不是严格划分的,而是比较灵活的。我自己不太做前端,但确实有一些人既做前端,也会做一些后端的工作。所以我觉得大部分处理 JavaScript 的人也熟悉 Go,并且也写很多 Go 代码。

总体来说,我们希望将部分代码转换为 Go 然后使用 GopherJS。我觉得这需要一个缓慢且谨慎的过渡,逐步进行。但我觉得整个团队对此是支持的。

Erik St. Martin: 哦,这真的很有趣。这也是我一直以来对采用它的一个疑问。但我想,如果大家都在跨越技术栈工作,那就说得通了。不过我想说,Go 并不难上手,可能比 JavaScript 更容易上手。

Kavya Joshi: [笑] 我个人是这么觉得,但这只是我的看法...

Johnny Boursiquot: 别挑起争端... [笑声]

Carlisia Thompson: 我有两个社区相关的消息要分享。一个是 GopherCon India 2017 的视频已经发布了。有大约 22 个视频,其中有一些很不错的演讲。还有就是今天,再过几个小时,Dave Cheney 将会举办一个 Go 远程聚会,他会谈论 Go 的隐藏 \#pragmas。我不太清楚 pragma 是什么...

Erik St. Martin: 这很有意思,我刚才点开了链接。pragma 是什么...?

Carlisia Thompson: 对吧...? [笑]

Erik St. Martin: 这个名称来源于 C 编译器中的 Pragma 声明,它告诉编译器如何解释代码的某些部分。而 Go 没有 Pragma 指令,但它确实有通过注释中的指令语法来改变 Go 编译器操作的方法。很有趣。

Carlisia Thompson: 刚刚是 Erik 在读聚会的描述。

Erik St. Martin: 是的,我其实直到你刚才说了,我才知道有这个聚会,所以我点了链接看看:“这是什么?”

Kavya Joshi: 等等,是今天,对吧?

Carlisia Thompson: 是的,但有录制,你之后也可以看

Erik St. Martin: 我们会记得在节目说明中发布录制链接,这样即使听众是节目发布后再听,也可以观看视频。

Johnny Boursiquot: 我还看到 Francesc 的新 JustForFunc 节目 关于 Context 的使用。我看了那个,真的很不错……很好地讲解了使用 Context 包的原因和方法,比如帮助你处理客户端和服务器连接突然终止的问题。这集很棒,大家应该去看。

Carlisia Thompson: 是的,他在印度也做了一场关于 Context 的演讲。今年 GopherCon India 的视频中有他讲的同样内容。

Erik St. Martin: Context 包真的非常棒,尤其是当你有请求管道,启动其他 goroutine 等等时,可以在前端取消操作。此外,JustForFunc 系列也很赞。我还没看完所有的,但我一直在努力赶上。我很喜欢 Francesc 在这个系列中的工作。Kavya,你看过这些节目吗?

Kavya Joshi: 我看过一些,但总的来说,我觉得 Francesc 所有的内容都很有趣且易于理解……我是个粉丝。

Carlisia Thompson: 我们也是 Francesc 的粉丝。 [笑]

Erik St. Martin: 是的……我想我们有点超时了,但我们每期节目有一个传统,就是做一个叫“\#FreeSoftwareFriday”的环节。为什么叫星期五 - 我想是因为我们在星期四发布节目之前就起了这个名字... [笑声] 我们想借此机会表扬社区的贡献者或开源项目,或者那些让我们生活更轻松的具体项目。

它不一定是 Go 项目,可以用任何语言写。如果你有想法,可以说;如果没有也没关系。

我会从 Carlisia 开始,给你一些时间想一想,Kavya。

Kavya Joshi: 好的。

Erik St. Martin: Carlisia?

Carlisia Thompson: 我以为你是说要给我时间想一想,那可能会想很久……但我确实有一个。

Erik St. Martin: 我看到你的文档里已经有了,所以你不需要时间。

Carlisia Thompson: 是的,我准备好了。我发现了这个 goreporter 工具,我很喜欢,因为当时我做 Ruby 和 Ruby on Rails 时用过一个类似的工具。它基本上运行分析工具和测试,生成一个代码质量报告,你可以将其输出为 HTML 格式,在浏览器中查看代码的状况。非常不错。

Erik St. Martin: 哦,这真的很酷。我也想做个比较……你见过 ReviewDog 吗?

Carlisia Thompson: 没有,那是什么?

Erik St. Martin: 这个工具有点类似,你可以设置它与 GitHub 集成,每次提交代码时都会运行。它执行类似的检查。我想比较一下它有哪些功能。

Carlisia Thompson: 这个 ReviewDog 听起来像 RubyCop。

Erik St. Martin: 我可能没见过——可能是我不再用 Ruby 之后出的东西。

Carlisia Thompson: 我觉得它叫 RubyCop,但这个名字听起来不太对……

Johnny Boursiquot: RuboCop。

Carlisia Thompson: 对,RuboCop,就是这个名字。听起来像它。很酷,我也会去看看。

Erik St. Martin: Johnny,你呢?有没有什么推荐的人或项目?

Johnny Boursiquot: 有的,就是 Robomongo 团队。前段时间我需要快速验证一些 Mongo 数据库的 schema,因为我正把它们部署到云端。用命令行可以快速查看不同数据库里的内容,但我想找一个 Mongo 的 GUI 工具。市场上有很多选择,但我发现了 robomongo.org 的 Robomongo。这个工具非常好用,界面友好,还开源且免费。所以,我想给那边的团队点个赞。真是个很棒的工具。

Erik St. Martin: 我现在正在看它的页面,哇……Mongo 的工具现在变得这么漂亮了。我记得我刚学 Mongo 的时候用过一个工具,样子就像普通的 Linux GUI——功能上可以用,但外观不怎么样。而这个工具看起来真不错。

Johnny Boursiquot: 我自己也很惊讶。

Erik St. Martin: Kavya,你呢?有没有什么项目或维护者想要提名一下?

Kavya Joshi: 哎呀,我可以再提一次 GopherJS 吗?

Erik St. Martin: 当然可以![笑声]

Carlisia Thompson: 完全没问题!

Erik St. Martin: 那我这次的推荐和我们今天的一些话题还挺契合的。这个项目叫 GNU ARM Eclipse。如果你玩嵌入式开发的话,你会发现几乎所有电子工程师都是 Windows 用户,因为很难找到适配其他系统的工具或 IDE。我自己也有一个 Windows 虚拟机,为了某些特定工具,我得把开发板放在地上,然后用 USB 线连接。

这个项目非常酷,它能处理 JTAG 和 OpenOCD 的调试,用于 ARM 开发板和 ARM 项目,还能通过 QEMU 运行测试和模拟器。这个项目真的很棒,我非常感谢它,因为要是没有它,我可能得全程都在 Windows 虚拟机里开发。

好了,到这里我要感谢所有参与节目的嘉宾,特别感谢 Johnny 和 Kavya 今天加入我们。

Kavya Joshi: 很有趣!

Johnny Boursiquot: 我的荣幸!

Erik St. Martin: 非常感谢我们的赞助商 Backtrace 和 DataDog。如果你觉得这个节目有价值,可以分享给其他 Go 开发者、朋友或同事。如果你还没订阅,可以访问 GoTime.fm 订阅;也可以在 Twitter 上关注我们。如果你有想要在节目中讨论的话题或想推荐的嘉宾和主题,可以通过 ping 联系我们。好了,各位再见!我们下周见。

Carlisia Thompson: 再见!

Johnny Boursiquot: 保重!

Kavya Joshi: 再见!


好文收藏
38 声望6 粉丝

好文收集